diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2018-01-09 19:06:55 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2018-01-09 19:06:55 (GMT) |
commit | 01e0ebfe59d9028b0246ec4a549bd7528ada94eb (patch) | |
tree | a6c5b54db03177a1c8f3e7fb531990dfbc7bae39 /ast/dsbspecframe.c | |
parent | d64cf9c0bd23e752867b149be636d1bbd4501cf4 (diff) | |
download | blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.zip blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.gz blt-01e0ebfe59d9028b0246ec4a549bd7528ada94eb.tar.bz2 |
update ast 8.6.2
Diffstat (limited to 'ast/dsbspecframe.c')
-rw-r--r-- | ast/dsbspecframe.c | 3266 |
1 files changed, 3266 insertions, 0 deletions
diff --git a/ast/dsbspecframe.c b/ast/dsbspecframe.c new file mode 100644 index 0000000..576f5b9 --- /dev/null +++ b/ast/dsbspecframe.c @@ -0,0 +1,3266 @@ +/* +*class++ +* Name: +* DSBSpecFrame + +* Purpose: +* Dual sideband spectral coordinate system description. + +* Constructor Function: +c astDSBSpecFrame +f AST_DSBSPECFRAME + +* Description: +* A DSBSpecFrame is a specialised form of SpecFrame which represents +* positions in a spectrum obtained using a dual sideband instrument. +* Such an instrument produces a spectrum in which each point contains +* contributions from two distinctly different frequencies, one from +* the "lower side band" (LSB) and one from the "upper side band" (USB). +* Corresponding LSB and USB frequencies are connected by the fact +* that they are an equal distance on either side of a fixed central +* frequency known as the "Local Oscillator" (LO) frequency. +* +* When quoting a position within such a spectrum, it is necessary to +* indicate whether the quoted position is the USB position or the +* corresponding LSB position. The SideBand attribute provides this +* indication. Another option that the SideBand attribute provides is +* to represent a spectral position by its topocentric offset from the +* LO frequency. +* +* In practice, the LO frequency is specified by giving the distance +* from the LO frequency to some "central" spectral position. Typically +* this central position is that of some interesting spectral feature. +* The distance from this central position to the LO frequency is known +* as the "intermediate frequency" (IF). The value supplied for IF can +* be a signed value in order to indicate whether the LO frequency is +* above or below the central position. + +* Inheritance: +* The DSBSpecFrame class inherits from the SpecFrame class. + +* Attributes: +* In addition to those attributes common to all SpecFrames, every +* DSBSpecFrame also has the following attributes: +* +* - AlignSideBand: Should alignment occur between sidebands? +* - DSBCentre: The central position of interest. +* - IF: The intermediate frequency used to define the LO frequency. +* - ImagFreq: The image sideband equivalent of the rest frequency. +* - SideBand: Indicates which sideband the DSBSpecFrame represents. + +* Functions: +c The DSBSpecFrame class does not define any new functions beyond those +f The DSBSpecFrame class does not define any new routines beyond those +* which are applicable to all SpecFrames. + +* Copyright: +* Copyright (C) 1997-2006 Council for the Central Laboratory of the +* Research Councils + +* Licence: +* This program is free software: you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation, either +* version 3 of the License, or (at your option) any later +* version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General +* License along with this program. If not, see +* <http://www.gnu.org/licenses/>. + +* Authors: +* DSB: David Berry (Starlink) + +* History: +* 5-AUG-2004 (DSB): +* Original version. +* 7-OCT-2004 (DSB): +* Fixed SetAttrib code which assigns values to SideBand. Previously +* all supplied values were ignored, leaving SideBand unchanged. +* 2-SEP-2005 (DSB): +* Allow conversion in any Domain within TopoMap (sometimes +* SpecFrames have a new Domain set which is not equal to SPECTRUM"). +* 12-SEP-2005 (DSB): +* Set all attributes required to described the RestFreq value +* before determining Mapping from RestFreq to ImagFreq in +* GetImageFreq. +* 2-DEC-2005 (DSB): +* Change default Domain from SPECTRUM to DSBSPECTRUM +* 3-APR-2006 (DSB): +* Fix memory leak in astLoadDSBSpecFrame. +* 6-OCT-2006 (DSB): +* Guard against annulling null pointers in subFrame. +* 27-OCT-2006 (DSB): +* Added AlignSideBand attribute. +* 31-OCT-2006 (DSB): +* Use AlignSideBand attribute in SubFrame only if we are not +* currently restoring a FrameSet's integrity. +* 31-JAN-2007 (DSB): +* Modified so that a DSBSpecFrame can be used as a template to find a +* DSBSpecFrame (or SpecFrame) contained within a CmpFrame. This +* involves changes in Match. +* 1-MAY-2007 (DSB): +* The default for AlignSideband has been changed from 1 to 0. +* 8-MAY-2007 (DSB): +* Correct initialisation of alignsideband in astInitDSBSpecFrame_. +* 19-OCT-2007 (DSB): +* Ignore SideBand alignment if the AlignSideBand attribute is zero +* in either the target or the template. +* 16-JAN-2007 (DSB): +* Modify SubFrame so that DSBSpecFrames are aligned in the +* observed sideband (LSB or USB) rather than always being aligned +* in the USB. +* 12-FEB-2010 (DSB): +* Report an error if the local oscillator frequency looks silly +* (specifically, if it less than the absolute intermediate frequency). +* 29-APR-2011 (DSB): +* Prevent astFindFrame from matching a subclass template against a +* superclass target. +*class-- + +* Implementation Deficiencies: +* - The default values for System and StdOfRest inherited from the +* SpecFrame class are "Wave" and "Heliocentric". These are not +* usually what is wanted for a DSB instrument. Defaults such as +* "Freq" and "Topo" may be more appropriate. However, changing the +* defaults inherited from SpecFrame may cause problems in the +* astConvert algorithm. The astConvertX function in frame.c includes +* the following implementation deficiency warning: "One likely +* problem is with attributes which default in both the source and +* destination Frames. This means they also default in the common +* coordinate system. If these default values were to differ when +* matching different target Frames, however, we would be in trouble, +* because the common coordinate system would not then be remaining +* constant. The longer-term solution to this is probably to provide +* some mechanism to "fix" all attribute values for a Frame, by taking +* any attributes that are un-set and explicitly setting a firm value +* (equal to the default) so they cannot then change". So the defaults +* should probably be left unchanged until this fix is made. + +*/ + +/* Module Macros. */ +/* ============== */ +/* Set the name of the class we are implementing. This indicates to + the header files that define class interfaces that they should make + "protected" symbols available. */ +#define astCLASS DSBSpecFrame + +#define BADSB -9999 +#define FIRST_SB -1 +#define LSB -1 +#define LO 0 +#define USB 1 +#define LAST_SB 1 + +/* Include files. */ +/* ============== */ +/* Interface definitions. */ +/* ---------------------- */ + +#include "globals.h" /* Thread-safe global data access */ +#include "error.h" /* Error reporting facilities */ +#include "memory.h" /* Memory management facilities */ +#include "object.h" /* Base Object class */ +#include "channel.h" /* I/O channels */ +#include "specframe.h" /* Spectral frames (parent class) */ +#include "unit.h" /* Unit handling */ +#include "cmpmap.h" /* Compound Mappings */ +#include "unitmap.h" /* Unit Mappings */ +#include "winmap.h" /* Window Mappings */ +#include "dsbspecframe.h" /* Interface definition for this class */ +#include "globals.h" /* Thread-safe global data access */ + +/* Error code definitions. */ +/* ----------------------- */ +#include "ast_err.h" /* AST error codes */ + +/* C header files. */ +/* --------------- */ +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +/* Module Variables. */ +/* ================= */ + +/* Address of this static variable is used as a unique identifier for + member of this class. */ +static int class_check; + +/* Pointers to parent class methods which are extended by this class. */ +static const char *(* parent_getattrib)( AstObject *, const char *, int * ); +static const char *(* parent_getlabel)( AstFrame *, int, int * ); +static int (* parent_match)( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); +static int (* parent_subframe)( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); +static int (* parent_testattrib)( AstObject *, const char *, int * ); +static void (* parent_clearattrib)( AstObject *, const char *, int * ); +static void (* parent_setattrib)( AstObject *, const char *, int * ); +static void (* parent_overlay)( AstFrame *, const int *, AstFrame *, int * ); +static const char *(* parent_getdomain)( AstFrame *, int * ); + +/* Define macros for accessing each item of thread specific global data. */ +#ifdef THREAD_SAFE + +/* Define how to initialise thread-specific globals. */ +#define GLOBAL_inits \ + globals->Class_Init = 0; \ + globals->GetAttrib_Buff[ 0 ] = 0; \ + globals->GetLabel_Buff[ 0 ] = 0; \ + +/* Create the function that initialises global data for this module. */ +astMAKE_INITGLOBALS(DSBSpecFrame) + +/* Define macros for accessing each item of thread specific global data. */ +#define class_init astGLOBAL(DSBSpecFrame,Class_Init) +#define class_vtab astGLOBAL(DSBSpecFrame,Class_Vtab) +#define getattrib_buff astGLOBAL(DSBSpecFrame,GetAttrib_Buff) +#define getlabel_buff astGLOBAL(DSBSpecFrame,GetLabel_Buff) + + + +/* If thread safety is not needed, declare and initialise globals at static + variables. */ +#else + +/* Define the thread-specific globals for this class. */ + +/* Buffer returned by GetAttrib. */ +static char getattrib_buff[ 101 ]; + +/* Default Label string buffer */ +static char getlabel_buff[ 101 ]; + + +/* Define the class virtual function table and its initialisation flag + as static variables. */ +static AstDSBSpecFrameVtab class_vtab; /* Virtual function table */ +static int class_init = 0; /* Virtual function table initialised? */ + +#endif + +/* External Interface Function Prototypes. */ +/* ======================================= */ +/* The following functions have public prototypes only (i.e. no + protected prototypes), so we must provide local prototypes for use + within this module. */ +AstDSBSpecFrame *astDSBSpecFrameId_( const char *, ... ); + +/* Prototypes for Private Member Functions. */ +/* ======================================== */ + +static AstMapping *TopoMap( AstDSBSpecFrame *, int, const char *, int * ); +static AstMapping *ToLOMapping( AstDSBSpecFrame *, const char *, int * )__attribute__((unused)); +static AstMapping *ToLSBMapping( AstDSBSpecFrame *, const char *, int * ); +static AstMapping *ToUSBMapping( AstDSBSpecFrame *, const char *, int * ); +static const char *GetAttrib( AstObject *, const char *, int * ); +static const char *GetLabel( AstFrame *, int, int * ); +static double GetImagFreq( AstDSBSpecFrame *, int * ); +static double GetLO( AstDSBSpecFrame *, const char *, const char *, int * ); +static int Match( AstFrame *, AstFrame *, int, int **, int **, AstMapping **, AstFrame **, int * ); +static int SubFrame( AstFrame *, AstFrame *, int, const int *, const int *, AstMapping **, AstFrame **, int * ); +static int TestAttrib( AstObject *, const char *, int * ); +static void ClearAttrib( AstObject *, const char *, int * ); +static void Dump( AstObject *, AstChannel *, int * ); +static void Overlay( AstFrame *, const int *, AstFrame *, int * ); +static void SetAttrib( AstObject *, const char *, int * ); +static void VerifyAttrs( AstDSBSpecFrame *, const char *, const char *, const char *, int * ); +static const char *GetDomain( AstFrame *, int * ); + +static double GetIF( AstDSBSpecFrame *, int * ); +static int TestIF( AstDSBSpecFrame *, int * ); +static void ClearIF( AstDSBSpecFrame *, int * ); +static void SetIF( AstDSBSpecFrame *, double, int * ); + +static double GetDSBCentre( AstDSBSpecFrame *, int * ); +static int TestDSBCentre( AstDSBSpecFrame *, int * ); +static void ClearDSBCentre( AstDSBSpecFrame *, int * ); +static void SetDSBCentre( AstDSBSpecFrame *, double, int * ); + +static int GetSideBand( AstDSBSpecFrame *, int * ); +static int TestSideBand( AstDSBSpecFrame *, int * ); +static void ClearSideBand( AstDSBSpecFrame *, int * ); +static void SetSideBand( AstDSBSpecFrame *, int, int * ); + +static int GetAlignSideBand( AstDSBSpecFrame *, int * ); +static int TestAlignSideBand( AstDSBSpecFrame *, int * ); +static void ClearAlignSideBand( AstDSBSpecFrame *, int * ); +static void SetAlignSideBand( AstDSBSpecFrame *, int, int * ); + + +/* Member functions. */ +/* ================= */ +static void ClearAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* ClearAttrib + +* Purpose: +* Clear an attribute value for a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* void ClearAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the astClearAttrib protected +* method inherited from the SpecFrame class). + +* Description: +* This function clears the value of a specified attribute for a +* DSBSpecFrame, so that the default value will subsequently be used. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* attrib +* Pointer to a null-terminated string specifying the attribute +* name. This should be in lower case with no surrounding white +* space. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the DSBSpecFrame structure. */ + this = (AstDSBSpecFrame *) this_object; + +/* Check the attribute name and clear the appropriate attribute. */ + +/* DSBCentre. */ +/* ---------- */ + if ( !strcmp( attrib, "dsbcentre" ) ) { + astClearDSBCentre( this ); + +/* IF */ +/* -- */ + } else if ( !strcmp( attrib, "if" ) ) { + astClearIF( this ); + +/* SideBand */ +/* -------- */ + } else if ( !strcmp( attrib, "sideband" ) ) { + astClearSideBand( this ); + +/* AlignSideBand */ +/* ------------- */ + } else if ( !strcmp( attrib, "alignsideband" ) ) { + astClearAlignSideBand( this ); + +/* Read-only attributes. */ +/* --------------------- */ +/* Test if the attribute name matches any of the read-only attributes + of this class. If it does, then report an error. */ + } else if ( !strcmp( attrib, "imagfreq" ) ) { + astError( AST__NOWRT, "astClear: Invalid attempt to clear the \"%s\" " + "value for a %s.", status, attrib, astGetClass( this ) ); + astError( AST__NOWRT, "This is a read-only attribute." , status); + +/* If the attribute is not recognised, pass it on to the parent method + for further interpretation. */ + } else { + (*parent_clearattrib)( this_object, attrib, status ); + } +} + + +static const char *GetAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* GetAttrib + +* Purpose: +* Get the value of a specified attribute for a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* const char *GetAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the protected astGetAttrib +* method inherited from the SpecFrame class). + +* Description: +* This function returns a pointer to the value of a specified +* attribute for a DSBSpecFrame, formatted as a character string. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* attrib +* Pointer to a null-terminated string containing the name of +* the attribute whose value is required. This name should be in +* lower case, with all white space removed. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* - Pointer to a null-terminated string containing the attribute +* value. + +* Notes: +* - The returned string pointer may point at memory allocated +* within the DSBSpecFrame, or at static memory. The contents of the +* string may be over-written or the pointer may become invalid +* following a further invocation of the same function or any +* modification of the DSBSpecFrame. A copy of the string should +* therefore be made if necessary. +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Declare the thread specific global data */ + AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ + AstMapping *tmap; /* Ptr to Mapping from topofreq to this */ + const char *result; /* Pointer value to return */ + double dval; /* Attribute value */ + double dtemp; /* Attribute value */ + int ival; /* Attribute value */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Get a pointer to the structure holding thread-specific global data. */ + astGET_GLOBALS(this_object); + +/* Obtain a pointer to the SpecFrame structure. */ + this = (AstDSBSpecFrame *) this_object; + +/* Compare "attrib" with each recognised attribute name in turn, + obtaining the value of the required attribute. If necessary, write + the value into "getattrib_buff" as a null-terminated string in an appropriate + format. Set "result" to point at the result string. */ + +/* DSBCentre */ +/* --------- */ + if ( !strcmp( attrib, "dsbcentre" ) ) { + +/* Get the value as topocentric frequency in Hz. */ + dval = astGetDSBCentre( this ); + +/* Find the Mapping from topocentric frequency in Hz to the spectral system + described by this SpecFrame. */ + tmap = TopoMap( this, 0, "astGetAttrib", status ); + if ( astOK ) { + +/* Transform the internal value from topocentric frequency into the required + system. */ + astTran1( tmap, 1, &dval, 1, &dtemp ); + if( dtemp == AST__BAD ) { + astError( AST__INTER, "astGetAttrib(%s): Cannot convert DSBCentre " + "value from topocentric frequency to the required " + "system.", status, astGetClass( this ) ); + } else { + +/* Format it. */ + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dtemp ); + result = getattrib_buff; + } + tmap = astAnnul( tmap ); + } + +/* IF */ +/* -- */ + } else if ( !strcmp( attrib, "if" ) ) { + dval = astGetIF( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval*1.0E-9 ); + result = getattrib_buff; + } + +/* ImagFreq */ +/* -------- */ + } else if ( !strcmp( attrib, "imagfreq" ) ) { + dval = astGetImagFreq( this ); + if ( astOK ) { + (void) sprintf( getattrib_buff, "%.*g", AST__DBL_DIG, dval*1.0E-9 ); + result = getattrib_buff; + } + +/* SideBand */ +/* -------- */ + } else if ( !strcmp( attrib, "sideband" ) ) { + ival = astGetSideBand( this ); + if ( astOK ) { + result = ( ival == USB ) ? "USB" : (( ival == LO ) ? "LO" : "LSB" ); + } + +/* AlignSideBand */ +/* ------------- */ + } else if ( !strcmp( attrib, "alignsideband" ) ) { + ival = astGetAlignSideBand( this ) ? 1 : 0; + if ( astOK ) { + (void) sprintf( getattrib_buff, "%d", ival ); + result = getattrib_buff; + } + +/* If the attribute name was not recognised, pass it on to the parent + method for further interpretation. */ + } else { + result = (*parent_getattrib)( this_object, attrib, status ); + } + +/* Return the result. */ + return result; + +} + +static const char *GetDomain( AstFrame *this_frame, int *status ) { +/* +* Name: +* GetDomain + +* Purpose: +* Obtain a pointer to the Domain attribute string for a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* const char *GetDomain( AstFrame *this, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the astGetDomain protected +* method inherited from the SpecFrame class). + +* Description: +* This function returns a pointer to the Domain attribute string +* for a DSBSpecFrame. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A pointer to a constant null-terminated string containing the +* Domain value. + +* Notes: +* - The returned pointer or the string it refers to may become +* invalid following further invocation of this function or +* modification of the DSBSpecFrame. +* - A NULL pointer is returned if this function is invoked with +* the global error status set or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *this; /* Pointer to DSBSpecFrame structure */ + const char *result; /* Pointer value to return */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the DSBSpecFrame structure. */ + this = (AstDSBSpecFrame *) this_frame; + +/* If a Domain attribute string has been set, invoke the parent method + to obtain a pointer to it. */ + if ( astTestDomain( this ) ) { + result = (*parent_getdomain)( this_frame, status ); + +/* Otherwise, provide a pointer to a suitable default string. */ + } else { + result = "DSBSPECTRUM"; + } + +/* Return the result. */ + return result; +} + +static double GetImagFreq( AstDSBSpecFrame *this, int *status ) { +/* +*+ +* Name: +* astGetImagFreq + +* Purpose: +* Get the value of the ImagFreq attribute. + +* Type: +* Protected virtual function. + +* Synopsis: +* #include "dsbspecframe.h" +* double GetImagFreq( AstDSBSpecFrame *this ) + +* Class Membership: +* DSBSpecFrame method. + +* Description: +* This function returns the image sideband frequency corresponding to +* the rest frequency. + +* Parameters: +* this +* Pointer to the Frame. + +* Returned Value: +* The required frequency, in Hz. + +* Notes: +* - A value of AST__BAD will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*- +*/ + +/* Local Variables: */ + AstDSBSpecFrame *rf_frame;/* DSBSpecFrame describing the rest frequency */ + AstMapping *map; /* Pointer to "Observed to Image" mapping */ + double result; /* The returned frequency */ + double rf; /* Rest frequency in observed sideband */ + int sb; /* SideBand value */ + +/* Check the global error status. */ + if ( !astOK ) return AST__BAD; + +/* The RestFreq attribute is an observed sideband frequency in the + source's standard of rest, measured in Hz. Temporaily set attributes + to these values. Create a copy of the supplied DSBSpecFrame and set + its attributes to these values. */ + rf_frame = astCopy( this ); + astSetStdOfRest( rf_frame, AST__SCSOR ); + astSetSystem( rf_frame, AST__FREQ ); + astSetUnit( rf_frame, 0, "Hz" ); + astSetC( rf_frame, "SideBand", "observed" ); + +/* Create a Mapping which transforms positions from the observed to the + image sideband. */ + sb = astGetSideBand( rf_frame ); + if( sb == USB ) { + map = ToLSBMapping( rf_frame, "astGetImagFreq", status ); + + } else if( sb == LSB ) { + map = ToUSBMapping( rf_frame, "astGetImagFreq", status ); + + } else { + map = NULL; + astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " + "(%d) encountered (internal AST programming error).", status, + astGetClass( this ), sb ); + } + +/* Get the rest frequency in Hz, and transform it using the above Mapping. */ + rf = astGetRestFreq( rf_frame ); + astTran1( map, 1, &rf, 1, &result ); + +/* Free resources */ + map = astAnnul( map ); + rf_frame = astAnnul( rf_frame ); + +/* If an error has occurrred, return AST__BAD. */ + if( !astOK ) result = AST__BAD; + +/* Return the result. */ + return result; + +} + +static const char *GetLabel( AstFrame *this, int axis, int *status ) { +/* +* Name: +* GetLabel + +* Purpose: +* Access the Label string for a DSBSpecFrame axis. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* const char *GetLabel( AstFrame *this, int axis, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the astGetLabel method inherited +* from the SpecFrame class). + +* Description: +* This function returns a pointer to the Label string for a specified axis +* of a DSBSpecFrame. + +* Parameters: +* this +* Pointer to the SpecFrame. +* axis +* Axis index (zero-based) identifying the axis for which information is +* required. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a constant null-terminated character string containing the +* requested information. + +* Notes: +* - A NULL pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Declare the thread specific global data */ + const char *result; /* Pointer to label string */ + +/* Check the global error status. */ + if ( !astOK ) return NULL; + +/* Get a pointer to the structure holding thread-specific global data. */ + astGET_GLOBALS(this); + +/* Initialise. */ + result = NULL; + +/* Validate the axis index. */ + astValidateAxis( this, axis, 1, "astGetLabel" ); + +/* Invoke the parent astGetLabel method to obtain a pointer to it. */ + result = (*parent_getlabel)( this, axis, status ); + +/* Check if this is a default value. If so, append a string indicating + the sideband. */ + if ( !astTestLabel( this, axis ) ) { + +/* If OK, supply a pointer to a suitable default label string. */ + sprintf( getlabel_buff, "%s (%s)", result, astGetAttrib( this, "sideband" ) ); + result = getlabel_buff; + } + +/* Return the result. */ + return result; + +} + +static double GetLO( AstDSBSpecFrame *this, const char *check_msg, + const char *method, int *status ) { +/* +* Name: +* GetLO + +* Purpose: +* Get the Local Oscillator frequency. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* double GetLO( AstDSBSpecFrame *this, const char *check_msg, +* const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame method. + +* Description: +* This function returns the local oscillator frequency in topocentric +* frequency. + +* Parameters: +* this +* Pointer to the Frame. +* check_msg +* If not NULL, an error will be reported if either the DSBCentre +* or IF attribute has not been set to an explicit value. In this +* case, the error message will include the supplied text. +* method +* The name of the calling method - used in error messages. +* status +* Pointer to the inherited status value. + +* Returned Value: +* The local oscillator frequency, in Hz. + +* Notes: +* - An error is reported if the local oscillator frequency looks +* un-physical (specifically, if it is less than the absolute value of +* the intermediate frequency). +* - A value of AST__BAD will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*- +*/ + +/* Local Variables: */ + double f_if; /* Intermediate frequency (topo,HZ) */ + double result; /* The returned frequency */ + +/* Check the global error status. */ + if ( !astOK ) return AST__BAD; + +/* If required, check that explicit values have been assigned to the required + attributes (i.e. report an error if a default value would be used for + either attribute). */ + if( check_msg ) VerifyAttrs( this, check_msg, "IF DSBCentre", method, + status ); + +/* The local oscillator is the sum of the intermediate frequency and the + observation centre frequency. */ + f_if = astGetIF( this ); + result = astGetDSBCentre( this ) + f_if; + +/* Check the local oscillator frequency is no smaller than the absolute + intermediate frequency. */ + if( result < fabs( f_if ) && astOK ) { + astError( AST__ATTIN, "%s(%s): The local oscillator frequency (%g Hz) " + "is too low (less than the intermediate frequency: %g Hz).", + status, method, astGetClass( this ), result, fabs( f_if ) ); + astError( AST__ATTIN, " This could be caused by a bad value for" + " either the IF attribute (currently %g Hz) or the DSBCentre " + "attribute (currently %g Hz).", status, f_if, + astGetDSBCentre( this ) ); + } + +/* If an error has occurrred, return AST__BAD. */ + if( !astOK ) result = AST__BAD; + +/* Return the result. */ + return result; +} + +void astInitDSBSpecFrameVtab_( AstDSBSpecFrameVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitDSBSpecFrameVtab + +* Purpose: +* Initialise a virtual function table for a DSBSpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "dsbspecframe.h" +* void astInitDSBSpecFrameVtab( AstDSBSpecFrameVtab *vtab, const char *name ) + +* Class Membership: +* DSBSpecFrame vtab initialiser. + +* Description: +* This function initialises the component of a virtual function +* table which is used by the DSBSpecFrame class. + +* Parameters: +* vtab +* Pointer to the virtual function table. The components used by +* all ancestral classes will be initialised if they have not already +* been initialised. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the virtual function table belongs (it +* is this pointer value that will subsequently be returned by the Object +* astClass function). +*- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstObjectVtab *object; /* Pointer to Object component of Vtab */ + AstFrameVtab *frame; /* Pointer to Frame component of Vtab */ + +/* Check the local error status. */ + if ( !astOK ) return; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Initialize the component of the virtual function table used by the + parent class. */ + astInitSpecFrameVtab( (AstSpecFrameVtab *) vtab, name ); + +/* Store a unique "magic" value in the virtual function table. This + will be used (by astIsADSBSpecFrame) to determine if an object belongs + to this class. We can conveniently use the address of the (static) + class_check variable to generate this unique value. */ + vtab->id.check = &class_check; + vtab->id.parent = &(((AstSpecFrameVtab *) vtab)->id); + +/* Initialise member function pointers. */ +/* ------------------------------------ */ +/* Store pointers to the member functions (implemented here) that provide + virtual methods for this class. */ + vtab->ClearDSBCentre = ClearDSBCentre; + vtab->TestDSBCentre = TestDSBCentre; + vtab->GetDSBCentre = GetDSBCentre; + vtab->SetDSBCentre = SetDSBCentre; + + vtab->ClearIF = ClearIF; + vtab->TestIF = TestIF; + vtab->GetIF = GetIF; + vtab->SetIF = SetIF; + + vtab->ClearSideBand = ClearSideBand; + vtab->TestSideBand = TestSideBand; + vtab->GetSideBand = GetSideBand; + vtab->SetSideBand = SetSideBand; + + vtab->ClearAlignSideBand = ClearAlignSideBand; + vtab->TestAlignSideBand = TestAlignSideBand; + vtab->GetAlignSideBand = GetAlignSideBand; + vtab->SetAlignSideBand = SetAlignSideBand; + + vtab->GetImagFreq = GetImagFreq; + +/* Save the inherited pointers to methods that will be extended, and + replace them with pointers to the new member functions. */ + object = (AstObjectVtab *) vtab; + frame = (AstFrameVtab *) vtab; + + parent_clearattrib = object->ClearAttrib; + object->ClearAttrib = ClearAttrib; + + parent_getattrib = object->GetAttrib; + object->GetAttrib = GetAttrib; + + parent_setattrib = object->SetAttrib; + object->SetAttrib = SetAttrib; + + parent_testattrib = object->TestAttrib; + object->TestAttrib = TestAttrib; + + parent_getdomain = frame->GetDomain; + frame->GetDomain = GetDomain; + + parent_overlay = frame->Overlay; + frame->Overlay = Overlay; + + parent_match = frame->Match; + frame->Match = Match; + + parent_subframe = frame->SubFrame; + frame->SubFrame = SubFrame; + + parent_getlabel = frame->GetLabel; + frame->GetLabel = GetLabel; + +/* Declare the class delete function.*/ + astSetDump( vtab, Dump, "DSBSpecFrame", "Dual sideband spectral axis" ); + +/* If we have just initialised the vtab for the current class, indicate + that the vtab is now initialised, and store a pointer to the class + identifier in the base "object" level of the vtab. */ + if( vtab == &class_vtab ) { + class_init = 1; + astSetVtabClassIdentifier( vtab, &(vtab->id) ); + } +} + +static int Match( AstFrame *template_frame, AstFrame *target, int matchsub, + int **template_axes, int **target_axes, AstMapping **map, + AstFrame **result, int *status ) { +/* +* Name: +* Match + +* Purpose: +* Determine if conversion is possible between two coordinate systems. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* int Match( AstFrame *template, AstFrame *target, int matchsub, +* int **template_axes, int **target_axes, +* AstMapping **map, AstFrame **result, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the protected astMatch method +* inherited from the SpecFrame class). + +* Description: +* This function matches a "template" DSBSpecFrame to a "target" Frame and +* determines whether it is possible to convert coordinates between them. +* If it is, a mapping that performs the transformation is returned along +* with a new Frame that describes the coordinate system that results when +* this mapping is applied to the "target" coordinate system. In addition, +* information is returned to allow the axes in this "result" Frame to be +* associated with the corresponding axes in the "target" and "template" +* Frames from which they are derived. + +* Parameters: +* template +* Pointer to the template DSBSpecFrame. This describes the coordinate +* system (or set of possible coordinate systems) into which we wish to +* convert our coordinates. +* target +* Pointer to the target Frame. This describes the coordinate system in +* which we already have coordinates. +* matchsub +* If zero then a match only occurs if the template is of the same +* class as the target, or of a more specialised class. If non-zero +* then a match can occur even if this is not the case. +* template_axes +* Address of a location where a pointer to int will be returned if the +* requested coordinate conversion is possible. This pointer will point +* at a dynamically allocated array of integers with one element for each +* axis of the "result" Frame (see below). It must be freed by the caller +* (using astFree) when no longer required. +* +* For each axis in the result Frame, the corresponding element of this +* array will return the index of the template DSBSpecFrame axis from +* which it is derived. If it is not derived from any template +* DSBSpecFrame axis, a value of -1 will be returned instead. +* target_axes +* Address of a location where a pointer to int will be returned if the +* requested coordinate conversion is possible. This pointer will point +* at a dynamically allocated array of integers with one element for each +* axis of the "result" Frame (see below). It must be freed by the caller +* (using astFree) when no longer required. +* +* For each axis in the result Frame, the corresponding element of this +* array will return the index of the target Frame axis from which it +* is derived. If it is not derived from any target Frame axis, a value +* of -1 will be returned instead. +* map +* Address of a location where a pointer to a new Mapping will be +* returned if the requested coordinate conversion is possible. If +* returned, the forward transformation of this Mapping may be used to +* convert coordinates between the "target" Frame and the "result" +* Frame (see below) and the inverse transformation will convert in the +* opposite direction. +* result +* Address of a location where a pointer to a new Frame will be returned +* if the requested coordinate conversion is possible. If returned, this +* Frame describes the coordinate system that results from applying the +* returned Mapping (above) to the "target" coordinate system. In +* general, this Frame will combine attributes from (and will therefore +* be more specific than) both the target and the template Frames. In +* particular, when the template allows the possibility of transformaing +* to any one of a set of alternative coordinate systems, the "result" +* Frame will indicate which of the alternatives was used. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A non-zero value is returned if the requested coordinate conversion is +* possible. Otherwise zero is returned (this will not in itself result in +* an error condition). + +* Notes: +* - A value of zero will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. + +* Implementation Notes: +* This implementation addresses the matching of a DSBSpecFrame class +* object to any other class of Frame. A DSBSpecFrame will match any class +* of DSBSpecFrame (i.e. possibly from a derived class) but will not match +* a less specialised class of Frame (except for a SpecFrame). +*/ + +/* Local Variables: */ + AstDSBSpecFrame *template; /* Pointer to template DSBSpecFrame structure */ + AstFrame *frame0; /* Pointer to Frame underlying axis 0 */ + int iaxis0; /* Axis index underlying axis 0 */ + int match; /* Coordinate conversion possible? */ + +/* Initialise the returned values. */ + *template_axes = NULL; + *target_axes = NULL; + *map = NULL; + *result = NULL; + match = 0; + +/* Check the global error status. */ + if ( !astOK ) return match; + +/* Obtain a pointer to the template DSBSpecFrame structure. */ + template = (AstDSBSpecFrame *) template_frame; + +/* The first criterion for a match is that the template matches as a + SpecFrame class object. This ensures that the number of axes (1) and + domain, class, etc. of the target Frame are suitable. Invoke the parent + "astMatch" method to verify this. */ + match = (*parent_match)( template_frame, target, matchsub, + template_axes, target_axes, map, result, status ); + +/* If a match was found, the target Frame must be (or contain) a SpecFrame, + but this target SpecFrame may be a simple SpecFrame rather than a + DSBSpecFrame. We use the returned objects directly if the target + SpecFrame is not a DSBSpecFrame. So if a DSBSpecFrame and a base + SpecFrame are aligned, this will result in the DSBSpecFrame behaving as + a normal SpecFrame. */ + if ( astOK && match ) { + +/* Get the primary Frame associated with the matching target axis. */ + astPrimaryFrame( target, (*target_axes)[ 0 ], &frame0, &iaxis0 ); + +/* Skip this next section, thus retaining the values returned by the + parent Match method above, if the target axis is not a DSBSpecFrame. */ + if( astIsADSBSpecFrame( frame0 ) ) { + +/* Annul the returned objects, which are not needed, but keep the axis + association arrays which already hold the correct values. */ + *map = astAnnul( *map ); + *result = astAnnul( *result ); + +/* Use the target's "astSubFrame" method to create a new Frame (the + result Frame) with a copy of of the target axis. This process also + overlays the template attributes on to the target Frame and returns a + Mapping between the target and result Frames which effects the required + coordinate conversion. */ + match = astSubFrame( target, template, 1, *target_axes, *template_axes, + map, result ); + } + +/* Free resources. */ + frame0 = astAnnul( frame0 ); + + } + +/* If an error occurred, or conversion to the result Frame's coordinate + system was not possible, then free all memory, annul the returned + objects, and reset the returned value. */ + if ( !astOK || !match ) { + if( *template_axes ) *template_axes = astFree( *template_axes ); + if( *target_axes ) *target_axes = astFree( *target_axes ); + if( *map ) *map = astAnnul( *map ); + if( *result ) *result = astAnnul( *result ); + match = 0; + } + +/* Return the result. */ + return match; +} + +static void Overlay( AstFrame *template, const int *template_axes, + AstFrame *result, int *status ) { +/* +* Name: +* Overlay + +* Purpose: +* Overlay the attributes of a template DSBSpecFrame on to another Frame. + +* Type: +* Private function. + +* Synopsis: +* #include "specframe.h" +* void Overlay( AstFrame *template, const int *template_axes, +* AstFrame *result, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the protected astOverlay method +* inherited from the SpecFrame class). + +* Description: +* This function overlays attributes of a DSBSpecFrame (the "template") on to +* another Frame, so as to over-ride selected attributes of that second +* Frame. Normally only those attributes which have been specifically set +* in the template will be transferred. This implements a form of +* defaulting, in which a Frame acquires attributes from the template, but +* retains its original attributes (as the default) if new values have not +* previously been explicitly set in the template. +* +* Note that if the result Frame is a DSBSpecFrame and a change of spectral +* coordinate system occurs as a result of overlaying its System +* attribute, then some of its original attribute values may no +* longer be appropriate (e.g. the Title, or attributes describing +* its axes). In this case, these will be cleared before overlaying +* any new values. + +* Parameters: +* template +* Pointer to the template DSBSpecFrame, for which values should have been +* explicitly set for any attribute which is to be transferred. +* template_axes +* Pointer to an array of int, with one element for each axis of the +* "result" Frame (see below). For each axis in the result frame, the +* corresponding element of this array should contain the (zero-based) +* index of the template axis to which it corresponds. This array is used +* to establish from which template axis any axis-dependent attributes +* should be obtained. +* +* If any axis in the result Frame is not associated with a template +* axis, the corresponding element of this array should be set to -1. +* +* If a NULL pointer is supplied, the template and result axis +* indices are assumed to be identical. +* result +* Pointer to the Frame which is to receive the new attribute values. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* void + +* Notes: +* - In general, if the result Frame is not from the same class as the +* template DSBSpecFrame, or from a class derived from it, then attributes may +* exist in the template DSBSpecFrame which do not exist in the result Frame. +* In this case, these attributes will not be transferred. +*/ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Invoke the parent class astOverlay method to transfer attributes inherited + from the parent class. */ + (*parent_overlay)( template, template_axes, result, status ); + +/* Check if the result Frame is a DSBSpecFrame or from a class derived from + DSBSpecFrame. If not, we cannot transfer DSBSpecFrame attributes to it as it is + insufficiently specialised. In this case simply omit these attributes. */ + if( astIsADSBSpecFrame( result ) && astOK ) { + +/* Define macros that test whether an attribute is set in the template and, + if so, transfers its value to the result. */ +#define OVERLAY(attribute) \ + if ( astTest##attribute( template ) ) { \ + astSet##attribute( result, astGet##attribute( template ) ); \ + } + +/* Use the macro to transfer each DSBSpecFrame attribute in turn. */ + OVERLAY(DSBCentre) + OVERLAY(IF) + OVERLAY(SideBand) + OVERLAY(AlignSideBand) + } + +/* Undefine macros local to this function. */ +#undef OVERLAY +} + +static void SetAttrib( AstObject *this_object, const char *setting, int *status ) { +/* +* Name: +* SetAttrib + +* Purpose: +* Set an attribute value for a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* void SetAttrib( AstObject *this, const char *setting ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the astSetAttrib protected +* method inherited from the SpecFrame class). + +* Description: +* This function assigns an attribute value for a DSBSpecFrame, the +* attribute and its value being specified by means of a string of +* the form: +* +* "attribute= value " +* +* Here, "attribute" specifies the attribute name and should be in +* lower case with no white space present. The value to the right +* of the "=" should be a suitable textual representation of the +* value to be assigned and this will be interpreted according to +* the attribute's data type. White space surrounding the value is +* only significant for string attributes. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* setting +* Pointer to a null-terminated string specifying the new attribute +* value. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ + AstMapping *tmap; /* Ptr to Mapping from this to topofreq */ + AstMapping *umap; /* Ptr to Mapping between units */ + double dtemp; /* Attribute value */ + double dval; /* Attribute value */ + int ival; /* Attribute value */ + int len; /* Length of setting string */ + int nc; /* Used length */ + int off; /* Offset to start of string */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the DSBSpecFrame structure. */ + this = (AstDSBSpecFrame *) this_object; + +/* Obtain the length of the setting string. */ + len = (int) strlen( setting ); + +/* Test for each recognised attribute in turn, using "astSscanf" to parse the + setting string and extract the attribute value (or an offset to it in the + case of string values). In each case, use the value set in "nc" to check + that the entire string was matched. Once a value has been obtained, use the + appropriate method to set it. */ + +/* DSBCentre */ +/* --------- */ + if ( strstr( setting, "dsbcentre=" ) ) { + +/* Without any units indication - assume it is supplied in the system of + the DSBSpecFrame. */ + int ok = 0; + if( nc = 0, + ( 1 == astSscanf( setting, "dsbcentre= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + ok = 1; + +/* With units indication. Is there a Mapping from the supplied units to the + units used by the DSBSpecFrame? If so, use the Mapping to convert the + supplied value to the required units. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "dsbcentre= %lg %n%*s %n", &dval, &off, &nc ) ) + && ( nc >= len ) ) { + + if( ( umap = astUnitMapper( setting + off, astGetUnit( this, 0 ), NULL, NULL ) ) ) { + astTran1( umap, 1, &dval, 1, &dtemp ); + dval = dtemp; + umap = astAnnul( umap ); + if( astOK && dval != AST__BAD ) ok = 1; + +/* Otherwise report an error. */ + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): Value supplied for " + "attribute \"DSBCentre\" (%s) uses units which are " + "inappropriate for the current spectral system (%s).", status, + astGetClass( this ), setting + 10, + astGetTitle( this ) ); + } + } + +/* Convert the value from the supplied system to topocentric frequency in + Hx, and store. */ + if( ok ) { + +/* Find the Mapping from the spectral system described by this SpecFrame to + topocentric frequency in Hz. */ + tmap = TopoMap( this, 1, "astSetAttrib", status ); + if ( astOK ) { + +/* Transform the supplied value to topocentric frequency. */ + astTran1( tmap, 1, &dval, 1, &dtemp ); + if( dtemp == AST__BAD ) { + astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " + "invalid for a %s.", status, astGetClass( this ), setting, + astGetClass( this ) ); + } else { + +/* Store it. */ + astSetDSBCentre( this, dtemp ); + + } + tmap = astAnnul( tmap ); + } + + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " + "invalid for a %s.", status, astGetClass( this ), setting, + astGetClass( this ) ); + } + +/* IF */ +/* -- */ +/* Without any units indication - assume GHz. Convert to Hz for storage. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "if= %lg %n", &dval, &nc ) ) + && ( nc >= len ) ) { + astSetIF( this, dval*1.0E9 ); + +/* With units indication. */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "if= %lg %n%*s %n", &dval, &off, &nc ) ) + && ( nc >= len ) ) { + +/* Is there a Mapping from the supplied units to Hz? If so, use the + Mapping to convert the supplied value to Hz. */ + if( ( umap = astUnitMapper( setting + off, "Hz", NULL, NULL ) ) ) { + astTran1( umap, 1, &dval, 1, &dtemp ); + umap = astAnnul( umap ); + +/* Set the intermediate frequency. */ + astSetIF( this, dtemp ); + +/* Otherwise report an error. */ + } else if( astOK ) { + astError( AST__ATTIN, "astSetAttrib(%s): Intermediate frequency given " + "in an inappropriate system of units \"%g %s\".", status, + astGetClass( this ), dval, setting + off ); + } + +/* SideBand */ +/* -------- */ + } else if ( nc = 0, + ( 0 == astSscanf( setting, "sideband= %n%*s %n", &ival, &nc ) ) + && ( nc >= len ) ) { + + if( astChrMatch( "usb", setting+ival ) ) { + astSetSideBand( this, USB ); + + } else if( astChrMatch( "lsb", setting+ival ) ) { + astSetSideBand( this, LSB ); + + } else if( astChrMatch( "lo", setting+ival ) ) { + astSetSideBand( this, LO ); + + } else if( astChrMatch( "observed", setting+ival ) ) { + astSetSideBand( this, ( astGetIF( this ) > 0 ) ? LSB : USB ); + + } else if( astChrMatch( "image", setting+ival ) ) { + astSetSideBand( this, ( astGetIF( this ) <= 0 ) ? LSB : USB ); + + } else { + astError( AST__ATTIN, "astSetAttrib(%s): The setting \"%s\" is " + "invalid for a %s.", status, astGetClass( this ), setting, + astGetClass( this ) ); + } + +/* AlignSideBand */ +/* ------------- */ + } else if ( nc = 0, + ( 1 == astSscanf( setting, "alignsideband= %d %n", &ival, &nc ) ) + && ( nc >= len ) ) { + astSetAlignSideBand( this, ival ); + +/* Read-only attributes. */ +/* --------------------- */ +/* Define a macro to see if the setting string matches any of the + read-only attributes of this class. */ +#define MATCH(attrib) \ + ( nc = 0, ( 0 == astSscanf( setting, attrib "=%*[^\n]%n", &nc ) ) && \ + ( nc >= len ) ) + +/* Use this macro to report an error if a read-only attribute has been + specified. */ + } else if ( MATCH( "imagfreq" ) ) { + astError( AST__NOWRT, "astSet: The setting \"%s\" is invalid for a %s.", status, + setting, astGetClass( this ) ); + astError( AST__NOWRT, "This is a read-only attribute." , status); + +/* Pass any unrecognised setting to the parent method for further + interpretation. */ + } else { + (*parent_setattrib)( this_object, setting, status ); + } +} + +static int SubFrame( AstFrame *target_frame, AstFrame *template, + int result_naxes, const int *target_axes, + const int *template_axes, AstMapping **map, + AstFrame **result, int *status ) { +/* +* Name: +* SubFrame + +* Purpose: +* Select axes from a DSBSpecFrame and convert to the new coordinate +* system. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* int SubFrame( AstFrame *target, AstFrame *template, +* int result_naxes, const int *target_axes, +* const int *template_axes, AstMapping **map, +* AstFrame **result, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the protected astSubFrame +* method inherited from the SpecFrame class). + +* Description: +* This function selects a requested sub-set (or super-set) of the axes +* from a "target" DSBSpecFrame and creates a new Frame with copies of +* the selected axes assembled in the requested order. It then +* optionally overlays the attributes of a "template" Frame on to the +* result. It returns both the resulting Frame and a Mapping that +* describes how to convert between the coordinate systems described by +* the target and result Frames. If necessary, this Mapping takes +* account of any differences in the Frames' attributes due to the +* influence of the template. + +* Parameters: +* target +* Pointer to the target DSBSpecFrame, from which axes are to be +* selected. +* template +* Pointer to the template Frame, from which new attributes for the +* result Frame are to be obtained. Optionally, this may be NULL, in +* which case no overlaying of template attributes will be performed. +* result_naxes +* Number of axes to be selected from the target Frame. This number may +* be greater than or less than the number of axes in this Frame (or +* equal). +* target_axes +* Pointer to an array of int with result_naxes elements, giving a list +* of the (zero-based) axis indices of the axes to be selected from the +* target DSBSpecFrame. The order in which these are given determines +* the order in which the axes appear in the result Frame. If any of the +* values in this array is set to -1, the corresponding result axis will +* not be derived from the target Frame, but will be assigned default +* attributes instead. +* template_axes +* Pointer to an array of int with result_naxes elements. This should +* contain a list of the template axes (given as zero-based axis indices) +* with which the axes of the result Frame are to be associated. This +* array determines which axes are used when overlaying axis-dependent +* attributes of the template on to the result. If any element of this +* array is set to -1, the corresponding result axis will not receive any +* template attributes. +* +* If the template argument is given as NULL, this array is not used and +* a NULL pointer may also be supplied here. +* map +* Address of a location to receive a pointer to the returned Mapping. +* The forward transformation of this Mapping will describe how to +* convert coordinates from the coordinate system described by the target +* DSBSpecFrame to that described by the result Frame. The inverse +* transformation will convert in the opposite direction. +* result +* Address of a location to receive a pointer to the result Frame. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* A non-zero value is returned if coordinate conversion is possible +* between the target and the result Frame. Otherwise zero is returned and +* *map and *result are returned as NULL (but this will not in itself +* result in an error condition). In general, coordinate conversion should +* always be possible if no template Frame is supplied but may not always +* be possible otherwise. + +* Notes: +* - A value of zero will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. + +* Implementation Notes: +* - This implementation addresses the selection of axes from a +* DSBSpecFrame object. This results in another object of the same class +* only if the single DSBSpecFrame axis is selected exactly once. +* Otherwise, the result is a Frame class object which inherits the +* DSBSpecFrame's axis information (if appropriate) but none of the other +* properties of a DSBSpecFrame. +* - In the event that a DSBSpecFrame results, the returned Mapping will +* take proper account of the relationship between the target and result +* coordinate systems. +* - In the event that a Frame class object results, the returned Mapping +* will only represent a selection/permutation of axes. + +* Implementation Deficiencies: +* - Any axis selection is currently permitted. Probably this should be +* restricted so that each axis can only be selected once. The +* astValidateAxisSelection method will do this but currently there are bugs +* in the CmpFrame class that cause axis selections which will not pass this +* test. Install the validation when these are fixed. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *dsbresult;/* Pointer to the DSBSpecFrame result Frame */ + AstDSBSpecFrame *dsbtarget;/* Pointer to the DSBSpecFrame target Frame */ + AstMapping *map1; /* Intermediate Mapping */ + AstMapping *map2; /* Intermediate Mapping */ + AstMapping *map3; /* Intermediate Mapping */ + int alignsb; /* Use sidebands to align the Frames? */ + int match; /* Coordinate conversion is possible? */ + int obs_sb; /* The observed sideband value */ + int old_sb; /* The original Sideband value */ + +/* Initialise the returned values. */ + *map = NULL; + *result = NULL; + match = 0; + +/* Check the global error status. */ + if ( !astOK ) return match; + +/* Invoke the astSubFrame method inherited from the parent SpecFrame + class. This will (if possible) create a result Frame which is a + DSBSpecFrame (since the supplied target Frame is a DSBSpecFrame). + However, the Mapping from target to result Frame will take no account + of any differences in the values of the attributes specific to the + DSBSpecFrame class. */ + match = (*parent_subframe)( target_frame, template, result_naxes, + target_axes, template_axes, map, result, status ); + +/* If a match occurred, and the result and template Frames are both + DSBSpecFrames, we now modify the Mapping to take account of + DSBSpecFrame-specific attributes. */ + if( match && template && astIsADSBSpecFrame( template ) && + astIsADSBSpecFrame( *result ) ) { + +/* Get pointers to the two DSBSpecFrames */ + dsbtarget = (AstDSBSpecFrame *) target_frame; + +/* See whether alignment occurs between sidebands. If the current call to + this function is part of the process of restoring a FrameSet's integrity + following changes to the FrameSet's current Frame, then we ignore the + setting of the AlignSideBand attributes and use 1. This ensures that + when the SideBand attribute (for instance) is changed via a FrameSet + pointer, the Mappings within the FrameSet are modified to produce + frequencies in the new SideBand. In most other cases, astronomers + usually want to align the DSBSpecFrames as if they were basic SpecFrames + (that is, ignoring the setting of the SideBand attribute). */ + if( astGetFrameFlags( target_frame ) & AST__INTFLAG ) { + alignsb = 1; + } else { + alignsb = astGetAlignSideBand( dsbtarget ) && + astGetAlignSideBand( (AstDSBSpecFrame *) template ); + } + +/* If we are aligning the sidebands we need to modify the Mapping + returned above by the parent SubFrame method. The existing Mapping + will convert between the spectral systems represented by the two + DSBSpecFrames but will not take account of any difference in + sidebands. */ + if( alignsb ) { + +/* We assume that alignment occurs in the observed sideband. Determine + which side band is the observed sideband in the target. */ + old_sb = astGetSideBand( dsbtarget ); + astSetC( dsbtarget, "SideBand", "observed" ); + obs_sb = astGetSideBand( dsbtarget ); + astSetSideBand( dsbtarget, old_sb ); + +/* Create a Mapping which transforms positions from the target to an exact + copy of the target in which the SideBand attribute is set to the + observed (USB or LSB) sideband. This will be a UnitMap if the target + already represents the observed sideband. */ + if( obs_sb == USB ) { + map1 = ToUSBMapping( dsbtarget, "astSubFrame", status ); + + } else if( obs_sb == LSB ) { + map1 = ToLSBMapping( dsbtarget, "astSubFrame", status ); + + } else { + map1 = NULL; + astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " + "(%d) encountered (internal AST programming error).", status, + astGetClass( target_frame ), obs_sb ); + } + +/* Determine which side band is the observed sideband in the result. */ + dsbresult = (AstDSBSpecFrame *) *result; + old_sb = astGetSideBand( dsbresult ); + astSetC( dsbresult, "SideBand", "observed" ); + obs_sb = astGetSideBand( dsbresult ); + astSetSideBand( dsbresult, old_sb ); + +/* Create a Mapping which transforms positions from the result to an exact + copy of the result in which the SideBand attribute is set to the + obserfed sideband. This will be a UnitMap if the target already represents + the observed sideband. */ + if( obs_sb == USB ) { + map2 = ToUSBMapping( dsbresult, "astSubFrame", status ); + + } else if( obs_sb == LSB ) { + map2 = ToLSBMapping( dsbresult, "astSubFrame", status ); + + } else { + map2 = NULL; + astError( AST__INTER, "astGetImagFreq(%s): Illegal sideband value " + "(%d) encountered (internal AST programming error).", status, + astGetClass( target_frame ), obs_sb ); + } + +/* Invert it to get the mapping from the observed sideband to the result. */ + astInvert( map2 ); + +/* Form a Mapping which first maps target values to the observed sideband, + then applies the Mapping returned by the parent SubFrame method in + order to convert between spectral systems, and then converts from the + observed sideband to the SideBand of the result. */ + map3 = (AstMapping *) astCmpMap( map1, *map, 1, "", status ); + map1 = astAnnul( map1 ); + *map = astAnnul( *map ); + map1 = (AstMapping *) astCmpMap( map3, map2, 1, "", status ); + map3 = astAnnul( map3 ); + map2 = astAnnul( map2 ); + +/* Returned the simplified Mapping. */ + *map = astSimplify( map1 ); + map1 = astAnnul( map1 ); + } + } + +/* If an error occurred or no match was found, annul the returned + objects and reset the returned result. */ + if ( !astOK || !match ) { + if( *map ) *map = astAnnul( *map ); + if( *result ) *result = astAnnul( *result ); + match = 0; + } + +/* Return the result. */ + return match; + +} + +static int TestAttrib( AstObject *this_object, const char *attrib, int *status ) { +/* +* Name: +* TestAttrib + +* Purpose: +* Test if a specified attribute value is set for a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* int TestAttrib( AstObject *this, const char *attrib, int *status ) + +* Class Membership: +* DSBSpecFrame member function (over-rides the astTestAttrib protected +* method inherited from the SpecFrame class). + +* Description: +* This function returns a boolean result (0 or 1) to indicate whether +* a value has been set for one of a DSBSpecFrame's attributes. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* attrib +* Pointer to a null-terminated string specifying the attribute +* name. This should be in lower case with no surrounding white +* space. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* One if a value has been set, otherwise zero. + +* Notes: +* - A value of zero will be returned if this function is invoked +* with the global status set, or if it should fail for any reason. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ + int result; /* Result value to return */ + +/* Initialise. */ + result = 0; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Obtain a pointer to the DSBSpecFrame structure. */ + this = (AstDSBSpecFrame *) this_object; + +/* Check the attribute name and test the appropriate attribute. */ + +/* DSBCentre */ +/* --------- */ + if ( !strcmp( attrib, "dsbcentre" ) ) { + result = astTestDSBCentre( this ); + +/* IF */ +/* -- */ + } else if ( !strcmp( attrib, "if" ) ) { + result = astTestIF( this ); + +/* SideBand */ +/* -------- */ + } else if ( !strcmp( attrib, "sideband" ) ) { + result = astTestSideBand( this ); + +/* AlignSideBand */ +/* ------------- */ + } else if ( !strcmp( attrib, "alignsideband" ) ) { + result = astTestAlignSideBand( this ); + +/* Read-only attributes. */ +/* --------------------- */ +/* Test if the attribute name matches any of the read-only attributes + of this class. If it does, then return zero. */ + } else if ( !strcmp( attrib, "imagfreq" ) ) { + result = 0; + +/* If the attribute is not recognised, pass it on to the parent method + for further interpretation. */ + } else { + result = (*parent_testattrib)( this_object, attrib, status ); + } + +/* Return the result, */ + return result; +} + +static AstMapping *ToLOMapping( AstDSBSpecFrame *this, const char *method, int *status ){ +/* +* Name: +* ToLOMapping + +* Purpose: +* Create a Mapping which transforms a DSBSpecFrame to offset from the +* local oscillator frequency. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstMapping *ToLOMapping( AstDSBSpecFrame *this, const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame member function + +* Description: +* This function returns a pointer to a new Mapping which transforms +* positions in the supplied DSBSpecFrame into an offset from the local +* oscillator frequency. This will be a UnitMap if the DSBSpecFrame +* already represents offset from the local oscillator frequency. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* method +* Pointer to a null-terminated string containing the name of the +* public invoking method. This is only used in the construction of +* error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a new Mapping. + +* Notes: +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + AstMapping *fmap; /* LSB to USB (topo freq) */ + AstMapping *map1; /* This to USB (topo freq) */ + AstMapping *map2; /* This (LSB) to This (USB) */ + AstMapping *result; /* Pointer to the returned Mapping */ + AstMapping *tmap; /* This to topocentric freq */ + double f_lo; /* Local oscillator freq (topo Hz) */ + double f_in_a; /* First LSB or USB freq */ + double f_in_b; /* Second LSB or USB freq */ + double f_out_a; /* First LO freq */ + double f_out_b; /* Second LO freq */ + int sb; /* SideBand value */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* If the DSBSpecFrame already represents LO offset, return a UnitMap.*/ + sb = astGetSideBand( this ); + if( sb == LO ) { + result = (AstMapping *) astUnitMap( 1, "", status ); + +/* If the DSBSpecFrame represents the USB or LSB, create a suitable WinMap. */ + } else { + +/* Find the Mapping from the spectral system described by this SpecFrame to + topocentric frequency in Hz. */ + tmap = TopoMap( this, 1, method, status ); + +/* Calculate the local oscillator frequency (topocentric in Hertz). */ + f_lo = GetLO( this, "create a Mapping to upper sideband", + "astGetImagFreq", status ); + +/* Create a 1D WinMap which converts f_in to f_out. */ + if( sb == LSB ) { + f_in_a = 0.0; + f_in_b = f_lo; + f_out_a = f_lo; + f_out_b = 0.0; + } else { + f_in_a = 0.0; + f_in_b = -f_lo; + f_out_a = f_lo; + f_out_b = 0.0; + } + + fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); + +/* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ + map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); + astInvert( tmap ); + map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); + +/* Simplify */ + result = astSimplify( map2 ); + +/* Free resources */ + tmap = astAnnul( tmap ); + fmap = astAnnul( fmap ); + map1 = astAnnul( map1 ); + map2 = astAnnul( map2 ); + } + +/* Return NULL if an error has occurred. */ + if( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; + +} + +static AstMapping *ToLSBMapping( AstDSBSpecFrame *this, const char *method, int *status ){ +/* +* Name: +* ToLSBMapping + +* Purpose: +* Create a Mapping which transforms a DSBSpecFrame to the lower +* sideband. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstMapping *ToLSBMapping( AstDSBSpecFrame *this, const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame member function + +* Description: +* This function returns a pointer to a new Mapping which transforms +* positions in the supplied DSBSpecFrame to the lower sideband. This +* will be a UnitMap if the DSBSpecFrame already represents the lower +* sideband. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* method +* Pointer to a null-terminated string containing the name of the +* public invoking method. This is only used in the construction of +* error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a new Mapping. + +* Notes: +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + AstMapping *fmap; /* LSB to USB (topo freq) */ + AstMapping *map1; /* This to USB (topo freq) */ + AstMapping *map2; /* This (LSB) to This (USB) */ + AstMapping *result; /* Pointer to the returned Mapping */ + AstMapping *tmap; /* This to topocentric freq */ + double f_lo; /* Local oscillator freq (topo Hz) */ + double f_out_a; /* First LSB freq */ + double f_out_b; /* Second LSB freq */ + double f_in_a; /* First USB or LO freq */ + double f_in_b; /* Second USB or LO freq */ + int sb; /* SideBand value */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* If the DSBSpecFrame already represents the LSB, return a UnitMap.*/ + sb = astGetSideBand( this ); + if( sb == LSB ) { + result = (AstMapping *) astUnitMap( 1, "", status ); + +/* If the DSBSpecFrame represents the USB or LO offset, create a suitable + WinMap. */ + } else { + +/* Find the Mapping from the spectral system described by this SpecFrame to + topocentric frequency in Hz. */ + tmap = TopoMap( this, 1, method, status ); + +/* Calculate the local oscillator frequency (topocentric in Hertz). */ + f_lo = GetLO( this, "create a Mapping to lower sideband", + "astGetImagFreq", status ); + +/* Create a 1D WinMap which converts USB or LO to LSB. */ + if( sb == USB ) { + f_in_a = 0.0; + f_in_b = 2*f_lo; + f_out_a = 2*f_lo; + f_out_b = 0.0; + } else { + f_in_a = 0.0; + f_in_b = f_lo; + f_out_a = f_lo; + f_out_b = 0.0; + } + + fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); + +/* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ + map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); + astInvert( tmap ); + map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); + +/* Simplify */ + result = astSimplify( map2 ); + +/* Free resources */ + tmap = astAnnul( tmap ); + fmap = astAnnul( fmap ); + map1 = astAnnul( map1 ); + map2 = astAnnul( map2 ); + } + +/* Return NULL if an error has occurred. */ + if( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; + +} + +static AstMapping *TopoMap( AstDSBSpecFrame *this, int forward, + const char *method, int *status ){ +/* +* Name: +* TopoMap + +* Purpose: +* Create a Mapping which transforms a DSBSpecFrame to topocentric +* frequency. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstMapping *TopoMap( AstDSBSpecFrame *this, int forward, +* const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame member function + +* Description: +* This function returns a pointer to a new Mapping which transforms +* positions in the supplied DSBSpecFrame to the corresponding +* topocentric frequency values in Hz (or the inverse of this). + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* forward +* If zero, the calcuated Mapping is inverted before being returned. +* method +* Pointer to a null-terminated string containing the name of the +* public invoking method. This is only used in the construction of +* error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a new Mapping. + +* Notes: +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + AstMapping *result; /* The returned Mapping */ + AstFrameSet *fs; /* FrameSet connecting tf1 and tf2 */ + AstSpecFrame *tf1; /* SpecFrame corresponding to this DSBSpecFrame */ + AstSpecFrame *tf2; /* Topocentric frequency SpecFrame */ + int template_axis; /* The axis to overlay */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* Make a SpecFrame and then overlay the SpecFrame attributes of this + DSBSpecFrame onto the new SpecFrame. This means it inherits the current + values of things like ObsLon and ObsLat. */ + tf1 = astSpecFrame( "", status ); + template_axis = 0; + (*parent_overlay)( (AstFrame *) this, &template_axis, (AstFrame *) tf1, status ); + +/* Copy this new SpecFrame and set its attributes to describe topocentric + frequency in Hz. Ensure that alignment occurs in the topocentric Frame. */ + astSetAlignStdOfRest( tf1, AST__TPSOR); + tf2 = astCopy( tf1 ); + astSetSystem( tf2, AST__FREQ ); + astSetStdOfRest( tf2, AST__TPSOR ); + astSetUnit( tf2, 0, "Hz" ); + +/* Find the Mapping from the spectral system described by this SpecFrame to + topocentric frequency in Hz. */ + fs = astConvert( tf1, tf2, "" ); + if ( astOK ) { + if( !fs ) { + astError( AST__INTER, "%s(%s): Cannot convert DSBCentre " + "value from the supplied system to topocentric frequency " + "(internal AST programming error).", status, method, + astGetClass( this ) ); + } else { + result = astGetMapping( fs, AST__BASE, AST__CURRENT ); + if( !forward ) astInvert( result ); + } + fs = astAnnul( fs ); + } + +/* Free resources */ + tf1 = astAnnul( tf1 ); + tf2 = astAnnul( tf2 ); + +/* Annul the result if an error has occurred. */ + if( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; + +} + +static AstMapping *ToUSBMapping( AstDSBSpecFrame *this, const char *method, int *status ){ +/* +* Name: +* ToUSBMapping + +* Purpose: +* Create a Mapping which transforms a DSBSpecFrame to the upper +* sideband. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstMapping *ToUSBMapping( AstDSBSpecFrame *this, const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame member function + +* Description: +* This function returns a pointer to a new Mapping which transforms +* positions in the supplied DSBSpecFrame to the upper sideband. This +* will be a UnitMap if the DSBSpecFrame already represents the upper +* sideband. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* method +* Pointer to a null-terminated string containing the name of the +* public invoking method. This is only used in the construction of +* error messages. +* status +* Pointer to the inherited status variable. + +* Returned Value: +* Pointer to a new Mapping. + +* Notes: +* - A NULL pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*/ + +/* Local Variables: */ + AstMapping *fmap; /* LSB to USB (topo freq) */ + AstMapping *map1; /* This to USB (topo freq) */ + AstMapping *map2; /* This (LSB) to This (USB) */ + AstMapping *result; /* Pointer to the returned Mapping */ + AstMapping *tmap; /* This to topocentric freq */ + double f_lo; /* Local oscillator freq (topo Hz) */ + double f_in_a; /* First LSB or LO freq */ + double f_in_b; /* Second LSB or LO freq */ + double f_out_a; /* First USB freq */ + double f_out_b; /* Second USB freq */ + int sb; /* SideBand value */ + +/* Initialise. */ + result = NULL; + +/* Check the global error status. */ + if ( !astOK ) return result; + +/* If the DSBSpecFrame already represents the USB, return a UnitMap.*/ + sb = astGetSideBand( this ); + if( sb == USB ) { + result = (AstMapping *) astUnitMap( 1, "", status ); + +/* If the DSBSpecFrame represents the LSB, or LO offset, create a suitable + WinMap. */ + } else { + +/* Find the Mapping from the spectral system described by this SpecFrame to + topocentric frequency in Hz. */ + tmap = TopoMap( this, 1, method, status ); + +/* Calculate the local oscillator frequency (topocentric in Hertz). */ + f_lo = GetLO( this, "create a Mapping to upper sideband", + "astGetImagFreq", status ); + +/* Create a 1D WinMap which converts f_in to f_out. */ + if( sb == LSB ) { + f_in_a = 0.0; + f_in_b = 2*f_lo; + f_out_a = 2*f_lo; + f_out_b = 0.0; + } else { + f_in_a = 0.0; + f_in_b = -f_lo; + f_out_a = f_lo; + f_out_b = 0.0; + } + + fmap = (AstMapping *) astWinMap( 1, &f_in_a, &f_in_b, &f_out_a, &f_out_b, "", status ); + +/* Construct the Mapping: input to f_in, f_in to f_out, f_out to input */ + map1 = (AstMapping *) astCmpMap( tmap, fmap, 1, "", status ); + astInvert( tmap ); + map2 = (AstMapping *) astCmpMap( map1, tmap, 1, "", status ); + +/* Simplify */ + result = astSimplify( map2 ); + +/* Free resources */ + tmap = astAnnul( tmap ); + fmap = astAnnul( fmap ); + map1 = astAnnul( map1 ); + map2 = astAnnul( map2 ); + } + +/* Return NULL if an error has occurred. */ + if( !astOK ) result = astAnnul( result ); + +/* Return the result. */ + return result; + +} + +static void VerifyAttrs( AstDSBSpecFrame *this, const char *purp, + const char *attrs, const char *method, int *status ) { +/* +* Name: +* VerifyAttrs + +* Purpose: +* Verify that usable attribute values are available. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* void VerifyAttrs( AstDSBSpecFrame *this, const char *purp, +* const char *attrs, const char *method, int *status ) + +* Class Membership: +* DSBSpecFrame member function + +* Description: +* This function tests each attribute listed in "attrs". It returns +* without action if 1) an explicit value has been set for each attribute +* or 2) the UseDefs attribute of the supplied DSBSpecFrame is non-zero. +* +* If UseDefs is zero (indicating that default values should not be +* used for attributes), and any of the named attributes does not have +* an explicitly set value, then an error is reported. + +* Parameters: +* this +* Pointer to the DSBSpecFrame. +* purp +* Pointer to a text string containing a message which will be +* included in any error report. This shouldindicate the purpose +* for which the attribute value is required. +* attrs +* A string holding a space separated list of attribute names. +* method +* A string holding the name of the calling method for use in error +* messages. +* status +* Pointer to the inherited status variable. + +*/ + +/* Local Variables: */ + const char *a; + const char *desc; + const char *p; + int len; + int set; + int state; + +/* Check inherited status */ + if( !astOK ) return; + +/* If the DSBSpecFrame has a non-zero value for its UseDefs attribute, then + all attributes are assumed to have usable values, since the defaults + will be used if no explicit value has been set. So we only need to do + any checks if UseDefs is zero. */ + if( !astGetUseDefs( this ) ) { + +/* Initialise variables to avoid compiler warnings. */ + a = NULL; + desc = NULL; + len = 0; + set = 0; + +/* Loop round the "attrs" string identifying the start and length of each + non-blank word in the string. */ + state = 0; + p = attrs; + while( 1 ) { + if( state == 0 ) { + if( !isspace( *p ) ) { + a = p; + len = 1; + state = 1; + } + } else { + if( isspace( *p ) || !*p ) { + +/* The end of a word has just been reached. Compare it to each known + attribute value. Get a flag indicating if the attribute has a set + value, and a string describing the attribute.*/ + if( len > 0 ) { + + if( !strncmp( "DSBCentre", a, len ) ) { + set = astTestDSBCentre( this ); + desc = "central position of interest"; + + } else if( !strncmp( "IF", a, len ) ) { + set = astTestIF( this ); + desc = "intermediate frequency"; + + } else { + astError( AST__INTER, "VerifyAttrs(DSBSpecFrame): " + "Unknown attribute name \"%.*s\" supplied (AST " + "internal programming error).", status, len, a ); + } + +/* If the attribute does not have a set value, report an error. */ + if( !set && astOK ) { + astError( AST__NOVAL, "%s(%s): Cannot %s.", status, method, + astGetClass( this ), purp ); + astError( AST__NOVAL, "No value has been set for " + "the AST \"%.*s\" attribute (%s).", status, len, a, + desc ); + } + +/* Continue the word search algorithm. */ + } + len = 0; + state = 0; + } else { + len++; + } + } + if( !*(p++) ) break; + } + } +} + + +/* Functions which access class attributes. */ +/* ---------------------------------------- */ +/* Implement member functions to access the attributes associated with + this class using the macros defined for this purpose in the + "object.h" file. For a description of each attribute, see the class + interface (in the associated .h file). */ + +/* +*att++ +* Name: +* ImagFreq + +* Purpose: +* The image sideband equivalent of the rest frequency. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point, read-only. + +* Description: +* This is a read-only attribute giving the frequency which +* corresponds to the rest frequency but is in the opposite sideband. + +* The value is calculated by first transforming the rest frequency +* (given by the RestFreq attribute) from the standard of rest of the +* source (given by the SourceVel and SourceVRF attributes) to the +* standard of rest of the observer (i.e. the topocentric standard of +* rest). The resulting topocentric frequency is assumed to be in the +* same sideband as the value given for the DSBCentre attribute (the +* "observed" sideband), and is transformed to the other sideband (the +* "image" sideband). The new frequency is converted back to the standard +* of rest of the source, and the resulting value is returned as the +* attribute value, in units of GHz. + +* Applicability: +* DSBSpecFrame +* All DSBSpecFrames have this attribute. + +*att-- +*/ + + +/* +*att++ +* Name: +* DSBCentre + +* Purpose: +* The central position of interest in a dual sideband spectrum. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute specifies the central position of interest in a dual +* sideband spectrum. Its sole use is to determine the local oscillator +* frequency (the frequency which marks the boundary between the lower +* and upper sidebands). See the description of the IF (intermediate +* frequency) attribute for details of how the local oscillator frequency +* is calculated. The sideband containing this central position is +* referred to as the "observed" sideband, and the other sideband as +* the "image" sideband. +* +* The value is accessed as a position in the spectral system +* represented by the SpecFrame attributes inherited by this class, but +* is stored internally as topocentric frequency. Thus, if the System +* attribute of the DSBSpecFrame is set to "VRAD", the Unit attribute +* set to "m/s" and the StdOfRest attribute set to "LSRK", then values +* for the DSBCentre attribute should be supplied as radio velocity in +* units of "m/s" relative to the kinematic LSR (alternative units may +* be used by appending a suitable units string to the end of the value). +* This value is then converted to topocentric frequency and stored. If +* (say) the Unit attribute is subsequently changed to "km/s" before +* retrieving the current value of the DSBCentre attribute, the stored +* topocentric frequency will be converted back to LSRK radio velocity, +* this time in units of "km/s", before being returned. +* +* The default value for this attribute is 30 GHz. + +* Applicability: +* DSBSpecFrame +* All DSBSpecFrames have this attribute. + +* Note: +* - The attributes which define the transformation to or from topocentric +* frequency should be assigned their correct values before accessing +* this attribute. These potentially include System, Unit, StdOfRest, +* ObsLon, ObsLat, ObsAlt, Epoch, RefRA, RefDec and RestFreq. + +*att-- +*/ +/* The central frequency (topocentric frequency in Hz). */ +astMAKE_CLEAR(DSBSpecFrame,DSBCentre,dsbcentre,AST__BAD) +astMAKE_GET(DSBSpecFrame,DSBCentre,double,3.0E10,((this->dsbcentre!=AST__BAD)?this->dsbcentre:3.0E10)) +astMAKE_SET(DSBSpecFrame,DSBCentre,double,dsbcentre,value) +astMAKE_TEST(DSBSpecFrame,DSBCentre,( this->dsbcentre != AST__BAD )) + + +/* +*att++ +* Name: +* IF + +* Purpose: +* The intermediate frequency in a dual sideband spectrum. + +* Type: +* Public attribute. + +* Synopsis: +* Floating point. + +* Description: +* This attribute specifies the (topocentric) intermediate frequency in +* a dual sideband spectrum. Its sole use is to determine the local +* oscillator (LO) frequency (the frequency which marks the boundary +* between the lower and upper sidebands). The LO frequency is +* equal to the sum of the centre frequency and the intermediate +* frequency. Here, the "centre frequency" is the topocentric +* frequency in Hz corresponding to the current value of the DSBCentre +* attribute. The value of the IF attribute may be positive or +* negative: a positive value results in the LO frequency being above +* the central frequency, whilst a negative IF value results in the LO +* frequency being below the central frequency. The sign of the IF +* attribute value determines the default value for the SideBand +* attribute. +* +* When setting a new value for this attribute, the units in which the +* frequency value is supplied may be indicated by appending a suitable +* string to the end of the formatted value. If the units are not +* specified, then the supplied value is assumed to be in units of GHz. +* For instance, the following strings all result in an IF of 4 GHz being +* used: "4.0", "4.0 GHz", "4.0E9 Hz", etc. +* +* When getting the value of this attribute, the returned value is +* always in units of GHz. The default value for this attribute is 4 GHz. + +* Applicability: +* DSBSpecFrame +* All DSBSpecFrames have this attribute. + +*att-- +*/ +/* The intermediate frequency (topocentric in Hz). */ +astMAKE_CLEAR(DSBSpecFrame,IF,ifr,AST__BAD) +astMAKE_GET(DSBSpecFrame,IF,double,4.0E9,((this->ifr!=AST__BAD)?this->ifr:4.0E9)) +astMAKE_SET(DSBSpecFrame,IF,double,ifr,value) +astMAKE_TEST(DSBSpecFrame,IF,( this->ifr != AST__BAD )) + +/* +*att++ +* Name: +* SideBand + +* Purpose: +* Indicates which sideband a dual sideband spectrum represents. + +* Type: +* Public attribute. + +* Synopsis: +* String. + +* Description: +* This attribute indicates whether the DSBSpecFrame currently +* represents its lower or upper sideband, or an offset from the local +* oscillator frequency. When querying the current value, the returned +* string is always one of "usb" (for upper sideband), "lsb" (for lower +* sideband), or "lo" (for offset from the local oscillator frequency). +* When setting a new value, any of the strings "lsb", "usb", "observed", +* "image" or "lo" may be supplied (case insensitive). The "observed" +* sideband is which ever sideband (upper or lower) contains the central +* spectral position given by attribute DSBCentre, and the "image" +* sideband is the other sideband. It is the sign of the IF attribute +* which determines if the observed sideband is the upper or lower +* sideband. The default value for SideBand is the observed sideband. + +* Applicability: +* DSBSpecFrame +* All DSBSpecFrames have this attribute. + +*att-- +*/ +/* Protected access to the SideBand attribute uses BADSB to indicate + "unset". Other negative values mean "LSB", zero means "LO" and + positive values mean "USB". */ +astMAKE_CLEAR(DSBSpecFrame,SideBand,sideband,BADSB) +astMAKE_SET(DSBSpecFrame,SideBand,int,sideband,((value<0)?LSB:((value==0)?LO:USB))) +astMAKE_TEST(DSBSpecFrame,SideBand,( this->sideband != BADSB )) +astMAKE_GET(DSBSpecFrame,SideBand,int,USB,(this->sideband == BADSB ? ((astGetIF( this )>0)?LSB:USB):this->sideband)) + +/* +*att++ +* Name: +* AlignSideBand + +* Purpose: +* Should the SideBand attribute be taken into account when aligning +* this DSBSpecFrame with another DSBSpecFrame? + +* Type: +* Public attribute. + +* Synopsis: +* Integer (boolean). + +* Description: +* This attribute controls how a DSBSpecFrame behaves when an attempt +* is made to align it with another DSBSpecFrame using +c astFindFrame or astConvert. +f AST_FINDFRAME or AST_CONVERT. +* If both DSBSpecFrames have a non-zero value for AlignSideBand, the +* value of the SideBand attribute in each DSBSpecFrame is used so that +* alignment occurs between sidebands. That is, if one DSBSpecFrame +* represents USB and the other represents LSB then +c astFindFrame and astConvert +f AST_FINDFRAME and AST_CONVERT +* will recognise that the DSBSpecFrames represent different sidebands +* and will take this into account when constructing the Mapping that +* maps positions in one DSBSpecFrame into the other. If AlignSideBand +* in either DSBSpecFrame is set to zero, then the values of the SideBand +* attributes are ignored. In the above example, this would result in a +* frequency in the first DSBSpecFrame being mapped onto the same +* frequency in the second DSBSpecFrame, even though those frequencies +* refer to different sidebands. In other words, if either AlignSideBand +* attribute is zero, then the two DSBSpecFrames aligns like basic +* SpecFrames. The default value for AlignSideBand is zero. +* +c When astFindFrame or astConvert +f When AST_FINDFRAME or AST_CONVERT +* is used on two DSBSpecFrames (potentially describing different spectral +* coordinate systems and/or sidebands), it returns a Mapping which can be +* used to transform a position in one DSBSpecFrame into the corresponding +* position in the other. The Mapping is made up of the following steps in +* the indicated order: +* +* - If both DSBSpecFrames have a value of 1 for the AlignSideBand +* attribute, map values from the target's current sideband (given by its +* SideBand attribute) to the observed sideband (whether USB or LSB). If +* the target already represents the observed sideband, this step will +* leave the values unchanged. If either of the two DSBSpecFrames have a +* value of zero for its AlignSideBand attribute, then this step is omitted. +* +* - Map the values from the spectral system of the target to the spectral +* system of the template. This Mapping takes into account all the +* inherited SpecFrame attributes such as System, StdOfRest, Unit, etc. +* +* - If both DSBSpecFrames have a value of 1 for the AlignSideBand +* attribute, map values from the result's observed sideband to the +* result's current sideband (given by its SideBand attribute). If the +* result already represents the observed sideband, this step will leave +* the values unchanged. If either of the two DSBSpecFrames have a value +* of zero for its AlignSideBand attribute, then this step is omitted. + +* Applicability: +* DSBSpecFrame +* All DSBSpecFrames have this attribute. + +*att-- +*/ +/* The AlignSideBand value has a value of -1 when not set yielding a + default of 0. */ +astMAKE_TEST(DSBSpecFrame,AlignSideBand,( this->alignsideband != -1 )) +astMAKE_CLEAR(DSBSpecFrame,AlignSideBand,alignsideband,-1) +astMAKE_GET(DSBSpecFrame,AlignSideBand,int,-1,((this->alignsideband==-1)?0:this->alignsideband) ) +astMAKE_SET(DSBSpecFrame,AlignSideBand,int,alignsideband,(value?1:0)) + +/* Copy constructor. */ +/* ----------------- */ +/* None needed */ + +/* Destructor. */ +/* ----------- */ +/* None needed */ + +/* Dump function. */ +/* -------------- */ +static void Dump( AstObject *this_object, AstChannel *channel, int *status ) { +/* +* Name: +* Dump + +* Purpose: +* Dump function for DSBSpecFrame objects. + +* Type: +* Private function. + +* Synopsis: +* void Dump( AstObject *this, AstChannel *channel, int *status ) + +* Description: +* This function implements the Dump function which writes out data +* for the DSBSpecFrame class to an output Channel. + +* Parameters: +* this +* Pointer to the DSBSpecFrame whose data are being written. +* channel +* Pointer to the Channel to which the data are being written. +* status +* Pointer to the inherited status variable. +*/ + +/* Local Variables: */ + AstDSBSpecFrame *this; /* Pointer to the DSBSpecFrame structure */ + const char *cval; /* Attribute value */ + const char *comm; /* Attribute comment */ + double dval; /* Attribute value */ + int ival; /* Attribute value */ + int set; /* Is attribute set? */ + +/* Check the global error status. */ + if ( !astOK ) return; + +/* Obtain a pointer to the DSBSpecFrame structure. */ + this = (AstDSBSpecFrame *) this_object; + +/* In the case of attributes, we first use the appropriate (private) + Test... member function to see if they are set. If so, we then use + the (private) Get... function to obtain the value to be written + out. + + For attributes which are not set, we use the astGet... method to + obtain the value instead. This will supply a default value + (possibly provided by a derived class which over-rides this method) + which is more useful to a human reader as it corresponds to the + actual default attribute value. Since "set" will be zero, these + values are for information only and will not be read back. */ + +/* DSBCentre */ +/* --------- */ + set = TestDSBCentre( this, status ); + dval = set ? GetDSBCentre( this, status ) : astGetDSBCentre( this ); + astWriteDouble( channel, "DSBCen", set, 1, dval, "Central frequency (Hz topo)" ); + +/* IF */ +/* -- */ + set = TestIF( this, status ); + dval = set ? GetIF( this, status ) : astGetIF( this ); + astWriteDouble( channel, "IF", set, 1, dval, "Intermediate frequency (Hz)" ); + +/* SideBand */ +/* -------- */ + set = TestSideBand( this, status ); + ival = set ? GetSideBand( this, status ) : astGetSideBand( this ); + if( ival == LSB ) { + cval = "LSB"; + comm = "Represents lower sideband"; + + } else if( ival == LO ) { + cval = "LO"; + comm = "Represents offset from LO frequency"; + + } else { + cval = "USB"; + comm = "Represents upper sideband"; + } + astWriteString( channel, "SideBn", set, 1, cval, comm ); + +/* AlignSideBand */ +/* ------------- */ + set = TestAlignSideBand( this, status ); + ival = set ? GetAlignSideBand( this, status ) : astGetAlignSideBand( this ); + astWriteInt( channel, "AlSdBn", set, 1, ival, "Align sidebands?" ); +} + +/* Standard class functions. */ +/* ========================= */ +/* Implement the astIsADSBSpecFrame and astCheckDSBSpecFrame functions using the macros + defined for this purpose in the "object.h" header file. */ +astMAKE_ISA(DSBSpecFrame,SpecFrame) +astMAKE_CHECK(DSBSpecFrame) + +AstDSBSpecFrame *astDSBSpecFrame_( const char *options, int *status, ...) { +/* +*++ +* Name: +c astDSBSpecFrame +f AST_DSBSPECFRAME + +* Purpose: +* Create a DSBSpecFrame. + +* Type: +* Public function. + +* Synopsis: +c #include "dsbspecframe.h" +c AstDSBSpecFrame *astDSBSpecFrame( const char *options, ... ) +f RESULT = AST_DSBSPECFRAME( OPTIONS, STATUS ) + +* Class Membership: +* DSBSpecFrame constructor. + +* Description: +* This function creates a new DSBSpecFrame and optionally initialises its +* attributes. +* +* A DSBSpecFrame is a specialised form of SpecFrame which represents +* positions in a spectrum obtained using a dual sideband instrument. +* Such an instrument produces a spectrum in which each point contains +* contributions from two distinctly different frequencies, one from +* the "lower side band" (LSB) and one from the "upper side band" (USB). +* Corresponding LSB and USB frequencies are connected by the fact +* that they are an equal distance on either side of a fixed central +* frequency known as the "Local Oscillator" (LO) frequency. +* +* When quoting a position within such a spectrum, it is necessary to +* indicate whether the quoted position is the USB position or the +* corresponding LSB position. The SideBand attribute provides this +* indication. Another option that the SideBand attribute provides is +* to represent a spectral position by its topocentric offset from the +* LO frequency. +* +* In practice, the LO frequency is specified by giving the distance +* from the LO frequency to some "central" spectral position. Typically +* this central position is that of some interesting spectral feature. +* The distance from this central position to the LO frequency is known +* as the "intermediate frequency" (IF). The value supplied for IF can +* be a signed value in order to indicate whether the LO frequency is +* above or below the central position. + +* Parameters: +c options +f OPTIONS = CHARACTER * ( * ) (Given) +c Pointer to a null-terminated string containing an optional +c comma-separated list of attribute assignments to be used for +c initialising the new DSBSpecFrame. The syntax used is identical to +c that for the astSet function and may include "printf" format +c specifiers identified by "%" symbols in the normal way. +f A character string containing an optional comma-separated +f list of attribute assignments to be used for initialising the +f new DSBSpecFrame. The syntax used is identical to that for the +f AST_SET routine. +c ... +c If the "options" string contains "%" format specifiers, then +c an optional list of additional arguments may follow it in +c order to supply values to be substituted for these +c specifiers. The rules for supplying these are identical to +c those for the astSet function (and for the C "printf" +c function). +f STATUS = INTEGER (Given and Returned) +f The global status. + +* Returned Value: +c astDSBSpecFrame() +f AST_DSBSPECFRAME = INTEGER +* A pointer to the new DSBSpecFrame. + +* Notes: +* - A null Object pointer (AST__NULL) will be returned if this +c function is invoked with the AST error status set, or if it +f function is invoked with STATUS set to an error value, or if it +* should fail for any reason. +*-- +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ + va_list args; /* Variable argument list */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Initialise the DSBSpecFrame, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitDSBSpecFrame( NULL, sizeof( AstDSBSpecFrame ), !class_init, &class_vtab, + "DSBSpecFrame" ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the options string + to the astVSet method to initialise the new DSBSpecFrame's attributes. */ + va_start( args, status ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return a pointer to the new DSBSpecFrame. */ + return new; +} + +AstDSBSpecFrame *astDSBSpecFrameId_( const char *options, ... ) { +/* +* Name: +* astDSBSpecFrameId_ + +* Purpose: +* Create a DSBSpecFrame. + +* Type: +* Private function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstDSBSpecFrame *astDSBSpecFrameId_( const char *options, ... ) + +* Class Membership: +* DSBSpecFrame constructor. + +* Description: +* This function implements the external (public) interface to the +* astDSBSpecFrame constructor function. It returns an ID value (instead +* of a true C pointer) to external users, and must be provided +* because astDSBSpecFrame_ has a variable argument list which cannot be +* encapsulated in a macro (where this conversion would otherwise +* occur). +* +* The variable argument list also prevents this function from +* invoking astDSBSpecFrame_ directly, so it must be a re-implementation +* of it in all respects, except for the final conversion of the +* result to an ID value. + +* Parameters: +* As for astDSBSpecFrame_. + +* Returned Value: +* The ID value associated with the new DSBSpecFrame. +*/ + +/* Local Variables: */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ + AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ + va_list args; /* Variable argument list */ + + int *status; /* Pointer to inherited status value */ + +/* Get a pointer to the inherited status value. */ + status = astGetStatusPtr; + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(NULL); + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* Initialise the DSBSpecFrame, allocating memory and initialising the + virtual function table as well if necessary. */ + new = astInitDSBSpecFrame( NULL, sizeof( AstDSBSpecFrame ), !class_init, &class_vtab, + "DSBSpecFrame" ); + +/* If successful, note that the virtual function table has been + initialised. */ + if ( astOK ) { + class_init = 1; + +/* Obtain the variable argument list and pass it along with the options string + to the astVSet method to initialise the new DSBSpecFrame's attributes. */ + va_start( args, options ); + astVSet( new, options, NULL, args ); + va_end( args ); + +/* If an error occurred, clean up by deleting the new object. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return an ID value for the new DSBSpecFrame. */ + return astMakeId( new ); +} + +AstDSBSpecFrame *astInitDSBSpecFrame_( void *mem, size_t size, int init, + AstDSBSpecFrameVtab *vtab, const char *name, int *status ) { +/* +*+ +* Name: +* astInitDSBSpecFrame + +* Purpose: +* Initialise a DSBSpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstDSBSpecFrame *astInitDSBSpecFrame( void *mem, size_t size, int init, +* AstDSBSpecFrameVtab *vtab, const char *name ) + +* Class Membership: +* DSBSpecFrame initialiser. + +* Description: +* This function is provided for use by class implementations to initialise +* a new DSBSpecFrame object. It allocates memory (if necessary) to accommodate +* the DSBSpecFrame plus any additional data associated with the derived class. +* It then initialises a DSBSpecFrame structure at the start of this memory. If +* the "init" flag is set, it also initialises the contents of a virtual +* function table for a DSBSpecFrame at the start of the memory passed via the +* "vtab" parameter. + +* Parameters: +* mem +* A pointer to the memory in which the DSBSpecFrame is to be initialised. +* This must be of sufficient size to accommodate the DSBSpecFrame data +* (sizeof(DSBSpecFrame)) plus any data used by the derived class. If a value +* of NULL is given, this function will allocate the memory itself using +* the "size" parameter to determine its size. +* size +* The amount of memory used by the DSBSpecFrame (plus derived class data). +* This will be used to allocate memory if a value of NULL is given for +* the "mem" parameter. This value is also stored in the DSBSpecFrame +* structure, so a valid value must be supplied even if not required for +* allocating memory. +* init +* A logical flag indicating if the DSBSpecFrame's virtual function table is +* to be initialised. If this value is non-zero, the virtual function +* table will be initialised by this function. +* vtab +* Pointer to the start of the virtual function table to be associated +* with the new DSBSpecFrame. +* name +* Pointer to a constant null-terminated character string which contains +* the name of the class to which the new object belongs (it is this +* pointer value that will subsequently be returned by the astGetClass +* method). + +* Returned Value: +* A pointer to the new DSBSpecFrame. + +* Notes: +* - A null pointer will be returned if this function is invoked with the +* global error status set, or if it should fail for any reason. +*- +*/ + +/* Local Variables: */ + AstDSBSpecFrame *new; /* Pointer to new DSBSpecFrame */ + +/* Check the global status. */ + if ( !astOK ) return NULL; + +/* If necessary, initialise the virtual function table. */ + if ( init ) astInitDSBSpecFrameVtab( vtab, name ); + +/* Initialise. */ + new = NULL; + +/* Initialise a SpecFrame structure (the parent class) as the first component + within the DSBSpecFrame structure, allocating memory if necessary. Specify that + the SpecFrame should be defined in both the forward and inverse directions. */ + new = (AstDSBSpecFrame *) astInitSpecFrame( mem, size, 0, + (AstSpecFrameVtab *) vtab, name ); + if ( astOK ) { + +/* Initialise the DSBSpecFrame data. */ +/* --------------------------------- */ + new->dsbcentre = AST__BAD; + new->ifr = AST__BAD; + new->sideband = BADSB; + new->alignsideband = -1; + +/* If an error occurred, clean up by deleting the new DSBSpecFrame. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return a pointer to the new DSBSpecFrame. */ + return new; +} + +AstDSBSpecFrame *astLoadDSBSpecFrame_( void *mem, size_t size, + AstDSBSpecFrameVtab *vtab, const char *name, + AstChannel *channel, int *status ) { +/* +*+ +* Name: +* astLoadDSBSpecFrame + +* Purpose: +* Load a DSBSpecFrame. + +* Type: +* Protected function. + +* Synopsis: +* #include "dsbspecframe.h" +* AstDSBSpecFrame *astLoadDSBSpecFrame( void *mem, size_t size, +* AstDSBSpecFrameVtab *vtab, const char *name, +* AstChannel *channel ) + +* Class Membership: +* DSBSpecFrame loader. + +* Description: +* This function is provided to load a new DSBSpecFrame using data read +* from a Channel. It first loads the data used by the parent class +* (which allocates memory if necessary) and then initialises a +* DSBSpecFrame structure in this memory, using data read from the input +* Channel. +* +* If the "init" flag is set, it also initialises the contents of a +* virtual function table for a DSBSpecFrame at the start of the memory +* passed via the "vtab" parameter. + + +* Parameters: +* mem +* A pointer to the memory into which the DSBSpecFrame is to be +* loaded. This must be of sufficient size to accommodate the +* DSBSpecFrame data (sizeof(DSBSpecFrame)) plus any data used by derived +* classes. If a value of NULL is given, this function will +* allocate the memory itself using the "size" parameter to +* determine its size. +* size +* The amount of memory used by the DSBSpecFrame (plus derived class +* data). This will be used to allocate memory if a value of +* NULL is given for the "mem" parameter. This value is also +* stored in the DSBSpecFrame structure, so a valid value must be +* supplied even if not required for allocating memory. +* +* If the "vtab" parameter is NULL, the "size" value is ignored +* and sizeof(AstDSBSpecFrame) is used instead. +* vtab +* Pointer to the start of the virtual function table to be +* associated with the new DSBSpecFrame. If this is NULL, a pointer +* to the (static) virtual function table for the DSBSpecFrame class +* is used instead. +* name +* Pointer to a constant null-terminated character string which +* contains the name of the class to which the new object +* belongs (it is this pointer value that will subsequently be +* returned by the astGetClass method). +* +* If the "vtab" parameter is NULL, the "name" value is ignored +* and a pointer to the string "DSBSpecFrame" is used instead. + +* Returned Value: +* A pointer to the new DSBSpecFrame. + +* Notes: +* - A null pointer will be returned if this function is invoked +* with the global error status set, or if it should fail for any +* reason. +*- +*/ + +/* Local Constants. */ + astDECLARE_GLOBALS /* Pointer to thread-specific global data */ +#define KEY_LEN 50 /* Maximum length of a keyword */ + +/* Local Variables: */ + AstDSBSpecFrame *new; /* Pointer to the new DSBSpecFrame */ + char *text; /* Pointer to string value */ + +/* Get a pointer to the thread specific global data structure. */ + astGET_GLOBALS(channel); + +/* Initialise. */ + new = NULL; + +/* Check the global error status. */ + if ( !astOK ) return new; + +/* If a NULL virtual function table has been supplied, then this is + the first loader to be invoked for this DSBSpecFrame. In this case the + DSBSpecFrame belongs to this class, so supply appropriate values to be + passed to the parent class loader (and its parent, etc.). */ + if ( !vtab ) { + size = sizeof( AstDSBSpecFrame ); + vtab = &class_vtab; + name = "DSBSpecFrame"; + +/* If required, initialise the virtual function table for this class. */ + if ( !class_init ) { + astInitDSBSpecFrameVtab( vtab, name ); + class_init = 1; + } + } + +/* Invoke the parent class loader to load data for all the ancestral + classes of the current one, returning a pointer to the resulting + partly-built DSBSpecFrame. */ + new = astLoadSpecFrame( mem, size, (AstSpecFrameVtab *) vtab, name, + channel ); + if ( astOK ) { + +/* Read input data. */ +/* ================ */ +/* Request the input Channel to read all the input data appropriate to + this class into the internal "values list". */ + astReadClassData( channel, "DSBSpecFrame" ); + +/* Now read each individual data item from this list and use it to + initialise the appropriate instance variable(s) for this class. */ + +/* In the case of attributes, we first read the "raw" input value, + supplying the "unset" value as the default. If a "set" value is + obtained, we then use the appropriate (private) Set... member + function to validate and set the value properly. */ + +/* DSBCentre */ +/* --------- */ + new->dsbcentre = astReadDouble( channel, "dsbcen", AST__BAD ); + if ( TestDSBCentre( new, status ) ) SetDSBCentre( new, new->dsbcentre, status ); + +/* IF */ +/* -- */ + new->ifr = astReadDouble( channel, "if", AST__BAD ); + if ( TestIF( new, status ) ) SetIF( new, new->ifr, status ); + +/* SideBand */ +/* -------- */ + text = astReadString( channel, "sidebn", " " ); + if( astOK ) { + if( !strcmp( text, " " ) ) { + new->sideband = BADSB; + } else if( !strcmp( text, "USB" ) ) { + new->sideband = USB; + } else if( !strcmp( text, "LSB" ) ) { + new->sideband = LSB; + } else if( !strcmp( text, "LO" ) ) { + new->sideband = LO; + } else { + astError( AST__ATTIN, "astRead(%s): Invalid SideBand description " + "\"%s\".", status, astGetClass( channel ), text ); + } + if ( TestSideBand( new, status ) ) SetSideBand( new, new->sideband, status ); + text = astFree( text ); + } + +/* AlignSideBand */ +/* ------------- */ + new->alignsideband = astReadInt( channel, "alsdbn", -1 ); + if( TestAlignSideBand( new, status ) ) SetAlignSideBand( new, new->alignsideband, status ); + +/* If an error occurred, clean up by deleting the new DSBSpecFrame. */ + if ( !astOK ) new = astDelete( new ); + } + +/* Return the new DSBSpecFrame pointer. */ + return new; +} + +/* Virtual function interfaces. */ +/* ============================ */ +/* These provide the external interface to the virtual functions defined by + this class. Each simply checks the global error status and then locates and + executes the appropriate member function, using the function pointer stored + in the object's virtual function table (this pointer is located using the + astMEMBER macro defined in "object.h"). + + Note that the member function may not be the one defined here, as it may + have been over-ridden by a derived class. However, it should still have the + same interface. */ + +double astGetImagFreq_( AstDSBSpecFrame *this, int *status ) { + if ( !astOK ) return AST__BAD; + return (**astMEMBER(this,DSBSpecFrame,GetImagFreq))( this, status ); +} + + + + + + |