Changeset 320
- Timestamp:
- Mar 31, 2004, 11:27:48 AM (22 years ago)
- File:
-
- 1 edited
-
trunk/doc/pslib/psLibSDRS.tex (modified) (107 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/doc/pslib/psLibSDRS.tex
r314 r320 1 %%% $Id: psLibSDRS.tex,v 1.1 4 2004-03-30 05:40:01 price Exp $1 %%% $Id: psLibSDRS.tex,v 1.15 2004-03-31 21:27:48 eugene Exp $ 2 2 \documentclass[panstarrs]{panstarrs} 3 3 %\documentclass[panstarrs]{panstarrs} 4 4 5 5 % basic document variables 6 \title{Pan-STARRS IPP Library Design} 6 \title{Pan-STARRS IPP Library\\ 7 Supplementary Design Requirements} 7 8 \author{Paul Price, Eugene Magnier, Robert Lupton} 8 9 \shorttitle{PSLib Design} … … 24 25 % use \hline between each table row 25 26 \RevisionsStart 26 % version Date Description 27 \theversion & 2003 Mar 11-- & Draft \\ 27 % version Date Description 28 DR-1 & 2003 Mar 11 & Draft \\ 29 \hline 30 DR-2 & 2003 Mar 29 & Reorganized, spell-checked \\ 28 31 \RevisionsEnd 29 32 30 \pagebreak 33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 35 \DocumentsInternal 36 PSCD-430-xxx & PS-1 Design Reference Mission \\ 37 \hline 38 PSCD-430-004 & Pan-STARRS IPP C Code Conventions \\ 39 \hline 40 PSCD-430-005 & Pan-STARRS IPP SRS \\ 41 \hline 42 PSCD-430-006 & Pan-STARRS IPP ADD \\ 43 \hline 44 PSCD-430-007 & Pan-STARRS IPP PSLib SDR \\ 45 \hline 46 PSCD-430-008 & Pan-STARRS IPP Architecture SDR \\ 47 48 \DocumentsExternal 49 Posix Standard & Open Group Based Specifications Issue 6, IEEE Std 1003.1, 2003 \\ 50 \DocumentsEnd 51 31 52 \tableofcontents 32 33 53 \pagebreak 34 54 \pagenumbering{arabic} 35 55 36 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 37 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 39 40 \section{\PS{} Library (PSLib)} 41 42 PSLib is a library of basic functions required for IPP (and MOPS) 43 operations. We expect that it will be, to a large extent, the major 44 workhorse of the IPP. 45 46 PSLib will consist of a variety of data structures and associated APIs 47 to perform common functions. It will provide low-level capabilities 48 in each of the following areas: 56 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 57 58 \section{Introduction} 59 60 This document describes the Pan-STARRS Image Processing Pipeline (IPP) 61 Toolkit Library, PSLib. Any large software project such as the IPP 62 benefits from the existence of a library of basic software functions 63 which can be used throughout the project to simplify programming 64 tasks. Among the benefits are the ability to reuse code, 65 simplification of the testing process, streamlining of the code, and 66 the isolation and encapsulation of concepts which may be subject to 67 change. The component functions of such a library should represent 68 well-defined, concise operations which can be coded with only a modest 69 number of lines. PSLib is a library of basic functions required by 70 the IPP, but should include many programming concepts which may be useful 71 for other software projects, especially those which deal with 72 astronomical data handling tasks. 73 74 PSLib consists of a collection of library function calls -- the 75 Application Programming Interfaces (APIs) -- and the associated data 76 structures. The capabilities provided by PSLib are grouped into the 77 following areas: 78 % 49 79 \begin{itemize} 50 \item System utilities;51 \item Data containers;52 \item Data manipulation; and53 \item Astronomy- specific tasks.80 \item System Utilities 81 \item Basic Data Collections 82 \item Data Manipulation 83 \item Astronomy-Specific Functions. 54 84 \end{itemize} 55 56 Below we sketch out approximately 200~APIs which specify the required 57 capabilities. 58 59 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 60 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 61 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 85 This list is sorted in a hierarchical order: the later entries depend 86 on the functions and data types of the earlier entries. 87 88 The installed base of code for PSLib consists of header files, the 89 binary library code, \code{libpslib.a} and the shared-library 90 equivalent, \code{libpslib.so}. Assuming these components have been 91 installed into the library and search path, PSLib may be used within a 92 program by including the line \code{#include <pslib.h>} into the C 93 code and linking with \code{-lpslib}. 94 95 This document describes the data structures and details the functions 96 calls. The specified data structures and functions follow the naming 97 conventions detailed in the IPP Code Conventions (PSDC-430-004). In 98 particular, these coding conventions restrict the namespace used by 99 the library functions by requiring that all globally visible symbols 100 start with the two letters \code{ps}. Further namespace organization 101 is achieved by encouraging functions to be named in the form 102 psNounVerbPhrase, where Noun is the data type of principle relevance 103 and VerbPhase describes the operation applied to that data type. For 104 example, the function which copies an image (of type \code{psImage}) 105 is called \code{psImageCopy()}. 106 107 \tbd{discuss the use of external libraries (list them)} 108 109 \tbd{discussion of thread safe?} 110 111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 62 112 63 113 \section{System Utilities} … … 70 120 The \PS{} software system will need a level of memory management 71 121 placed between the operating system (\code{malloc}/\code{free}) and 72 the high level routines (e.g.\ \code{psMetaDataAlloc}). 73 74 This layer is in addition to the possibility that specific heavily 75 used data types may need their own special-purpose memory managers; 76 but as we have specified that all user-level objects be allocated via 77 \code{typeAlloc/typeFree} functions, we will easily be able to 78 implement such functionality without impacting the facilities 79 described here. 122 the high level routines (e.g.\ \code{psMetaDataAlloc}). This layer is 123 in addition to the possibility that specific heavily used data types 124 may need their own special-purpose memory managers. However, since we 125 require that all user-level objects be allocated via associated 126 \code{Alloc/Free} functions, we will easily be able to implement such 127 functionality without impacting the facilities described here. 80 128 81 129 \subsubsection{Rationale} … … 107 155 \item 108 156 While debugging complex scientific code, it is very useful to be 109 able to trace a given data structure as it passe dthrough the157 able to trace a given data structure as it passes through the 110 158 processing pipeline. 111 159 … … 115 163 \end{itemize} 116 164 117 \subsubsection{A Minimal Specification} 118 119 The previous section laid out a number of desiderata for a memory 120 management system. Rather than implement our own heap-manager at this 121 stage of the project, we propose to put in place a sufficient set of 122 data structures and APIs, but initially implement only a simple subset 123 (e.g.\ that we not implement a multi-bucket memory manager that takes 124 in 100Mb chunks from the system and performs sophisticated 125 defragmentation and garbage collection). 126 127 Subject to agreement with the IfA, some of the functions proposed 128 here may be omitted from the initial implementation; in particular 129 the routines \code{psMemCheckCorruption} and \code{psMemCheckLeaks} 130 may be hard to build efficiently in a simple implementation based 131 upon adding extra fields to allocation requests. 132 133 \paragraph{Extra information to be saved by Memory Allocation Functions} 134 135 It is required that a table of all allocated memory blocks be 136 maintained by the \PS{} memory system. 137 138 Each allocated block should preserve at least the information present 139 in the following struct definition: 165 \subsubsection{Memory Management} 166 167 In the following sections, we specify the API set, and define the 168 appropriate data structures, needed by the PSLib memory management 169 system in order to meet the requirements specified by the desiderata 170 listed above. 171 172 Within the PSLib memory management system, every allocated memory 173 block which is provided to the user is bounded by two additions memory 174 segments. The segment preceeding the user-memory contains data 175 describing the allocated block, using the \code{psMemBlock} structure. 176 The final element of this structure is a \code{void} pointer called 177 \code{magic} and is assigned a special value, \code{PS_MEM_MAGIC}. 178 The segment following the user-memory block consists of a single 179 \code{void} pointer, and is also assigned the special value of 180 \code{PS_MEM_MAGIC}. 181 182 In practice, these bounding memory blocks mean that when a user is 183 requests $N$ bytes of memory, the memory management system in fact 184 allocates \code{N + sizeof(psMemBlock) + sizeof(void)} bytes, starting 185 at a paricular address, \code{ADDR}. It then fills in the first 186 \code{sizeof(psMemBlock)} bytes with the data of the \code{psMemBlock} 187 structure, and the last \code{sizeof(void)} bytes with the 188 \code{PS_MEM_MAGIC}. It returns to the user the pointer corresponding 189 to the address \code{ADDR + sizeof(psMemBlock)}. If the memory 190 management system reallocates a block of memory, it must also allocate 191 the additional space and fill in the boundary values. If the memory 192 management system is give a specific pointer for some operation, it is 193 able to find the corresponding \code{psMemBlock} by simply subtracting 194 \code{sizeof(psMemBlock)} from the pointer address. 195 196 The purpose of the two boundary markers is to catch corruption and to 197 act as an aid in low-level debugging. In the first case, memory over- 198 and under-run errors are likely to overwrite the special values in 199 either the leading or trailing boundaries. The typical situation is 200 one where the coder mis-counts the range and either fills the data 201 just before the start of the valid memory or just after the end of the 202 valid memory. These actions will alter the boundary-post values and 203 can be detected by the memory management system. In the second case, 204 hexidecimal dumps of large blocks of memory are easier to examine if 205 the value of \code{PS_MEM_MAGIC} is chosen to catch the eye. A 206 traditional value for \code{PS_MEM_MAGIC} is \code{0xdeadbeef} which 207 is also easily recognized in a dump of the memory table. 208 209 The PSLib memory management system must maintain a private table of 210 the allocated memory blocks. The table includes a list of pointers to 211 structures of type \code{psMemBlock}, defined as follows: 212 % 140 213 \begin{verbatim} 141 214 typedef struct { 142 const void *magic0; //!< initialised to p_psMEMMAGIC143 const unsigned long id; //!< a unique ID for this allocation144 const char *file; //!< set from __FILE__ in e.g. p_psAlloc145 const int lineno; //!< set from __LINE__ in e.g. p_psAlloc146 int refCounter; //!< how many times pointer is referenced147 const void *magic; // !< initialised to p_psMEMMAGIC215 const unsigned long id; ///< a unique ID for this allocation 216 const char *file; ///< set from __FILE__ in e.g. p_psAlloc 217 const int lineno; ///< set from __LINE__ in e.g. p_psAlloc 218 int refCounter; ///< how many times pointer is referenced 219 int state; ///< current state of memory block 220 const void *magic; ///< initialised to PS_MEM_MAGIC 148 221 } psMemBlock; 149 222 \end{verbatim} 150 151 The value of \code{P_PS_MEMMAGIC} shall be \code{(void *)0xdeadbeef}% 152 \footnote{Why this choice? Tradition, and because it's easy to notice 153 in a hex dump.} 154 155 \paragraph{APIs for using Memory Allocation Functions} 156 157 The types and function prototypes for the part of the memory API 158 concerned with allocating and freeing memory are shown below. 159 160 \begin{verbatim} 161 /// Memory allocation. Underlying private function called by macro psAlloc. 162 void *p_psAlloc(size_t size, //!< Size required 163 const char *file, //!< File of call 164 int lineno //!< Line number of call 165 ); 166 167 /// Memory re-allocation. Underlying private function called by macro psRealloc. 168 void *p_psRealloc(void *ptr, //!< Pointer to re-allocate 169 size_t size, //!< Size required 170 const char *file, //!< File of call 171 int lineno //!< Line number of call 172 ); 173 174 /// Free memory. Underlying private function called by macro psFree. 175 void p_psFree(void *ptr, //!< Pointer to free 176 const char *file, //!< File of call 177 int lineno //!< Line number of call 178 ); 179 180 /// Memory allocation. psAlloc sends file and line number to p_psAlloc. 181 #define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__) 182 183 /// Memory re-allocation. psRealloc sends file and line number to p_psRealloc. 184 #define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__) 185 186 /// Free memory. psFree sends file and line number to p_psFree. 187 #define psFree(size) p_psFree(size, __FILE__, __LINE__) 188 \end{verbatim} 189 190 N.b. 223 % 224 The first element in the structure is a sequential memory block ID. 225 The memory management system must maintain an internal memory block ID 226 counter from which a new ID may be supplied to each newly allocated 227 block of memory and saved in the element \code{id}. This ID should 228 also be the key to the memory block in the memory block table. 229 230 The two entries \code{file} and \code{lineno} are set to the line 231 number and file at which the memory was originally allocated. This is 232 most easily implemented by the use of the C preprocessor macros 233 \code{__LINE__} and \code{__FILE__}. For this reason, we specify 234 below that the basic memory managment functions be implemented as 235 preprocessor macros which wrap the intrinsic C level functions. 236 237 The \code{psMemBlock} structure element \code{refCounter} is provided 238 so APIs may cleanly manage multiple references to the same block of 239 memory. As discussed below, the basic free function, \code{psFree}, 240 is specified to free the memory block only if the reference counter is 241 set to 1. See the discussion of the \code{psDlist} and \code{psHash} 242 data containers for an example of the usage. Usage of this feature is 243 strongly encouraged, but not enforced by the memory management system. 244 245 The element \code{state} defines the state of the memory block. In 246 order to trace double frees and other memory errors, the memory block 247 reference is not automatically deleted when the assocated memory is 248 deleted. Valid states are \code{PS_MEM_FREE} and \code{PS_MEM_ALLOC}. 249 250 \subsubsection{APIs for Allocation and Freeing} 251 252 PSLib provides the following APIs to create and destroy memory blocks: 253 % 254 \begin{verbatim} 255 void *psAlloc(size_t size); 256 void *psRealloc(void *ptr, size_t size); 257 void *psFree(void *ptr); 258 \end{verbatim} 259 % 260 From the user's perspective, the functions \code{psAlloc}, 261 \code{psRealloc}, and \code{psFree} have identical semantics to the 262 standard C library functions \code{malloc}, \code{realloc}, and 263 \code{free}. In fact, these functions shall be implemented as C 264 preprocessor macros which call the following private functions: 265 % 266 \begin{verbatim} 267 void *p_psAlloc(size_t size, char *file, int line); 268 void *p_psRealloc(void *ptr, size_t size, char *file, int line); 269 void p_psFree(void *ptr, char *file, int line); 270 \end{verbatim} 271 % 272 In these function calls, \code{size} is the number of bytes required 273 to be allocated, \code{ptr} is the pointer to the allocated memory 274 block, \code{file} is the file containing the calling function (set by 275 \code{__FILE__}), and \code{line} is the calling function line number 276 in the source-code file (set by \code{__LINE__}). Because the user 277 should only see the preprocessor versions (ie, \code{psAlloc}), we do 278 not distinguish between these two in the following discussion. 279 280 In order to enforce the use of the PSLib versions, the header file 281 shall take steps to ensure that code calling the functions 282 \code{malloc}, \code{calloc}, \code{realloc}, or \code{free} will not 283 compile. This may be achieved by defining preprocessor macros which 284 mask these functions with invalid statements (\eg{} \code{#define 285 malloc(S) for}). In exceptional cases, such as the memory management 286 system itself, programmers may choose to override this prohibition by 287 defining the symbol \code{PS_ALLOW_MALLOC}. Application code will 288 call \code{p_psAlloc,p_psRealloc,p_psFree} via the macros defined 289 above. 290 291 The functions \code{psAlloc} and \code{psRealloc} shall never return a 292 \code{NULL} pointer. If they are unable to provide the requested 293 memory they should attempt to obtain the desired memory by calling the 294 routine registered by \code{psMemExhaustedSetCB} (see subsubsection 295 \ref{secMemAdvanced}), and if still unsuccessful, call \code{psAbort()}. 296 297 Note that we have not specified an equivalent of the \code{calloc} 298 function. The \code{calloc} function provides two aspects which 299 \code{malloc} originally did not: aligned memory and inialization. 300 Neither of these are required: under POSIX, \code{malloc} is required 301 to be aligned. Also, for all structures it is necessary to explicity 302 define the initialization independently since a byte value of 0 is 303 usually insufficient. 304 305 \subsubsection{Callback Routines} 306 307 The PSLib memory management system uses callback functions to handle 308 certain errors and trace conditions. The callbacks are registered by 309 the programmer and called by the basic memory management functions if 310 needed. The four callbacks currently defined are called in the 311 following situations: 312 % 191 313 \begin{itemize} 192 \item 193 The functions \code{psAlloc}, \code{psRealloc}, and \code{psFree} 194 are defined, and are required to be equivalent to \code{p_psAlloc}, 195 \code{p_psRealloc}, and \code{p_psFree} with the final two arguments 196 \code{__FILE__} and \code{__LINE__}. 197 198 In the descriptions that follow, I shall not distinguish between the 199 functions with and without the \code{p_} prefix. 200 201 \item 202 Except as specified below, the functions \code{psAlloc}, 203 \code{psRealloc}, and \code{psFree} have identical semantics 204 to the standard C library functins \code{malloc}, \code{realloc}, 205 and \code{free}. 206 207 \item 208 The header file (\file{psMemory.h}) shall take steps to ensure that 209 code calling the functions \code{malloc}, \code{calloc}, 210 \code{realloc}, or \code{free} shall not compile (\eg{} 211 \code{#define malloc(S) for}) unless the symbol 212 \code{PS_ALLOC_MALLOC} is defined. 213 214 \item 215 In all cases, application code will call 216 \CODE|p_{psAlloc,psRealloc,psFree}| via the macros defined above. 217 218 \item 219 The functions \code{psAlloc} and \code{psRealloc} shall never 220 return a \code{NULL} pointer. If they are unable to provide 221 the requested memory they should attempt to obtain the desired 222 memory by calling the routine registered by \code{psMemExhaustedSetCB} (see 223 subsubsection \ref{secMemAdvanced}), and if still unsuccessful, 224 call \code{abort()}. 225 226 \item 227 The memory management routines shall maintain the field 228 \code{psMemBlock.refcntr}. It should be set to \code{1} 229 when a block is returned to the user. It is an error to 230 attempt to free a block with \code{psMemBlock.refcntr != 1} 231 (see subsubsection \ref{secMemRefcounter}). 232 233 \item 234 Where practical and efficient, the memory manager shall call the 235 routine registered using the \code{psMemProblemSetCB} (see section 236 \ref{secMemAdvanced}) whenever a corrupted block of memory is 237 discovered. For example, doubly-freed blocks can be detected by 238 checking \code{psMemBlock.refcntr}. 239 240 \item 241 There is no \code{psCalloc} function. Initialisation of data is 242 almost always more complex than setting all bytes to 0. 243 Correspondingly, the system call \code{calloc} should be disabled 244 using the pre-processor. 314 \item when insufficient memory is available (\code{psMemExhaustedCB}) 315 \item when a memory block is found to be corrupted (\code{psMemProblemCB}) 316 \item when a specified memory ID is allocated (\code{psMemAllocateCB}) 317 \item when a specified memory ID is freed (\code{psMemFreeCB}) 245 318 \end{itemize} 246 247 \paragraph{APIs for Tracing and Debugging Memory} 319 % 320 The callback functions are defined in terms of specific callback 321 types, specified below. The callbacks are set using functions with 322 names of the form \code{psCallbackSet}. In all cases, the 323 `\code{Set}' routine takes a pointer to the desired callback 324 function and returns a pointer to the one that was previously 325 installed. If the function pointer is \code{NULL}, the default 326 callback function is reinstalled. We discuss the use of each of the 327 four callbacks below. 328 329 \subsubsubsection{\tt psMemExhaustedCB} 330 331 If not enough memory is available to satisfy a request by 332 \code{psAlloc} or \code{psRealloc}, these functions attempt to find an 333 alternative solution by calling the \code{psMemExhaustedCB}, a 334 function which may be set by the programmer in appropriate 335 circumstances, rather than immediately fail. The typical use of such 336 a feature may be when a program needs a large chunk of memory to do an 337 operation, but the exact size is not critical. This feature gives the 338 programmer the opportunity to make a smaller request and try again, 339 limiting the size of the operating buffer. This callback has the 340 following form: 341 % 342 \begin{verbatim} 343 typedef void *(*psMemExhaustedCB)(size_t size); 344 psMemExhaustedCB psMemExhaustedCBSet(psMemExhaustedCB func); 345 \end{verbatim} 346 % 347 The callback function is called with the attempted size and is 348 expected to return a pointer to the allocated memory or \code{NULL}. 349 Until the callback function is set with \code{psMemExhaustedCBSet}, 350 the default callback function immediately returns \code{NULL}, in 351 which case \code{psAlloc} will call \code{psAbort}. 352 353 \subsubsubsection{\tt psMemProblemCB} 354 355 At various occasions, the memory manager can check the state of the 356 memory stack. If any of these checks discover that the memory stack 357 is corrupted, the \code{psMemProblemCB} is called. The callback 358 has the following form: 359 % 360 \begin{verbatim} 361 typedef void (*psMemProblemCB)(psMemBlock *ptr, char *file, int lineno); 362 psMemProblemCB psMemProblemCBSet(psMemProblemCB func); 363 \end{verbatim} 364 % 365 This callback may be used to report the error and other status 366 information. No return value is accepted, and no specific operations 367 are expected. The callback is for informational purposes only. Where 368 practical and efficient, the memory manager shall call the routine 369 registered using the \code{psMemProblemCBSet} whenever a corrupted 370 block of memory is discovered. For example, doubly-freed blocks can 371 be detected by checking \code{psMemBlock.refcntr}. 372 373 \subsubsubsection{\tt psMemAllocateCB \& psMemFreeCB} 374 375 Two private variables, \code{p_psMemAllocateID} and 376 \code{p_psMemFreeID}, can be used to trace the allocation and freeing 377 of specific memory blocks. If the first (\code{p_psMemAllocateID}) is 378 set and a memory block with that ID is allocated, the corresponding 379 callback is called just before memory is returned to the calling 380 function. If the second (\code{p_psMemFreeID}) is set and the memory 381 block with the ID is about to be freed, the corresponding callback is 382 called just before the memory block is freed. These variables are 383 internal and private to the memory manager and should be set using the 384 following two functions: 385 % 386 \begin{verbatim} 387 long psMemAllocateCBSetID(long id); 388 long psMemFreeCBSetID(long id); 389 \end{verbatim} 390 % 391 The corresponding callback have the following form: 392 % 393 \begin{verbatim} 394 typedef long (*psMemAllocateCB)(const psMemBlock *ptr); 395 psMemAllocateCB psMemAllocateCBSet(psMemAllocateCB func); 396 typedef long (*psMemFreeCB)(const psMemBlock *ptr); 397 psMemFreeCB psMemFreeCBSet(psMemFreeCB func); 398 \end{verbatim} 399 % 400 The callback functions are called with a pointer to the corresponding 401 memory block. The routines \code{psMemFreeIDSet} and 402 \code{psMemAllocateIDSet} accept the desired ID value and return the 403 old value to the user. The return values of the handlers installed by 404 \code{psMemAllocateCBSet} and \code{psMemFreeCBSet} are used to 405 increment the values of \code{p_psMemAllocateID} and 406 \code{p_psMemFreeID} respectively. For example, the return value 407 \code{0} implies that the value is unchanged; if the value is \code{2} 408 the callback will be called again when the memory ID counter has 409 increased by two. This functionality may be useful to check, for 410 example, every 100th block allocated. The function, \code{long 411 psMemGetId(void);} returns the next identification number to be 412 assigned to a memory block. This function can be used to guide the 413 choice of ID set with the functions above. 414 415 \subsubsection{Memory Tracing and Corruption Checks} 248 416 \hlabel{secMemAdvanced} 249 417 250 The types and function prototypes for this part of the memory API 251 are shown below. 252 253 \begin{verbatim} 254 /// prototype of a basic callback used by memory functions 255 typedef int (*psMemCallback)(const psMemBlock *ptr); 256 257 /// prototype of a callback used in error conditions 258 typedef void (*psMemProblemCallback)(const psMemBlock *ptr, const char *file, int lineno); 259 260 /// prototype of a callback used when memory runs out 261 typedef void *(*psMemExhaustedCallback)(size_t size); 262 263 /// Set callback for problems 264 psMemProblemCallback psMemProblemSetCB(psMemProblemCallback func //!< Function to run 265 ); 266 267 /// Set callback for out-of-memory 268 psMemExhaustedCallback psMemExhaustedSetCB(psMemExhaustedCallback func //!< Function to run 269 ); 270 271 /// Set call back for when a particular memory block is allocated 272 psMemCallback psMemAllocateSetCB(psMemCallback func //!< Function to run 273 ); 274 275 /// Set call back for when a particular memory block is freed 276 psMemCallback psMemFreeSetCB(psMemCallback func 277 ); 278 279 /// get next memory ID 280 int psMemGetId(void); 281 282 /// set p_psMemAllocateID to id 283 long psMemSetAllocateID(long id //!< ID to set 284 ); 285 286 /// set p_psMemFreeID to id 287 long psMemSetFreeID(long id //!< ID to set 288 ); 289 290 /// Check for memory leaks 291 int psMemCheckLeaks(int id0, //!< don't list blocks with id < id0 292 psMemBlock ***arr, //!< pointer to array of pointers to leaked blocks, or NULL 293 FILE *fd //!< print list of leaks to fd (or NULL) 294 ); 295 /// Check for memory corruption 296 int psMemCheckCorruption(int abort_on_error //!< Abort on detecting corruption? 297 ); 298 \end{verbatim} 299 300 \paragraph{Callback Routines} 301 302 The four `\code{SetCB}' routines are: 303 304 \begin{tabular}{ll|l} 305 \textbf{type} & \textbf{Name} & \textbf{Function of callback} \\ 306 \code{psMemProblemCallback} & \code{psMemProblemSetCB} & 307 Called when a problem is detected with data being managed on the heap \\ 308 \code{psMemExhaustedCallback} & \code{psMemExhaustedSetCB} & 309 Called when \code{psAlloc} is unable to satisfy a memory request. \\ 310 \code{psMemCallback} & \code{psMemAllocateSetCB} & 311 Callback is called when the \code{psMemBlock} with a specified ID is 312 allocated. \\ 313 \code{psMemCallback} & \code{psMemFreeSetCB} & 314 Callback is called when the \code{psMemBlock} with a specified ID is 315 freed. \\ 316 \end{tabular} 317 318 N.b. 319 \begin{itemize} 320 \item 321 In all cases, the `\code{SetCB}' routine takes a pointer to the 322 desired callback function, and returns a pointer to the one that was 323 previously installed. If the function pointer is \code{NULL}, the 324 default callback function is reinstalled. 325 326 \item 327 The routine installed by \code{psMemExhaustedSetCB} should return 328 a pointer to the desired memory or \code{NULL}; in the latter case 329 \code{psAlloc} will call \code{abort()} 330 331 \item 332 \code{psMemGetId} returns the next identification number to be 333 assigned to a \code{psMemBlock.id}. 334 335 \item 336 The handler specified by \code{psMemAllocateSetCB} is called just 337 before the pointer with \code{psMemBlock.id} equal to 338 \code{p_psMemAllocateID} is returned to the user. The variable 339 \code{p_psMemAllocateID} should not be set directly in any 340 delivered code, \code{psMemSetAllocateID} should be used instead. 341 342 \item 343 The handler specified by \code{psMemFreeSetCB} is called just 344 before the pointer with \code{psMemBlock.id} equal to 345 \code{p_psMemFreeID} is freed. The variable 346 \code{p_psMemFreeID} should not be set directly in any delivered 347 code, \code{psMemSetFreeID} should be used instead. 348 349 \item 350 The routines \code{psMemSetFreeID} and \code{psMemSetAllocateID} 351 accept the desired ID value (see previous two items) and return 352 the old value to the user. 353 354 \item 355 The return values of the handlers installed by \code{psMemAllocateSetCB} 356 and \code{psMemFreeSetCB} are used to increment the values of 357 \code{p_psMemAllocateID} and \code{p_psMemFreeID} respectively. 358 359 For example, the return value \code{0} implies that the value is unchanged; 360 if the value is \code{2} the callback will be called again when the 361 memory ID counter has increased by two. 362 \end{itemize} 363 364 \paragraph{Memory Tracing and Corruption Routines} 365 418 The PSLib memory management system includes features to facilitate 419 tracing the memory allocation and freeing process and to debug memory 420 errors in the calling code. The types and function prototypes for 421 this part of the memory API are shown below. 422 % 423 \begin{verbatim} 424 int psMemCheckLeaks(long id0, psMemBlock ***array, FILE *fd); 425 int psMemCheckCorruption(int abort_on_error); 426 \end{verbatim} 427 % 366 428 The routine \code{psMemCheckLeaks} may be used to check for memory 367 429 leaks. The return value is the number of blocks that have been 368 allocated but not freed. 369 370 Only blocks with \code{psMemBlock.id} greater than \code{id0} 371 are checked; this allows the user to ignore blocks allocated 372 by initialisation routines. 373 374 If the argument \code{arr} is non-\code{NULL}, then upon entering 375 the call \code{**arr} should be \code{NULL}. Upon return it is set 376 to an array of \code{psMemBlock *} pointers, one for each block 430 allocated but not freed. Only blocks with \code{psMemBlock.id} 431 greater than \code{id0} are checked; this allows the user to ignore 432 blocks allocated by initialization routines. 433 434 If the argument \code{array} is non-\code{NULL}, then \code{**array} 435 is set to an array of \code{psMemBlock *} pointers when the function 436 returns. These pointers represent the blocks which have been 377 437 allocated but not freed. It is the caller's responsibility to free 378 this array with \code{psFree}. 438 this array with \code{psFree}. Also note that \code{**array} should be 439 \code{NULL} (or not point to allocated memory) upon entering the call 440 or the corresponding memory reference will be lost. 379 441 380 442 If the argument \code{fd} is non\code{NULL}, a one-line summary … … 384 446 The routine \code{psMemCheckCorruption} checks the entire heap for 385 447 corruption, calling the routine registered with 386 \code{psMemProblem SetCB} for each block detected as being corrupted.448 \code{psMemProblemCBSet} for each block detected as being corrupted. 387 449 The return value is the number of corrupted blocks detected. If the 388 argument \code{abort_on_error} is true, 389 \code{psMemCheckCorruption} shall call \code{abort()} as soon as 390 memory corruption is detected. 391 392 \paragraph{Reference Counting} 450 argument \code{abort_on_error} is true, \code{psMemCheckCorruption} 451 shall call \code{psAbort} as soon as memory corruption is detected. 452 453 \subsubsection{Reference Counting} 393 454 \hlabel{secMemRefcounter} 394 455 395 The memory management routines include a field 396 \code{psMemBlock.refcntr} which must equal \code{1} whenever 397 a pointer is presented to \code{psFree}. 398 399 The API for this field is: 400 \begin{verbatim} 401 /// Return reference counter 402 int psMemGetRefCounter(void *vptr //!< Pointer to get refCounter for 403 ); 404 405 /// Increment reference counter and return the pointer 406 void *psMemIncrRefCounter(void *vptr //!< Pointer to increment refCounter, and return 407 ); 408 409 /// Decrement reference counter and return the pointer 410 void *psMemDecrRefCounter(void *vptr //!< Pointer to decrement refCounter, and return 411 ); 412 \end{verbatim} 413 414 The functions \code{psMemIncrRefCounter} and \code{psMemDecrRefCounter} shall 415 return \code{NULL} if passed a \code{NULL} pointer. 416 417 \subsubsubsection{Rationale} 418 419 The \code{psMemBlock.refcounter} is clearly useful for detecting 420 attempts to free memory that is already free. A more complex 421 application is for allowing pointers to complex data-objects (e.g.\ 422 images) to appear in more than one data structure simultaneously: 423 424 \begin{verbatim} 425 typedef struct { 426 char *name; 427 int value; 428 } psSimple; 429 430 psSimple *psSimpleAlloc(const char *name, int val) 431 { 432 psSimple *simp = psAlloc(sizeof(psSimple)); 433 simp->name = strcpy(psAlloc(strlen(name) + 1), name); 434 simp->value = val; 435 436 return simp; 437 } 438 439 void psSimpleFree(psSimple *simp) 440 { 441 if (simp == NULL) { return; } 442 443 if (psMemGetRefCounter(simp) > 1) { 444 (void)psMemDecrRefCounter(simp); 445 return; 446 } 447 } 448 \end{verbatim} 449 450 451 Because of the use of the \code{refcounter} field, we can safely put items of 452 this type onto many lists: 453 \goodbreak 454 \begin{verbatim} 455 simp = psSimpleAlloc("RHL", 0); 456 psDlistAppend(list1, psMemIncrRefCounter(simp)); 457 psDlistAppend(list2, psMemIncrRefCounter(simp)); 458 psSimpleFree(simp); 459 \end{verbatim} 460 461 (Note: in fact there is no need to explicitly increment the counter 462 in this case, as the \code{psDlistAppend} (section \ref{psDlist}) 463 API specifies that it 464 does it for you.) 456 As mentioned above, the memory management system provides the 457 \code{refCounter} element in \code{psMemBlock} to allow for the 458 management of multiple references to the same block of memory. 459 External APIs which make use of this structure must increment the 460 counter for every additional reference to an allocated memory block, 461 and decrement it when those references are removed. The memory 462 management routines respect the use of the \code{refCounter} field: 463 \code{psFree} will not free a block for which \code{refCounter != 1}, 464 and \code{psAlloc} will initialize the field to 1. \tbd{should psFree 465 give an error if refCounter $>$ 1 or actually do the decrement?} 466 However, they do not (and cannot practically) enforce the use of the 467 counters; this is a requirement of external APIs which intend to use 468 the feature. 469 470 Several APIs are provided to manage the reference counters. These 471 APIs are: 472 % 473 \begin{verbatim} 474 int psMemGetRefCounter(void *vptr); 475 void *psMemIncrRefCounter(void *vptr); 476 void *psMemDecrRefCounter(void *vptr); 477 \end{verbatim} 478 % 479 The functions all take a pointer to the start of a user block of 480 memory. The first simply returns the value of the reference counter. 481 The next two functions increment or decrement the reference counter, 482 returning the pointer which was passed in. These functions must 483 validate the memory pointer by determining the corresponding 484 \code{psMemBlock.id} and checking for consistency in the internal 485 memory block table (the table pointer for \code{psMemBlock.id} should 486 be in the valid range and should correspond to the address of the 487 \code{psMemBlock}). For an example implementation of the 488 \code{refCounter} facilities, see the discussion of \code{psDlist} 489 490 \tbd{REF}. 465 491 466 492 \subsection{Tracing and Logging} … … 468 494 This section defines the \PS{} Tracing and Logging APIs; the former 469 495 refers to debug information that we wish to be able to turn on and off 470 without recompiling (although it will \emph{not} be available in 471 production code); the latter means information about the processing 472 that must be collected and saved, even in the production system. 473 474 We envision that we will make extensive use of \code{psTrace} throughout 475 the \PS{} code. 496 without recompiling (it will \emph{not} be available in production 497 code); the latter means information about the processing that must be 498 collected and saved, even in the production system. We envision that 499 we will make extensive use of \code{psTrace} throughout the \PS{} 500 code. 476 501 477 502 \subsubsection{Tracing APIs} 478 503 \hlabel{psTrace} 479 504 480 \begin{verbatim} 481 #if defined(PS_NTRACE) 482 # define psTrace(facil, level, ...) /* do nothing */ 483 #else 484 # define psTrace(facil, level, ...) \ 485 p_psTrace(facil, level, __VA_ARGS__) 486 #endif 487 488 /// Send a trace message 489 void p_psTrace(const char *facil, ///< facilty of interest 490 int level, ///< desired trace level 491 ... ///< trace message arguments 492 ); 493 494 /// Set trace level 495 int psSetTraceLevel(const char *facil, ///< facilty of interest 496 int level ///< desired trace level 497 ); 498 499 /// Get the trace level 500 int psGetTraceLevel(const char *name ///< facilty of interest 501 ); 502 503 /// turn off all tracing, and free trace's allocated memory 504 void psTraceReset(void); 505 506 /// print trace levels 507 void psPrintTraceLevels(void); 508 \end{verbatim} 509 510 \begin{itemize} 511 \item 512 Logging is provided by the function \code{psTrace}, 513 which is actually a macro. When the macro \code{PS_NTRACE} 514 is defined, all occurrences of \code{psTrace} shall 515 be replaced by whitespace. 516 517 \item 518 The first argument to \code{psTrace} is a name of the form 519 \code{aaa.bbb.ccc}. The second is an integer, 520 \code{level}. The remaining arguments are a printf-style format 521 and a (possibly empty) set of values for that formatting 522 string. When this trace is active, \code{psTrace} shall generate 523 the requested output on \code{stdout}, preceded by \code{level} 524 spaces. 525 526 \item 527 The call \code{psSetTraceLevel(name, level)} shall set the trace 528 level for \code{name} to \code{level}. 529 530 \item 531 The call \code{psGetTraceLevel(name)} shall return the level 532 associated with \code{name}. If \code{name} has not been 533 associated with a level, the routine shall remove the \textit{last} 534 element of \code{name} and attempt to look up its level; this 535 procedure shall be applied recursively until the name is reduced 536 to \code{""}; if this name has no level associated with 537 it, then the value \code{0} shall be returned (see examples 538 below). 539 540 \item 541 The call \code{psTrace(name, level, ...)} 542 shall print the message if and only if 543 \code{psGetTraceLevel(name)} returns a value greater than 544 or equal to \code{level}. 545 546 \item 547 \code{psPrintTraceLevels} shall print a listing of all 548 declared levels, displayed as a hierarchy with sub-components 549 sorted within each component (see examples below). 550 551 Note in particular that the root of the tree, the name \code{""} 552 should print as \code{(root)}, and nodes which have not 553 been assigned a value should list their level as \code{.}. 554 555 \item 556 All of the tracing facilities shall be SWIGed, with the exception 557 of \code{p_psTrace}. 558 559 \item 560 There is no requirement that \code{psTrace} be usable from 561 within the functions that implement the tracing or memory 562 management systems. 563 564 \item 565 \code{psTraceReset} shall reset all tracing to the state that it 566 had at program initiation, including freeing any memory that the 567 tracing subsystem may have allocated. 568 \end{itemize} 569 570 \paragraph{Examples of the use of Tracing Facilities} 571 572 For example, after the commands: 573 \begin{verbatim} 574 psSetTraceLevel("utils.dlist.add.head", 9); 575 psSetTraceLevel("utils.dlist.add", 3); 576 psSetTraceLevel("utils.dlist.remove", 4); 577 psSetTraceLevel("coadd", 2); 578 psSetTraceLevel("coadd.CR.remove.morphology", 5); 579 psSetTraceLevel("utils.hash", 2); 580 psSetTraceLevel("utils.dlist.add", 9); 581 psSetTraceLevel("utils", 1); 582 \end{verbatim} 583 the command \code{psPrintTraceLevels()} should print: 584 \begin{verbatim} 585 (root) 0 586 utils 1 587 hash 2 588 dlist . 589 remove 4 590 add 9 591 head 9 592 coadd 2 593 CR . 594 remove . 595 morphology 5 596 \end{verbatim} 597 where \code{.} means that the trace level should be inherited from its parent. 598 599 After this set of \code{psSetTraceLevel} commands, and if 600 \code{PS_NTRACE} is not defined, the following commands 601 \begin{verbatim} 602 psTrace("utils.dlist.remove", 2, "Removing psDList key \"%s\"\n", "my_key"); 603 psTrace("utils", 2, "Initialising utilities library\n"); 604 psTrace("", 2, "This is turned on by trace component \"\""); 605 psTrace("utils.dlist", 2, "Initialising psDList\n"); 606 psTrace("utils.dlist.remove", 4, "Removing psDList key \"%s\" (value: \"%d\")\n", "my_key", 12345); 607 psTrace("utils.hash.remove", 4, "Removing hash key \"%s\" (value: \"%d\")\n", "my_key", 12345); 608 psTrace("utils.dlist.add", 1, "Adding psDList key \"%s\"\n", "your_key"); 609 psTrace("utils.dlist.find", 2, "Looking up psDList key \"%s\"\n", "some_key"); 610 psTrace("coadd.CR.remove", 4, "Removing CRs\n"); 611 psTrace("coadd.CR.remove.morphology", 4, "CRs are not fuzzy\n"); 612 \end{verbatim} 613 should produce this output: 614 \begin{verbatim} 615 Removing psDList key "my_key" 616 Removing psDList key "my_key" (value: "12345") 617 Adding psDList key "your_key" 618 CRs are not fuzzy 619 \end{verbatim} 620 621 Note that 622 \begin{description} 623 \item 624 \code{utils.dlist} messages are at level 1, inherited from \code{utils}, so the 625 \code{Initialising utilities library}, \code{Initialising psDList}, and 626 \code{Looking up psDList key} messages are \emph{not} printed (the traces are at level 2). 627 628 \item 629 \code{utils.dlist.remove} messages are at level 4, and are printed. 630 631 \item 632 \code{utils.hash} messages are at level 2, and are not printed (the traces are at level 4) 633 634 \item 635 \code{coadd.CR.remove} is at level 2 (inherited from \code{coadd}) so \code{Removing CRs} 636 isn't printed. \code{coadd.CR.remove.morphology} is at level 4, so \code{CRs are not fuzzy} is printed. 637 \end{description} 505 A code-tracing facility should allow the programmer to place messages 506 in the code which, when called, will print some useful information 507 about the containing block of code. Ideally, different messages may 508 be specified to have different levels (of severity or interest). For 509 a given run of the program, the level of interest should be set to 510 provide more or less feedback, depending on the needs of the 511 programmer. In a typical situation, low-level messages would be 512 placed generously throughout the code, indicating the flow of the 513 program. Higher-level messages would be placed in a limited number of 514 special locations, such as the start of major code segments or where a 515 particularly unusual condition is met. Top-level messages would be 516 placed in code triggered under serious error conditions. A normal run 517 of the program would have the trace messages printed only for the 518 top-level. If the user needs to dig deeper into the code, the trace 519 level should be set lower, and the more detailed messages could be 520 examined. In a case of a real, poorly-understood problem with the 521 code, the trace threshold would be placed to the bottom and the 522 lowest-level step-by-step messages would be printed. 523 524 The PSLib tracing facility provides the above functionality along with 525 the ability to assign different trace levels to different types of 526 messages. Each trace message when placed in the code is assigned to 527 be part of a specific tracing 'facility', defined in more detail 528 below. The trace level for that specific message is also set when the 529 message is placed. Each facility may have its trace level set 530 independently. Thus, it is possible to request detailed trace output 531 for one facility while minimizing the verbosity of the trace output 532 from the rest of the program. 533 534 The trace facilities consist of a hierarchy of names. A trace 535 facility is defined by a string consisting of words separated by dots, 536 with a hierarchy equivalent to that of UNIX directory names. The 537 top-level facility is simply \code{'.'} (one dot). The next level 538 would be \code{'.A'}, followed by \code{.A.B}, and so on. The 539 relationship is seen in two ways. First, a facility inherits the 540 trace level of its parent unless specified. Second, the hierarchy is 541 used to format the listing of the trace facilities. The first of 542 these rules provides a mechanism to define the default trace levels 543 for any facility even if it has not been registered explicitly since 544 all named facilities are implicitly children of the top level facility 545 (\code{.}). The second rule is simply an organizational technique to 546 make the listing of facility information clear. 547 548 The API to place a trace message in the code, and simultaneously set 549 its trace level and facility, is: 550 % 551 \begin{verbatim} 552 void psTrace(char *facil, int myLevel,...); 553 \end{verbatim} 554 % 555 where the last argument is a printf-style formatting code and possible 556 arguments to that formatting statement, to be implemented using the 557 \code{vprintf} functions. This command specifies the name of the 558 facility to which the message belongs (\code{facil}), the trace level 559 for this message in that facility (\code{myLevel}) and the message 560 itself. 561 562 The trace level for any facility may be set at any time with the 563 following function: 564 % 565 \begin{verbatim} 566 int psSetTraceLevel(char *facil, int level); 567 \end{verbatim} 568 % 569 where \code{level} specifies the current trace level for the facility 570 named by \code{facil}. The currently defined trace level for a given 571 facility is determined by the function: 572 % 573 \begin{verbatim} 574 int psGetTraceLevel(char *facil); 575 \end{verbatim} 576 % 577 which returns the trace level of the named facility following the 578 rules specified above. A specified trace message (identified by 579 \code{psTrace}) shall be printed if and only if 580 \code{psGetTraceLevel(facil)} returns a value greater than or equal to 581 the value of \code{myLevel} for that message. 582 583 PSLib includes a utility function for examining the current tracing 584 levels of all facilities: \code{void psPrintTraceLevels(void);}. This 585 function will print the hierarchy of trace facilities along with the 586 current trace level for each facility. For example, a particular 587 program may have a few facilities defined, along with their trace 588 levels. A call to \code{psPrintTraceLevels} may produce a listing 589 which appears as: 590 \begin{verbatim} 591 . 0 592 .debias 1 593 .flatten 1 594 .flatten.divide 2 595 .object.findpeak 1 596 .object.getsky 1 597 \end{verbatim} 598 599 Considering the same program, the programmer might place a variety of 600 trace messages throughout the \code{flatten} portion of the code with 601 different types of messages, such as: 602 % 603 \begin{verbatim} 604 psTrace("flatten", 2, "starting flatten function\n"); 605 psTrace("flatten", 0, "ERROR: flat-field image \%s is invalid\n", filename); 606 psTrace("flatten.divide", 2, "doing the divide\n"); 607 psTrace("flatten.divide", 3, "trying the loop, i = \%d\n", i); 608 psTrace("flatten.divide", 1, "got an invalid pixel value (NaN) at \%d,\%d\n"); 609 psTrace("flatten.divide", 2, "divide is done\n"); 610 \end{verbatim} 611 % 612 Under the trace levels set above, if the code actually reached each of 613 these trace messages, the following messages would be printed: 614 % 615 \begin{verbatim} 616 ERROR: flat-field image foo.fits is invalid (printed) 617 doing the divide (printed) 618 got an invalid pixel value (NaN) at 500,20 (printed) 619 divide is done (printed) 620 \end{verbatim} 621 % 622 while these two would not be printed because their facility level was 623 too low: 624 % 625 \begin{verbatim} 626 starting flatten function 627 trying the loop, i = 0 628 trying the loop, i = 1 629 trying the loop, i = 2 630 ... 631 \end{verbatim} 632 % 633 634 The tracing facility should be made available, or not, on compilation. 635 If the C pre-processor macro \code{PS_NO_TRACE} is defined, all trace 636 code shall be replaced by empty space so that none of the code is 637 compiled. This can be implemented via macro front-ends to private 638 versions of the user APIs. In addition, a function \code{void 639 psTraceReset(void)} will set all trace levels to 0. 640 641 \tbd{ability to send trace messages to output locations other than stdout?} 638 642 639 643 \subsubsection{Message Logging} 640 644 \hlabel{psLogMsg} 641 645 642 \begin{verbatim} 643 enum { PS_LOG_ABORT = 0, PS_LOG_ERROR, PS_LOG_WARN, PS_LOG_INFO }; //!< Status codes for log messages 644 645 enum { PS_LOG_TO_STDERR, PS_LOG_TO_STDOUT }; //!< Destinations for log messages 646 647 /// Logs a message 648 void psLogMsg(const char *name, int level, const char *fmt, ...); 649 650 /// Logs a message from varargs 651 void p_psVLogMsg(const char *name, int level, const char *fmt, va_list ap); 652 653 /// Sets the log destination 646 Message logging is similar in some respects to tracing. Like trace 647 messages, log messages are placed in the code at various locations to 648 provide output describing the current state of the program. Like 649 the PSLib trace facility, a good log facility should have the 650 capability of associating each message with an importance or severity 651 level, and at any point, the level for which messages are actually 652 printed should be set in a flexible manner. Unlike trace messages, 653 however, log messages are always part of the code and are available in 654 the production version as well as in test versions. 655 656 The PSLib logging facility does not include the extensive facility 657 levels which are provided by the trace facility. Less control over 658 the granularity is needed for the log messages than for the trace 659 messages. 660 661 A log message is placed in the code with the command: 662 % 663 \begin{verbatim} 664 void psLogMsg(char *name, int myLevel, char *fmt, ...); 665 void psVLogMsg(char *name, int myLevel, char *fmt, va_list ap); 666 \end{verbatim} 667 where \code{name} is a word to describe the source of the message, 668 \code{myLevel} is the severity level of this message, and \code{fmt} 669 is a printf-style formatting statement defining the actual message, 670 and is followed by the arguments to the formatting code. The second 671 form, \code{psVLogMsg} is an equivalent command which takes a 672 \code{va_list} argument. 673 674 A log message may have any level specified in the range 0-9, though 675 the first 4 levels are associated with symbolic names: 676 % 677 \begin{verbatim} 678 enum { PS_LOG_ABORT = 0, PS_LOG_ERROR, PS_LOG_WARN, PS_LOG_INFO }; 679 \end{verbatim} 680 % 681 The default level is set to \code{PS_LOG_INFO}. 682 683 At any time, the program may set the current log level, the level 684 above which log messages are ignored, using the function: 685 % 686 \begin{verbatim} 687 int psSetLogLevel(int level); 688 \end{verbatim} 689 % 690 A specific message invoked with \code{psLogMsg} is only printed if its 691 value of \code{myLevel} is less than the current value set by 692 \code{psSetLogLevel}. 693 694 Log messages are sent to the destination most recently set using: 695 % 696 \begin{verbatim} 654 697 int psSetLogDestination(int dest); 655 656 /// Sets the log level 657 int psSetLogLevel(int level); 658 659 /// sets the log format 698 \end{verbatim} 699 % 700 The only two values that are initially defined are 701 \code{PS_LOG_TO_STDERR} and \code{PS_LOG_TO_STDOUT} to write to 702 \code{stderr} and \code{stdout} respectively. \tbd{define other 703 destinations? why not use file descriptors?, etc?}. 704 705 The output format is controlled with the function: 706 % 707 \begin{verbatim} 660 708 void psSetLogFormat(const char *fmt); 661 709 \end{verbatim} 662 663 The function \code{psSetLogLevel} may be used to set the current 664 level of logging; the previous value is returned. 665 The default value is \code{PS_LOG_INFO}. Valid values are 0---9 666 inclusive (note that only the first four are required to have 667 symbolic names). 668 669 A call to \code{psLogMsg(name, level, msg, ...)} shall generate 670 a log message if \code{level} is less than or equal to the 671 value most recently set using \code{psSetLogLevel}. The function 672 \code{p_psLogMsg} is identical, except that it expects a 673 final \code{va_list} argument. 674 675 The format of the log message shall be of the form: 676 \begin{verbatim} 677 YYYY:MM:DD hh:mm:ssZ|hostname|l|name |msg 678 \end{verbatim} 679 \code{YYYY}, \code{MM}, \code{DD}, \code{hh}, \code{mm}, and \code{ss} 680 are the year, month (Jan == 1), day of the month, hours (0--23), 681 minutes, and seconds when the log message was received. Note that the 682 timestamp is in ISO order, and that the timezone is GMT (hence the 683 \code{Z}). 684 685 The \code{hostname} is returned by \code{gethostname}, \code{l} is a 686 letter associated with the level (\code{A}, \code{E}, \code{W}, and 687 \code{I} for \code{PS_LOG_ABORT}, \code{PS_LOG_ERROR}, \code{PS_LOG_WARN}, 688 and \code{PS_LOG_INFO} respectively. Other levels are represented 689 numerically (\code{5} etc.). The other two field, \code{name} and 690 \code{msg} are arguments to \code{psLogMsg}; note that \code{name} has 691 a fixed width of 15 characters. If \code{msg} doesn't end in a newline, 692 a single newline is emitted to terminate the message. 693 694 An example message is: 695 \begin{verbatim} 696 2004:02:24 20:14:18Z|alibaba.IfA.Hawaii.Edu|I|utils |Hello World 697 \end{verbatim} 698 699 Log messages are sent to the destination most recently set using 700 \code{psSetLogDestination}. The only two values that are initially 701 defined are \code{PS_LOG_TO_STDERR} and \code{PS_LOG_TO_STDOUT} to 702 write to \code{stderr} and \code{stdout} respectively. 703 704 The fields included in the log message may be controlled using \code{psSetLogFormat} which 705 expects a string consisting of the letters \code{H} (host), \code{L} (level), \code{M} (message), 706 \code{N} (name), and \code{T} (time). The default is \code{THLNM}, as shown above. 707 708 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 710 % 711 which expects a string consisting of the letters \code{H} (host), 712 \code{L} (level), \code{M} (message), \code{N} (name), and \code{T} 713 (time). The default is \code{THLNM}, which produces log messages in 714 the form: 715 \begin{verbatim} 716 YYYY:MM:DD hh:mm:ssZ | hostname | L | name | msg 717 \end{verbatim} 718 where \code{YYYY}, \code{MM}, \code{DD}, \code{hh}, \code{mm}, and 719 \code{ss} are the year, month (Jan == 1), day of the month, hours 720 (0--23), minutes, and seconds when the log message was received. Note 721 that the timestamp is in ISO order, and that the timezone is GMT 722 (hence the \code{Z}). The \code{hostname} is returned by 723 \code{gethostname}, \code{L} is a letter associated with the level 724 (\code{A}, \code{E}, \code{W}, and \code{I} for \code{PS_LOG_ABORT}, 725 \code{PS_LOG_ERROR}, \code{PS_LOG_WARN}, and \code{PS_LOG_INFO} 726 respectively. Other levels are represented numerically (\code{5} 727 etc.). The other two field, \code{name} and \code{msg} are the 728 arguments to \code{psLogMsg}; note that \code{name} has a fixed width 729 of 15 characters. If \code{msg} doesn't end in a newline, a single 730 newline is emitted to terminate the message. An example message is: 731 % 732 \begin{verbatim} 733 2004:02:24 20:14:18Z | alibaba.IfA.Hawaii.Edu |I | utils | Hello World 734 \end{verbatim} 735 % 736 The possible order of the format entries is fixed and not determined 737 by the order of the letters. Selecting an output format with fewer 738 than the complete set of 5 entries simply removes those entries from 739 the output messages. 740 741 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 709 742 710 743 \subsection{Miscellaneous Utilities} 711 744 712 \begin{verbatim} 713 #define PS_STRING(S) #S // converts argument S to string 714 715 /// Prints an error message and aborts 716 void psAbort(const char *name, ///< Category of code that caused the abort 717 const char *fmt, ///< Format 718 ... ///< Extra arguments to use format 719 ); 720 721 /// Prints an error message and doesn't abort 722 void psError(const char *name, ///< Category of code that caused the abort 723 const char *fmt, ///< Format 724 ... ///< Extra arguments to use format 725 ); 726 727 /// Allocates and returns a copy of a string 728 char *psStringCopy(const char *str ///< string to copy 729 ); 730 731 /// Allocates nChar and returns a copy of the string or segment 732 char *psStringNCopy(const char *str, ///< string to copy 733 int nChar //!< Number of characters (including \0 ) 734 ); 735 \end{verbatim} 736 737 \code{psAbort} shall call \code{psMsgLog} with a level of \code{PS_LOG_ABORT}, 738 and then call \code{abort}. 739 \code{psError} shall call \code{psMsgLog} with a level of \code{PS_LOG_ERROR}, 740 and then return. 741 In cases of doubt, a good choice for 742 \code{name} is \code{__func__}. 743 744 \code{psStringCopy} shall allocate and return a copy of the input string. 745 746 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 747 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 748 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 745 We require a several very low-functions. Two functions provide 746 conveniences tied to the logging facilities: 747 % 748 \begin{verbatim} 749 void psAbort(char *name, char *fmt,...); 750 void psError(char *name, char *fmt,...); 751 \end{verbatim} 752 % 753 The first function, \code{psAbort}, shall call \code{psMsgLog} with a 754 level of \code{PS_LOG_ABORT}, and then call \code{abort}. The second 755 function, \code{psError}, shall call \code{psMsgLog} with a level of 756 \code{PS_LOG_ERROR}, and then return. In cases of doubt, a good 757 choice for \code{name} is \code{__func__}. 758 759 A few useful string functions are also necessary: 760 % 761 \begin{verbatim} 762 PS_STRING(S); 763 char *psStringCopy(char *string); 764 char *psStringNCopy(char *string, int nChar); 765 \end{verbatim} 766 % 767 The first function simply converts the argument to a string 768 \tbd{explanation of usage and rational?}. The second function, 769 \code{psStringCopy}, shall allocate a sufficient memory block and 770 return a copy of the input string. Similarly, \code{psStringNCopy} 771 shall allocate exactly \code{nChar} bytes and copy as much of the 772 input string as possible into the resulting block without overrunning 773 the available space. The last byte of the output string is required 774 to be \code{NULL}, as well as any additional bytes if \code{string} is 775 not long enough to fill the output string. 776 777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 749 778 750 779 \section{Basic Data Collections} … … 933 962 /** Doubly-linked list element */ 934 963 typedef struct psDlistElem { 935 struct psDlistElem *prev; // !< previous link in list936 struct psDlistElem *next; // !< next link in list937 void *data; // !< real data item964 struct psDlistElem *prev; ///< previous link in list 965 struct psDlistElem *next; ///< next link in list 966 void *data; ///< real data item 938 967 } psDlistElem; 939 968 940 969 /** Doubly-linked list */ 941 970 typedef struct { 942 int n; // !< number of elements on list943 psDlistElem *head; // !< first element on list (may be NULL)944 psDlistElem *tail; // !< last element on list (may be NULL)945 psDlistElem *iter; // !< iteration cursor971 int n; ///< number of elements on list 972 psDlistElem *head; ///< first element on list (may be NULL) 973 psDlistElem *tail; ///< last element on list (may be NULL) 974 psDlistElem *iter; ///< iteration cursor 946 975 } psDlist; 947 976 948 977 /** Special values of index into list */ 949 978 enum { 950 PS_DLIST_HEAD = 0, // !< at head951 PS_DLIST_TAIL = -1, // !< at tail952 PS_DLIST_UNKNOWN = -2, // !< unknown position953 PS_DLIST_PREV = -3, // !< previous element954 PS_DLIST_NEXT = -4 // !< next element979 PS_DLIST_HEAD = 0, ///< at head 980 PS_DLIST_TAIL = -1, ///< at tail 981 PS_DLIST_UNKNOWN = -2, ///< unknown position 982 PS_DLIST_PREV = -3, ///< previous element 983 PS_DLIST_NEXT = -4 ///< next element 955 984 }; 956 985 \end{verbatim} … … 960 989 \begin{verbatim} 961 990 /** Constructor */ 962 psDlist *psDlistAlloc(void *data // !< initial data item; may be NULL991 psDlist *psDlistAlloc(void *data ///< initial data item; may be NULL 963 992 ); 964 993 965 994 /** Destructor */ 966 void psDlistFree(psDlist *list, // !< list to destroy967 void (*elemFree)(void *) // !< destructor for data on list995 void psDlistFree(psDlist *list, ///< list to destroy 996 void (*elemFree)(void *) ///< destructor for data on list 968 997 ); 969 998 … … 971 1000 972 1001 /** Add to list */ 973 psDlist *psDlistAdd(psDlist *list, // !< list to add to (may be NULL)974 void *data, // !< data item to add975 int where // !< index, PS_DLIST_HEAD, or PS_DLIST_TAIL1002 psDlist *psDlistAdd(psDlist *list, ///< list to add to (may be NULL) 1003 void *data, ///< data item to add 1004 int where ///< index, PS_DLIST_HEAD, or PS_DLIST_TAIL 976 1005 ); 977 1006 978 1007 /** Append to a list */ 979 psDlist *psDlistAppend(psDlist *list, // !< list to append to (may be NULL)980 void *data // !< data item to add1008 psDlist *psDlistAppend(psDlist *list, ///< list to append to (may be NULL) 1009 void *data ///< data item to add 981 1010 ); 982 1011 983 1012 /** Remove from a list */ 984 void *psDlistRemove(psDlist *list, // !< list to remove element from985 void *data, // !< data item to remove986 int which // !< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or987 // !< PS_DLIST_PREV1013 void *psDlistRemove(psDlist *list, ///< list to remove element from 1014 void *data, ///< data item to remove 1015 int which ///< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or 1016 ///< PS_DLIST_PREV 988 1017 ); 989 1018 /** Retrieve from a list */ 990 void *psDlistGet(const psDlist *list, // !< list to retrieve element from991 int which // !< index of item, or PS_DLIST_NEXT, or PS_DLIST_PREV1019 void *psDlistGet(const psDlist *list, ///< list to retrieve element from 1020 int which ///< index of item, or PS_DLIST_NEXT, or PS_DLIST_PREV 992 1021 ); 993 1022 994 1023 /** Convert doubly-linked list to an array */ 995 psVoidPtrArray *psDlistToArray(psDlist *dlist // !< List to convert1024 psVoidPtrArray *psDlistToArray(psDlist *dlist ///< List to convert 996 1025 ); 997 1026 998 1027 /** Convert array to a doubly-linked list */ 999 psDlist *psArrayToDlist(psVoidPtrArray *arr // !< Array to convert1028 psDlist *psArrayToDlist(psVoidPtrArray *arr ///< Array to convert 1000 1029 ); 1001 1030 \end{verbatim} … … 1015 1044 \begin{verbatim} 1016 1045 /** Set the iterator */ 1017 void psDlistSetIterator(psDlist *list, // !< list to retrieve element from1018 int where, // !< index, PS_DLIST_HEAD, or PS_DLIST_TAIL1019 int which // !< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or1020 // !< PS_DLIST_PREV1046 void psDlistSetIterator(psDlist *list, ///< list to retrieve element from 1047 int where, ///< index, PS_DLIST_HEAD, or PS_DLIST_TAIL 1048 int which ///< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or 1049 ///< PS_DLIST_PREV 1021 1050 ); 1022 1051 1023 1052 /** Get next element */ 1024 void *psDlistGetNext(psDlist *list, // !< list to retrieve element from1025 int which // !< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or1026 // !< PS_DLIST_PREV1053 void *psDlistGetNext(psDlist *list, ///< list to retrieve element from 1054 int which ///< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or 1055 ///< PS_DLIST_PREV 1027 1056 ); 1028 1057 1029 1058 /** Get previous element */ 1030 void *psDlistGetPrev(psDlist *list, // !< list to retrieve element from1031 int which // !< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or1032 // !< PS_DLIST_PREV1059 void *psDlistGetPrev(psDlist *list, ///< list to retrieve element from 1060 int which ///< index of item, or PS_DLIST_UNKNOWN, or PS_DLIST_NEXT, or 1061 ///< PS_DLIST_PREV 1033 1062 ); 1034 1063 \end{verbatim} … … 1048 1077 \code{psDlist}). 1049 1078 1079 \subsubsubsection{Rationale} 1080 1081 \tbd{defer this example to the psDlist section?} 1082 1083 The \code{psMemBlock.refcounter} is clearly useful for detecting 1084 attempts to free memory that is already free. A more complex 1085 application is for allowing pointers to complex data-objects (e.g.\ 1086 images) to appear in more than one data structure simultaneously: 1087 1088 \begin{verbatim} 1089 typedef struct { 1090 char *name; 1091 int value; 1092 } psSimple; 1093 1094 psSimple *psSimpleAlloc(const char *name, int val) 1095 { 1096 psSimple *simp = psAlloc(sizeof(psSimple)); 1097 simp->name = strcpy(psAlloc(strlen(name) + 1), name); 1098 simp->value = val; 1099 1100 return simp; 1101 } 1102 1103 void psSimpleFree(psSimple *simp) 1104 { 1105 if (simp == NULL) { return; } 1106 1107 if (psMemGetRefCounter(simp) > 1) { 1108 (void)psMemDecrRefCounter(simp); 1109 return; 1110 } 1111 } 1112 \end{verbatim} 1113 1114 Because of the use of the \code{refcounter} field, we can safely put items of 1115 this type onto many lists: 1116 \goodbreak 1117 \begin{verbatim} 1118 simp = psSimpleAlloc("RHL", 0); 1119 psDlistAppend(list1, psMemIncrRefCounter(simp)); 1120 psDlistAppend(list2, psMemIncrRefCounter(simp)); 1121 psSimpleFree(simp); 1122 \end{verbatim} 1123 1124 (Note: in fact there is no need to explicitly increment the counter 1125 in this case, as the \code{psDlistAppend} (section \ref{psDlist}) 1126 API specifies that it 1127 does it for you.) 1128 1050 1129 \subsection{Hash Tables} 1051 1130 \hlabel{psHash} … … 1087 1166 \end{verbatim} 1088 1167 1089 1090 1168 A hash table is an abstract type \code{psHash}. The argument 1091 1169 \code{nbucket} to \code{psHashAlloc} is a non-binding suggestion … … 1108 1186 \code{psHashRemove} removes the entry associated with the 1109 1187 key from the table, and returns the \code{data}; if the key's invalid it returns NULL. 1188 1189 \code{psHashKeylist} returns the complete list of defined keys 1190 associated with the psHash table. \tbd{API is not yet specified.} 1110 1191 1111 1192 \section{Data manipulation} … … 1123 1204 \item (Fast) Fourier Transforms; 1124 1205 \item General functions; and 1125 \item Minimi sation and fitting routines.1206 \item Minimization and fitting routines. 1126 1207 \end{itemize} 1127 1208 … … 1137 1218 /** A bitmask of arbitrary length. */ 1138 1219 typedef struct { 1139 int n; // !< Number of chars that form the mask1140 char *bits; // !< The bits1220 int n; ///< Number of chars that form the mask 1221 char *bits; ///< The bits 1141 1222 } psBitMask; 1142 1223 \end{verbatim} … … 1146 1227 \begin{verbatim} 1147 1228 /** Constructor */ 1148 psBitMask *psBitMaskAlloc(int n // !< Number of bits required1229 psBitMask *psBitMaskAlloc(int n ///< Number of bits required 1149 1230 ); 1150 1231 1151 1232 /** Destructor */ 1152 void psBitMaskFree(psBitMask *restrict myMask // !< Bit mask to destroy1233 void psBitMaskFree(psBitMask *restrict myMask ///< Bit mask to destroy 1153 1234 ); 1154 1235 \end{verbatim} … … 1165 1246 /** Set a bit mask */ 1166 1247 psBitMask * 1167 psBitMaskSet(psBitMask *outMask, // !< Output bit mask or NULL1168 const psBitMask *myMask, // !< Input bit mask1169 int bit // !< Bit to set1248 psBitMaskSet(psBitMask *outMask, ///< Output bit mask or NULL 1249 const psBitMask *myMask, ///< Input bit mask 1250 int bit ///< Bit to set 1170 1251 ); 1171 1252 \end{verbatim} … … 1174 1255 /** Check a bit mask. Returns true or false */ 1175 1256 int 1176 psBitMaskTest(const psBitMask *checkMask, // !< Bit mask to check1177 int bit // !< Bit to check1257 psBitMaskTest(const psBitMask *checkMask, ///< Bit mask to check 1258 int bit ///< Bit to check 1178 1259 ); 1179 1260 \end{verbatim} … … 1182 1263 /** apply the given operator to two bit masks */ 1183 1264 psBitMask * 1184 psBitMaskOp(psBitMask *outMask, // !< Output bit mask or NULL1185 const psBitMask *restrict inMask1, // !< Input bit mask 11186 char *operator, // !< bit mask operator (AND, OR, XOR)1187 const psBitMask *restrict inMask2 // !< Input bit mask 21265 psBitMaskOp(psBitMask *outMask, ///< Output bit mask or NULL 1266 const psBitMask *restrict inMask1, ///< Input bit mask 1 1267 char *operator, ///< bit mask operator (AND, OR, XOR) 1268 const psBitMask *restrict inMask2 ///< Input bit mask 2 1188 1269 ); 1189 1270 \end{verbatim} … … 1198 1279 /** Sort an array. Inputs not restrict-ed to allow sort in place */ 1199 1280 psFloatArray * 1200 psSort(psFloatArray *out, // !< Sorted array to return. May be NULL1201 const psFloatArray *myArray // !< Array to sort1281 psSort(psFloatArray *out, ///< Sorted array to return. May be NULL 1282 const psFloatArray *myArray ///< Array to sort 1202 1283 ); 1203 1284 \end{verbatim} … … 1205 1286 We also require the ability to sort one array based on another. In 1206 1287 order to facilitate this, we will have a sort function return an array 1207 containing the ind ices for the unsorted list in the order appropriate1288 containing the induces for the unsorted list in the order appropriate 1208 1289 for the sorted array: 1209 1290 … … 1211 1292 /** Sort an array, along with some other stuff. Returns an index array */ 1212 1293 psIntArray * 1213 psSortIndex(psIntArray *restrict out; // !< Output index array (may be NULL)1214 const psFloatArray *restrict myArray // !< Array to sort1294 psSortIndex(psIntArray *restrict out; ///< Output index array (may be NULL) 1295 const psFloatArray *restrict myArray ///< Array to sort 1215 1296 ); 1216 1297 \end{verbatim} … … 1251 1332 /** Do Statistics on an array. Returns a status value. */ 1252 1333 psStats * 1253 psArrayStats(const psFloatArray *restrict myArray, // !< Array to be analysed1254 const psIntArray *restrict maskArray, // !< Ignore elements where (maskArray & maskVal) != 01255 // !< May be NULL1256 unsigned int maskVal, // !< Only mask elements with one of these bits set in maskArray1257 psStats *stats // !< stats structure defines stats to be calculated and how1334 psArrayStats(const psFloatArray *restrict myArray, ///< Array to be analysed 1335 const psIntArray *restrict maskArray, ///< Ignore elements where (maskArray & maskVal) != 0 1336 ///< May be NULL 1337 unsigned int maskVal, ///< Only mask elements with one of these bits set in maskArray 1338 psStats *stats ///< stats structure defines stats to be calculated and how 1258 1339 ); 1259 1340 \end{verbatim} … … 1265 1346 /** generic statistics structure */ 1266 1347 typedef struct { 1267 double sampleMean; // <!formal mean of sample1268 double sampleMedian; // <!formal median of sample1269 double sampleMode; // !< Formal mode of sample1270 double sampleStdev; // <!standard deviation of sample1271 double sampleUQ; // <!upper quartile of sample1272 double sampleLQ; // <!lower quartile of sample1273 double robustMean; // <!robust mean of array1274 double robustMeanError; // <!error on robust mean1275 int robustMeanNvalues; // <!number of measurements used for robust mean1276 double robustMedian; // <!robust median of array1277 double robustMedianError; // <!error on robust median1278 int robustMedianNvalues; // <!number of measurements used for robust median1279 double robustMode; // !< Robust mode of array1280 double robustModeErr; // !< Error in robust mode1281 int robustModeNvalues; // !< Number of measurements used for robust mode1282 double robustStdev; // <!robust standard deviation of array1283 double robustUQ; // <!robust upper quartile1284 double robustLQ; // <!robust lower quartile1285 double clippedMean; // <!Nsigma clipped mean1286 double clippedMeanError; // <!error on clipped mean1287 int clippedMeanNvalues; // <!number of data points used for clipped mean1288 double clippedStdev; // !< standard deviation after clipping1289 double clipSigma; // <!Nsigma used for clipping; user input1290 int clipIter; // !< Number of clipping iterations; user input1291 double min; // <!minimum data value in array1292 double max; // <!maximum data value in array1293 int nValues; // <!number of data values in array1294 psStatsOptions options; // <!bitmask of calculated values1348 double sampleMean; ///< formal mean of sample 1349 double sampleMedian; ///< formal median of sample 1350 double sampleMode; ///< Formal mode of sample 1351 double sampleStdev; ///< standard deviation of sample 1352 double sampleUQ; ///< upper quartile of sample 1353 double sampleLQ; ///< lower quartile of sample 1354 double robustMean; ///< robust mean of array 1355 double robustMeanError; ///< error on robust mean 1356 int robustMeanNvalues; ///< number of measurements used for robust mean 1357 double robustMedian; ///< robust median of array 1358 double robustMedianError; ///< error on robust median 1359 int robustMedianNvalues; ///< number of measurements used for robust median 1360 double robustMode; ///< Robust mode of array 1361 double robustModeErr; ///< Error in robust mode 1362 int robustModeNvalues; ///< Number of measurements used for robust mode 1363 double robustStdev; ///< robust standard deviation of array 1364 double robustUQ; ///< robust upper quartile 1365 double robustLQ; ///< robust lower quartile 1366 double clippedMean; ///< Nsigma clipped mean 1367 double clippedMeanError; ///< error on clipped mean 1368 int clippedMeanNvalues; ///< number of data points used for clipped mean 1369 double clippedStdev; ///< standard deviation after clipping 1370 double clipSigma; ///< Nsigma used for clipping; user input 1371 int clipIter; ///< Number of clipping iterations; user input 1372 double min; ///< minimum data value in array 1373 double max; ///< maximum data value in array 1374 int nValues; ///< number of data values in array 1375 psStatsOptions options; ///< bitmask of calculated values 1295 1376 } psStats; 1296 1377 \end{verbatim} … … 1305 1386 /** Histograms */ 1306 1387 typedef struct { 1307 const psFloatArray *restrict lower; // !< Lower bounds for the bins1308 const psFloatArray *restrict upper; // !< Upper bounds for the bins1309 psIntArray *nums; // !< Number in each of the bins1310 const float minVal, maxVal; // !< Minimum and maximum values1311 int minNum, maxNum; // !< Number below the minimum and above the maximum1388 const psFloatArray *restrict lower; ///< Lower bounds for the bins 1389 const psFloatArray *restrict upper; ///< Upper bounds for the bins 1390 psIntArray *nums; ///< Number in each of the bins 1391 const float minVal, maxVal; ///< Minimum and maximum values 1392 int minNum, maxNum; ///< Number below the minimum and above the maximum 1312 1393 } psHistogram; 1313 1394 \end{verbatim} … … 1321 1402 /** Constructor */ 1322 1403 psHistogram * 1323 psHistogramAlloc(float lower, // !< Lower limit for the bins1324 float upper, // !< Upper limit for the bins1325 float size // !< Size of the bins1404 psHistogramAlloc(float lower, ///< Lower limit for the bins 1405 float upper, ///< Upper limit for the bins 1406 float size ///< Size of the bins 1326 1407 ); 1327 1408 \end{verbatim} … … 1330 1411 /** Generic constructor */ 1331 1412 psHistogram * 1332 psHistogramAllocGeneric(const psFloatArray *restrict lower, // !< Lower bounds for the bins1333 const psFloatArray *restrict upper, // !< Upper bounds for the bins1334 float minVal, // !< Minimum value1335 float maxVal // !< Maximum value1413 psHistogramAllocGeneric(const psFloatArray *restrict lower, ///< Lower bounds for the bins 1414 const psFloatArray *restrict upper, ///< Upper bounds for the bins 1415 float minVal, ///< Minimum value 1416 float maxVal ///< Maximum value 1336 1417 ); 1337 1418 \end{verbatim} … … 1340 1421 /** Destructor */ 1341 1422 void 1342 psHistogramFree(psHistogram *restrict myHist // !< Histogram to destroy1423 psHistogramFree(psHistogram *restrict myHist ///< Histogram to destroy 1343 1424 ); 1344 1425 \end{verbatim} … … 1354 1435 /** A matrix */ 1355 1436 typedef struct { 1356 int xSize, ySize; // !< Dimensions in x and y1357 float *restrict *restrict value; // !< Values in matrix1437 int xSize, ySize; ///< Dimensions in x and y 1438 float *restrict *restrict value; ///< Values in matrix 1358 1439 } psMatrix; 1359 1440 \end{verbatim} … … 1364 1445 /** Constructor */ 1365 1446 psMatrix * 1366 psMatrixAlloc(int Xdimen, // !< x dimension of new matrix1367 int Ydimen // !< y dimension of new matrix1447 psMatrixAlloc(int Xdimen, ///< x dimension of new matrix 1448 int Ydimen ///< y dimension of new matrix 1368 1449 ); 1369 1450 \end{verbatim} … … 1372 1453 /** Destructor */ 1373 1454 void 1374 psMatrixFree(psMatrix *restrict myMatrix // !< Matrix to destroy1455 psMatrixFree(psMatrix *restrict myMatrix ///< Matrix to destroy 1375 1456 ); 1376 1457 \end{verbatim} … … 1389 1470 /** Invert matrix. Not using restrict, to allow inversion to be done in-place */ 1390 1471 psMatrix * 1391 psMatrixInvert(psMatrix *out, // !< Matrix to return, or NULL1392 const psMatrix *myMatrix, // !< Matrix to be inverted1393 float *restrict determinant // !< Determinant to return, or NULL1472 psMatrixInvert(psMatrix *out, ///< Matrix to return, or NULL 1473 const psMatrix *myMatrix, ///< Matrix to be inverted 1474 float *restrict determinant ///< Determinant to return, or NULL 1394 1475 ); 1395 1476 \end{verbatim} … … 1405 1486 /** Matrix operations */ 1406 1487 psMatrix * 1407 psMatrixOp(psMatrix *out, // !< Matrix to return, or NULL1408 const psMatrix *matrix1, // !< Matrix 11409 const char *op, // !< Operation to perform1410 const psMatrix *matrix2 // !< Matrix 21488 psMatrixOp(psMatrix *out, ///< Matrix to return, or NULL 1489 const psMatrix *matrix1, ///< Matrix 1 1490 const char *op, ///< Operation to perform 1491 const psMatrix *matrix2 ///< Matrix 2 1411 1492 ); 1412 1493 \end{verbatim} … … 1415 1496 /** Transpose Matrix */ 1416 1497 psMatrix * 1417 psMatrixTranspose(psMatrix *out, // !< Matrix to return, or NULL1418 const psMatrix *myMatrix // !< Matrix to transpose1498 psMatrixTranspose(psMatrix *out, ///< Matrix to return, or NULL 1499 const psMatrix *myMatrix ///< Matrix to transpose 1419 1500 ); 1420 1501 \end{verbatim} … … 1423 1504 /** Convert matrix to vector. Intended for a 1-d matrix. */ 1424 1505 psVector * 1425 psMatrixToVector(psMatrix *myMatrix // !< Matrix to convert1506 psMatrixToVector(psMatrix *myMatrix ///< Matrix to convert 1426 1507 ); 1427 1508 \end{verbatim} … … 1573 1654 is not a Gaussian deviate. The evaluated Gaussian is: \f[ exp(-\frac{(x-mean)^2}{2\sigma^2}) \f] */ 1574 1655 float 1575 psGaussian(float x, // !< Value at which to evaluate1576 float mean, // !< Mean for the Gaussian1577 float stddev // !< Standard deviation for the Gaussian1656 psGaussian(float x, ///< Value at which to evaluate 1657 float mean, ///< Mean for the Gaussian 1658 float stddev ///< Standard deviation for the Gaussian 1578 1659 ); 1579 1660 \end{verbatim} … … 1583 1664 floating-point (for speed) and double-precision (for milli-arcsec 1584 1665 precision) versions. This comes from the need to fit over $x$,$y$, 1585 colo ur and magnitude simultaneously. We must also be able to1666 color and magnitude simultaneously. We must also be able to 1586 1667 calculate the errors in the fit coefficients, as well as be able to 1587 1668 turn on and off each coefficient. This leads us to define polynomial … … 1591 1672 /** One-dimensional polynomial */ 1592 1673 typedef struct { 1593 int n; // !< Number of terms1594 float *restrict coeff; // !< Coefficients1595 float *restrict coeffErr; // !< Error in coefficients1596 char *restrict mask; // !< Coefficient mask1674 int n; ///< Number of terms 1675 float *restrict coeff; ///< Coefficients 1676 float *restrict coeffErr; ///< Error in coefficients 1677 char *restrict mask; ///< Coefficient mask 1597 1678 } psPolynomial1D; 1598 1679 \end{verbatim} … … 1601 1682 /** Two-dimensional polynomial */ 1602 1683 typedef struct { 1603 int nX, nY; // !< Number of terms in x and y1604 float *restrict *restrict coeff; // !< Coefficients1605 float *restrict *restrict coeffErr; // !< Error in coefficients1606 char *restrict *restrict mask; // !< Coefficients mask1684 int nX, nY; ///< Number of terms in x and y 1685 float *restrict *restrict coeff; ///< Coefficients 1686 float *restrict *restrict coeffErr; ///< Error in coefficients 1687 char *restrict *restrict mask; ///< Coefficients mask 1607 1688 } psPolynomial2D; 1608 1689 \end{verbatim} … … 1613 1694 /** Double-precision one-dimensional polynomial */ 1614 1695 typedef struct { 1615 int n; // !< Number of terms1616 double *restrict coeff; // !< Coefficients1617 double *restrict coeffErr; // !< Error in coefficients1618 char *restrict mask; // !< Coefficient mask1696 int n; ///< Number of terms 1697 double *restrict coeff; ///< Coefficients 1698 double *restrict coeffErr; ///< Error in coefficients 1699 char *restrict mask; ///< Coefficient mask 1619 1700 } psDPolynomial1D; 1620 1701 \end{verbatim} … … 1623 1704 /** Double-precision two-dimensional polynomial */ 1624 1705 typedef struct { 1625 int nX, nY; // !< Number of terms in x and y1626 double *restrict *restrict coeff; // !< Coefficients1627 double *restrict *restrict coeffErr; // !< Error in coefficients1628 char *restrict *restrict mask; // !< Coefficients mask1706 int nX, nY; ///< Number of terms in x and y 1707 double *restrict *restrict coeff; ///< Coefficients 1708 double *restrict *restrict coeffErr; ///< Error in coefficients 1709 char *restrict *restrict mask; ///< Coefficients mask 1629 1710 } psDPolynomial2D; 1630 1711 \end{verbatim} … … 1636 1717 The constructor and destructor are: 1637 1718 \begin{verbatim} 1638 psDPolynomial2D *psDPolynomial2DAlloc(int nX, int nY // !< Number of terms in x and y1639 ); 1640 void psDPolynomial2DFree(psDPolynomial2D *restrict myPoly // !< Polynomial to destroy1719 psDPolynomial2D *psDPolynomial2DAlloc(int nX, int nY ///< Number of terms in x and y 1720 ); 1721 void psDPolynomial2DFree(psDPolynomial2D *restrict myPoly ///< Polynomial to destroy 1641 1722 ); 1642 1723 \end{verbatim} … … 1647 1728 /** Evaluate 2D polynomial (double precision) */ 1648 1729 double 1649 psEvalDPolynomial2D(double x, // !< Value x at which to evaluate1650 double y, // !< Value y at which to evaluate1651 const psDPolynomial2D *restrict myPoly // !< Coefficients for the polynomial1730 psEvalDPolynomial2D(double x, ///< Value x at which to evaluate 1731 double y, ///< Value y at which to evaluate 1732 const psDPolynomial2D *restrict myPoly ///< Coefficients for the polynomial 1652 1733 ); 1653 1734 \end{verbatim} 1654 1735 1736 \tbd{generate a Gaussian deviate vector} 1737 1655 1738 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1656 1739 1657 1740 \subsection{Minimization and fitting routines} 1658 1741 1659 We require a general minimi sation routine, a routine that will1660 specifically minimi se $\chi^2$ given a list of data with associated1742 We require a general minimization routine, a routine that will 1743 specifically minimize $\chi^2$ given a list of data with associated 1661 1744 errors, and a function that will analytically determine the polynomial 1662 1745 fit by least-squares. The APIs are: … … 1665 1748 /** Minimize a particular function */ 1666 1749 psFloatArray * 1667 psMinimize(float (*myFunction)(const psFloatArray *restrict), // !< Function to minimize1668 psFloatArray *restrict initialGuess // !< Initial guess1750 psMinimize(float (*myFunction)(const psFloatArray *restrict), ///< Function to minimize 1751 psFloatArray *restrict initialGuess ///< Initial guess 1669 1752 ); 1670 1753 \end{verbatim} … … 1674 1757 psFloatArray * 1675 1758 psMinimizeChi2(float (*evalModel)(const psFloatArray *restrict, 1676 const psFloatArray *restrict), // !< Model to fit; receives domain and1677 // !< parameters1678 const psFloatArray *restrict domain, // !< The domain values for the corresponding measurements1679 const psFloatArray *restrict data, // !< Data to fit1680 const psFloatArray *restrict errors, // !< Errors in the data1681 psFloatArray *restrict initialGuess, // !< Initial guess1682 const psIntArray *restrict guessMask // !< 1 = fit for parameter, 0 = hold parameter constant1759 const psFloatArray *restrict), ///< Model to fit; receives domain and 1760 ///< parameters 1761 const psFloatArray *restrict domain, ///< The domain values for the corresponding measurements 1762 const psFloatArray *restrict data, ///< Data to fit 1763 const psFloatArray *restrict errors, ///< Errors in the data 1764 psFloatArray *restrict initialGuess, ///< Initial guess 1765 const psIntArray *restrict guessMask ///< 1 = fit for parameter, 0 = hold parameter constant 1683 1766 ); 1684 1767 \end{verbatim} … … 1687 1770 /** Derive a polynomial that goes through the points --- can be done analytically */ 1688 1771 psFloatArray * 1689 psGetArrayPolynomial(const psFloatArray *restrict ord, // !< Ordinates (or NULL to just use the indices)1690 const psFloatArray *restrict coord // !< Coordinates1772 psGetArrayPolynomial(const psFloatArray *restrict ord, ///< Ordinates (or NULL to just use the indices) 1773 const psFloatArray *restrict coord ///< Coordinates 1691 1774 ); 1692 1775 \end{verbatim} … … 1718 1801 psF32 **rows_f32; ///< pointers to psF32 data 1719 1802 psF64 **rows_f64; ///< pointers to psF64 data 1720 psComplex **rows_complex; // !< pointers to psComplex data1803 psComplex **rows_complex; ///< pointers to psComplex data 1721 1804 } rows; 1722 1805 psImage *parent; ///< parent, if a subimage … … 1732 1815 restricted to the datatypes equivalent to the valid BITPIX values 8, 1733 1816 16, 32, -32, -64). The image represented in the data structure may 1734 represent a subset of the pixels in a complete array. The offset of 1735 the \code{(0,0)} pixel in this array relative to the parent array is 1736 given by the elements \code{(x0,y0)}. The structure may include 1737 references to subrasters (\code{children, Nchildren}) and/or to a 1738 containing array (\code{parent}). 1817 represent a subset of the pixels in a complete array, in which case 1818 the image is considered to be the child of that parent array. The 1819 offset of the \code{(0,0)} pixel in this array relative to the parent 1820 array is given by the elements \code{(x0,y0)}. The structure may 1821 include references to subrasters (\code{children, Nchildren}) and/or 1822 to a containing array (\code{parent}). 1739 1823 1740 1824 We require a variety of functions to manipulate these image … … 1759 1843 /// Create a subimage of the specified area. 1760 1844 psImage * 1761 psImageSubset(psImage *out, // !< Subimage to return, or NULL1845 psImageSubset(psImage *out, ///< Subimage to return, or NULL 1762 1846 const psImage *image, ///< parent image 1763 1847 int nx, ///< subimage width (<= image.nx - x0) … … 1779 1863 \begin{verbatim} 1780 1864 psImage * 1781 psImageFreePixels(psImage *restrict image // !< Image whose pixels are to be freed1865 psImageFreePixels(psImage *restrict image ///< Image whose pixels are to be freed 1782 1866 ); 1783 1867 \end{verbatim} … … 1810 1894 \begin{verbatim} 1811 1895 psFloatArray * 1812 psImageSlice(psFloatArray *out, // !< Vector to output, or NULL1896 psImageSlice(psFloatArray *out, ///< Vector to output, or NULL 1813 1897 const psImage *input, ///< extract slice from this image 1814 1898 int x, ///< starting x coord of region to slice … … 1832 1916 \begin{verbatim} 1833 1917 psFloatArray * 1834 psImageCut(psFloatArray *out, // !< Vector to output, or NULL1918 psImageCut(psFloatArray *out, ///< Vector to output, or NULL 1835 1919 const psImage *input, ///< extract cut from this image 1836 1920 float xs, ///< starting x coord of cut … … 1844 1928 1845 1929 1846 Extract radial annuli idata to a vector. A vector is constructed1930 Extract radial annuli data to a vector. A vector is constructed 1847 1931 where each vector elements is derived from the statistics of the 1848 pixels which land in one of a sequence of annuli i. The annulii are1932 pixels which land in one of a sequence of annuli. The annuli are 1849 1933 centered on the image pixel coordinate \code{x,y}, and have width 1850 \code{dr}. The number of annuli iis $radius / dr$. The statistic1934 \code{dr}. The number of annuli is $radius / dr$. The statistic 1851 1935 used to derive the output vector value is specified by \code{psStats 1852 1936 stats} 1853 1937 \begin{verbatim} 1854 1938 psFloatArray * 1855 psImageRadialCut(psFloatArray *out, // !< Vector to output, or NULL1939 psImageRadialCut(psFloatArray *out, ///< Vector to output, or NULL 1856 1940 const psImage *input, ///< extract profile from this image 1857 1941 float x, ///< center x coord of annulii … … 1872 1956 \begin{verbatim} 1873 1957 psImage * 1874 psImageRebin(psImage *out, // !< Image to output, or NULL1958 psImageRebin(psImage *out, ///< Image to output, or NULL 1875 1959 const psImage *input, ///< rebin this image 1876 1960 float scale, ///< rebinning scale: doutput = scale*dinput … … 1887 1971 \begin{verbatim} 1888 1972 psImage * 1889 psImageRotate(psImage *out, // !< Image to output, or NULL1973 psImageRotate(psImage *out, ///< Image to output, or NULL 1890 1974 const psImage *input, ///< rotate this image 1891 1975 float angle ///< rotate by this amount anti-clockwise (degrees) … … 1897 1981 values should interpolate between the input pixel values. The output 1898 1982 image has the same dimensions as the input image. Pixels which fall 1899 off the edge of the output image are lo ast. Newly exposed pixels are1983 off the edge of the output image are lost. Newly exposed pixels are 1900 1984 set to the value given by \code{exposed}. 1901 1985 \begin{verbatim} 1902 1986 psImage * 1903 psImageShift(psImage *out, // !< Image to output, or NULL1987 psImageShift(psImage *out, ///< Image to output, or NULL 1904 1988 const psImage *input, ///< shift this image 1905 1989 float dx, ///< shift by this amount in x … … 1914 1998 \begin{verbatim} 1915 1999 psImage * 1916 psImageRoll(psImage *out, // !< Image to output, or NULL2000 psImageRoll(psImage *out, ///< Image to output, or NULL 1917 2001 const psImage *input, ///< roll this image 1918 2002 int dx, ///< roll this amount in x … … 1941 2025 Fit a 2-D polynomial surface to an image. The input structure 1942 2026 \code{coeffs} contains the desired order and terms of interest. 1943 \tbd{how do we specify the reno malization?}2027 \tbd{how do we specify the renormalization?} 1944 2028 \begin{verbatim} 1945 2029 psPolynomial2D * … … 2008 2092 2009 2093 Write an image section to named file, which may exist. This 2010 operat ation may write a portion of an image over the existing bytes of2094 operation may write a portion of an image over the existing bytes of 2011 2095 an existing image. If the file does not exist, it should be created. 2012 2096 If the specified extension does not exist, it should be created. If … … 2067 2151 \begin{verbatim} 2068 2152 psImage * 2069 psImageFFT(psImage *output, // !< Output image2153 psImageFFT(psImage *output, ///< Output image 2070 2154 const psImage *input, ///< image to FFT 2071 2155 int direction ///< FFT direction … … 2198 2282 \section{Astronomy-Specific Functions} 2199 2283 2200 Some basic, relatively simple astronomy-specific functions are 2201 required which will serve as the foundation for building the Phase $N$ 2202 modules. These functions are not expected to cover every forseeable 2203 function, but will serve as the building blocks of more complicated 2204 processing functions. 2284 The previous sections of this document defined basic functionality 2285 needed by a wide range of scientific programming. The rest of this 2286 document concentrates on aspects of the library which are specific to 2287 astronomy. Some basic, relatively simple astronomy-specific functions 2288 are required which will serve as the foundation for building the 2289 higher level modules. These functions are not expected to cover every 2290 foreseeable function, but will serve as the building blocks of more 2291 complicated processing functions. 2205 2292 2206 2293 We require functions covering each of the following areas: 2207 2294 \begin{itemize} 2208 \item Astrometry;2209 \item Dates and times;2210 \item Image handling;2211 \item Metadata;2212 \item Detector and sky positions;2213 \item Astronomical objects; and2214 \item Photometry.2295 \item Dates and times 2296 \item Metadata 2297 \item Detector and sky positions 2298 \item Astronomy Image 2299 \item Astrometry 2300 \item Photometry 2301 \item Astronomical objects 2215 2302 \end{itemize} 2216 These are each dealt with below.2217 2303 2218 2304 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% … … 2224 2310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2225 2311 2226 \subsection{Detector and sky positions}2227 2228 Both detector and sky positions will be used extensively in the IPP.2229 Since these both contain two coordinates with their associated errors,2230 we bundle these into a single generic structure, \code{psCoord},2231 containing \code{union}s to handle the semantic differences.2232 2233 \begin{verbatim}2234 /** A point in 2-D space, with errors.2235 */2236 typedef union {2237 struct {2238 double x; //!< x position2239 double y; //!< y position2240 double xErr; //!< Error in x position2241 double yErr; //!< Error in y position2242 } xy;2243 struct {2244 double r; //!< RA2245 double d; //!< Dec2246 double rErr; //!< Error in RA2247 double dErr; //!< Error in Dec2248 } rd;2249 } psCoord;2250 \end{verbatim}2251 2252 \subsubsection{Transformations}2253 2254 We specify two types of transforms between coordinate systems. The2255 first consists simply of two 2D polynomials to transform both2256 components; this will be used to apply the coordinate transformations2257 between Cells, Chips and the Focal Plane. The second consists of two2258 4D polynomials; this will be used to apply position-, colour- and2259 magnitude-dependent distortions between the Focal Plane and the2260 Tangent Plane.2261 2262 \begin{verbatim}2263 /** A polynomial transformation between coordinate frames. This may be a linear relationship, or may2264 * represent a higher-order transformation.2265 */2266 typedef struct {2267 psDPolynomial2D *x;2268 psDPolynomial2D *y;2269 } psCoordXform;2270 \end{verbatim}2271 2272 \begin{verbatim}2273 /** The optical distortion terms. The lowest two terms are the x and y axis of the target system. The higher2274 * two terms represent magnitude and color terms.2275 */2276 typedef struct {2277 psDPolynomial4D *x;2278 psDPolynomial4D *y;2279 } psDistortion;2280 \end{verbatim}2281 2282 We require corresponding functions to apply the transformations:2283 2284 \begin{verbatim}2285 /** apply the coordinate transformation to the given coordinate */2286 psCoord *psCoordXformApply (psCoord *out, //!< Output coordinates, or NULL2287 const psCoordXform *frame, ///< coordinate transformation2288 const psCoord *coords ///< input coordiate2289 );2290 \end{verbatim}2291 2292 \begin{verbatim}2293 /** apply the optical distortion to the given coordinate, magnitude, color */2294 psCoord *psDistortionApply (psCoord *out, //!< Output coordinates, or NULL2295 const psdistortion *pattern, ///< optical distortion pattern2296 const psCoord *coords, ///< input coordinate2297 float mag, ///< magnitude of object2298 float color ///< color of object2299 );2300 \end{verbatim}2301 2302 2303 \subsubsection{Offsets}2304 2305 We require a function to calculate the offset between two positions on2306 the sky, as well as a function to apply an offset to a position.2307 2308 \begin{verbatim}2309 /** Get offset (RA,Dec) on the sky between two positions position1 and position2 may not be identical */2310 psCoord *2311 psGetOffset(const psCoord *restrict position1, //!< Position 12312 const psCoord *restrict position2, //!< Position 22313 const char *type //!< Type of offset: Linear, Spherical/Arcsec, Spherical/Degreees etc2314 );2315 \end{verbatim}2316 2317 \begin{verbatim}2318 /** Apply an offset to a position */2319 psCoord *2320 psApplyOffset(const psCoord *restrict position, //!< Position2321 const psCoord *restrict offset, //!< Offset2322 const char *type //!< Type of offset: Linear, Spherical/Arcsec, Spherical/Degreees etc2323 );2324 \end{verbatim}2325 2326 2327 \subsubsection{Positions of Major SS Objects}2328 2329 We require the ability to calculate the position of major Solar System2330 objects, as well as Lunar phase.2331 2332 \begin{verbatim}2333 /** Get Sun Position */2334 psCoord *2335 psGetSunPos(float mjd //!< MJD to get position for2336 );2337 \end{verbatim}2338 2339 \begin{verbatim}2340 /** Get Moon position */2341 psCoord *2342 psGetMoonPos(float mjd, //!< MJD to get position for2343 double latitude, //!< Latitude for apparent position2344 double longitude //!< Longitude for apparent position2345 );2346 \end{verbatim}2347 2348 \begin{verbatim}2349 /** Get Moon phase */2350 float2351 psGetMoonPhase(float mjd //!< MJD to get phase for2352 );2353 \end{verbatim}2354 2355 \begin{verbatim}2356 /** Get Planet positions */2357 psCoord *2358 psGetSolarSystemPos(const char *solarSystemObject, //!< Named S.S. object2359 float mjd //!< MJD to get position for2360 );2361 \end{verbatim}2362 2363 \subsubsection{Celestial Coordinate Conversions}2364 2365 We need to be able to convert between ICRS, Galactic and Ecliptic2366 coordinates.2367 2368 \begin{verbatim}2369 /** Convert ICRS to Ecliptic */2370 psCoord *2371 psCoordinatesItoE(const psCoord *restrict coordinates //!< ICRS coordinates to convert2372 );2373 \end{verbatim}2374 2375 \begin{verbatim}2376 /** Convert Ecliptic to ICRS */2377 psCoord *2378 psCoordinatesEtoI(const psCoord *restrict coordinates //!< Ecliptic coordinates to convert2379 );2380 \end{verbatim}2381 2382 \begin{verbatim}2383 /** Convert ICRS to Galactic */2384 psCoord *2385 psCoordinatesItoG(const psCoord *restrict coordinates //!< ICRS coordinates to convert2386 );2387 \end{verbatim}2388 2389 \begin{verbatim}2390 /** Convert Galactic to ICRS */2391 psCoord *2392 psCoordinatesGtoI(const psCoord *restrict coordinates //!< Galactic coordinates to convert2393 );2394 \end{verbatim}2395 2396 2397 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%2398 2399 2312 \subsection{Metadata} 2313 2314 \subsubsection{Conceptual Overview} 2315 2316 Within PSLib, we provide a data structure to carry metadata and 2317 mechanisms to manipulate the metadata. Metadata is a general concept 2318 that requires some discussion. In any data analysis task, the 2319 ensemble of all possible data may be divided into two or three 2320 classes: there is the specific data of interest, there is data which 2321 is related or critical but not the primary data of interest, and there 2322 is all of the other data which may or may not be interesting. For 2323 example, consider a simple 2D image obtained of a galaxy from a CCD 2324 camera on a telescope. If you want to study the galaxy, the specific 2325 data of interest is the collection of pixels. There are a variety of 2326 other pieces of data which are closely related and crucial to 2327 understanding the data in those pixels, such as the dimensions of the 2328 image, the coordinate system, the time of the image, the exposure 2329 time, and so forth. Other data may be known which may be less 2330 critical to understanding the image, but which may be interesting or 2331 desired at a later date. For example, the observer who took the 2332 image, the filter manufacturer, the humidity at the telescope, etc. 2333 2334 Formally, all of the related data which describe the principal data of 2335 interest are metadata. Note that which piece is the metadata and 2336 which is the data may depend on the context. If you are examining the 2337 pixels in an image, the coordinate and flux of an object may be part 2338 of the metadata. However, if you are analyzing a collection of 2339 objects extracted from an image, you may consider then pixel data 2340 simply part of the metadata associated with the list of objects. 2341 2342 There are various ways to handle metadata vs data within a programming 2343 environment. In C, it is convenient to use structures to group 2344 associated data together. One possibility is to define the metadata 2345 as part of the associated data structure. For example, the image data 2346 structure would have elements for all possible associated measurement. 2347 This approach is both cumbersome (because of the large number metadata 2348 types), impractical (because the full range of necessary metadata is 2349 difficult to know in advance) and inflexible (because any change in 2350 the collection of metadata requires addition of new structure elements 2351 and recompilation). 2352 2353 An alternative is to place the metadata in a generic container and use 2354 lookup mechanisms to extract the appropriate metadata when needed. An 2355 example of this is would be a text-based FITS header for an image read 2356 into a flat text buffer. In this implementation, metadata lookup 2357 functions could return the current value of, for example, NAXIS1 (the 2358 number of columns of the image) by scanning through the header buffer. 2359 This method has the benefits of flexibility and simplicity of 2360 programming interface, but it has the disadvantage that all metadata 2361 is accessed though this lookup mechanism. This may make the code less 2362 readable and it may slow down the access. 2363 2364 We propose an intermediate solution to this problem. We specify a 2365 flexible, generic metadata container and access methods. Data types 2366 which require access to a general collection of metadata should 2367 include an entry of this metadata type. However, a subset of metadata 2368 concepts which are basic and frequently required may be placed in the 2369 coded structure elements. This approach allows the code to refer to 2370 the basic metadata concepts as part of the data structure (ie, 2371 image.nx), but also allows us to provide access to any arbitrary 2372 metadata which may be generated. As a practical matter, the choice of 2373 which entries are only in the metadata and which are part of the 2374 explicit structure elements is rather subjective. Any data elements 2375 which are frequently used should be put in the structure; those which 2376 are only infrequently needed should be left in the generic metadata. 2377 2378 There are some points of caution which must be noted. Any 2379 manipulation of the data should be reflected in the metadata where 2380 appropriate. This is always an issue of concern. For example, 2381 consider an image of dimensions \code{Nx, Ny}. If a function extracts 2382 a subraster, it must change the values of \code{Nx, Ny} to match the 2383 new dimensions. What should it do to the corresponding metadata? 2384 Clearly, it should change the corresponding value which defines 2385 \code{Nx, Ny}. However, it is not quite so simple: there may be other 2386 metadata values which depend on those values. These must also be 2387 changed appropriately. What if the metadata element points to a 2388 copy of the metadata which may be shared by other representations of 2389 the image? These must be treated differently because the change would 2390 invalidate those other references. 2391 2392 A related issue is the definition of metadata names. Entries in a 2393 structure have the advantage of being hardwired: every instance of 2394 that structure will have the same name for the same entry. This is 2395 not necessarily the case with a more flexible metadata container. The 2396 image exposure time is a notorious example in astronomy. Different 2397 observatories use different header keywords (ie, metadata names) for 2398 the same concept of the exposure time (EXPTIME, EXPOSURE, OPENTIME, 2399 INTTIME, etc). Any system which operates on these metadata needs to 2400 address the issue of identifying these names. This issue seems like an 2401 argument for hardwiring metadata in the structure, but in fact it does 2402 not present such a strong case. If the metadata are hardwired, some 2403 function will still have to know how to interpret the various names to 2404 populate the structure. The concept can still be localized with 2405 generic metadata containers by including abstract metadata names 2406 within the code which are tied to the various implementations-specific 2407 metadata names. 2408 2409 \subsubsection{Metadata Representation} 2400 2410 2401 2411 This section addresses the question of how \PS{} metadata should be … … 2403 2413 represented on disk. 2404 2414 2405 \subsubsection{Metadata Representation}2406 2407 2415 We propose that an item of metadata be represented as a C structure with at least the following 2408 2416 fields: … … 2410 2418 /** A struct to define a single item of metadata */ 2411 2419 typedef struct { 2412 const int id; // !< unique ID for this item2413 char *restrict name; // !< Name of item2414 psMetaDataType type; // !< type of this item2415 psMetaDataFlags flags; // !< flags associated with this item2420 const int id; ///< unique ID for this item 2421 char *restrict name; ///< Name of item 2422 psMetaDataType type; ///< type of this item 2423 psMetaDataFlags flags; ///< flags associated with this item 2416 2424 const union { 2417 float f; // !< floating value2418 int i; // !< integer value2419 void *v; // !< other type2420 } val; // !< value of metadata2421 char *comment; // !< optional comment ("", not NULL)2422 psDlist *restrict items; // !< list of psMetaDataItems with the same name2425 float f; ///< floating value 2426 int i; ///< integer value 2427 void *v; ///< other type 2428 } val; ///< value of metadata 2429 char *comment; ///< optional comment ("", not NULL) 2430 psDlist *restrict items; ///< list of psMetaDataItems with the same name 2423 2431 } psMetaDataItem; 2424 2432 \end{verbatim} … … 2437 2445 \begin{verbatim} 2438 2446 /** Possible types of metadata. */ 2439 typedef enum { // !< type of val is:2440 PS_META_ITEM_SET = 0, // !< NULL; metadata is in psMetaDataType.items2441 PS_META_FLOAT, // !< float (.f)2442 PS_META_INT, // !< int (.i)2443 PS_META_STR, // !< string (.v)2444 PS_META_IMG, // !< image (.v)2445 PS_META_JPEG, // !< JPEG (.v)2446 PS_META_PNG, // !< PNG (.v)2447 PS_META_ASTROM, // !< astrometric coefficients (.v)2448 PS_META_UNKNOWN, // !< other (.v)2449 PS_META_NTYPE // !< Number of types; must be last2447 typedef enum { ///< type of val is: 2448 PS_META_ITEM_SET = 0, ///< NULL; metadata is in psMetaDataType.items 2449 PS_META_FLOAT, ///< float (.f) 2450 PS_META_INT, ///< int (.i) 2451 PS_META_STR, ///< string (.v) 2452 PS_META_IMG, ///< image (.v) 2453 PS_META_JPEG, ///< JPEG (.v) 2454 PS_META_PNG, ///< PNG (.v) 2455 PS_META_ASTROM, ///< astrometric coefficients (.v) 2456 PS_META_UNKNOWN, ///< other (.v) 2457 PS_META_NTYPE ///< Number of types; must be last 2450 2458 } psMetaDataType; 2451 2459 \end{verbatim} … … 2455 2463 \textbf{Value} & \textbf{Type} & \textbf{member of union} & \textbf{Comments}\\ 2456 2464 \hline 2457 \code{PS_META_FLOAT} & float& f & value, not pointer, is stored \\2458 \code{PS_META_INT} & int & i &value, not pointer, is stored \\2459 \code{PS_META_STR} & string & v &value, not pointer to original, is stored \\2460 \code{PS_META_IMG} & psImage & v &\\2461 \code{PS_META_JPEG} & JPEG & v &\\2462 \code{PS_META_PNG} & PNG & v &\\2463 \code{PS_META_ASTROM} & psAstrom & v &\\2464 \code{ \code{PS_META_UNKNOWN} & other & v &\\2465 PS_META_NTYPE} & (none) && The number of types defined2465 \code{PS_META_FLOAT} & float & f & value, not pointer, is stored \\ 2466 \code{PS_META_INT} & int & i & value, not pointer, is stored \\ 2467 \code{PS_META_STR} & string & v & value, not pointer to original, is stored \\ 2468 \code{PS_META_IMG} & psImage & v & \\ 2469 \code{PS_META_JPEG} & JPEG & v & \\ 2470 \code{PS_META_PNG} & PNG & v & \\ 2471 \code{PS_META_ASTROM} & psAstrom & v & \\ 2472 \code{PS_META_UNKNOWN} & other & v & \\ 2473 \code{PS_META_NTYPE} & (none) & & The number of types defined 2466 2474 \end{tabular} 2467 2475 \begin{caption}{Supported Metadata Types} … … 2476 2484 /** A set of metadata */ 2477 2485 typedef struct { 2478 psDlist *restrict list; // !< list of psMetaDataItem2479 psHash *restrict table; // !< hash table of the same metadata2486 psDlist *restrict list; ///< list of psMetaDataItem 2487 psHash *restrict table; ///< hash table of the same metadata 2480 2488 } psMetaDataSet; 2481 2489 \end{verbatim} … … 2559 2567 \begin{verbatim} 2560 2568 /** Constructor */ 2561 psMetaDataItem *psMetaDataItemAlloc(int typeFlags, // !< type of this piece of metadata + flags2562 const void *val, // !< value of new item N.b. a pointer even if the item2563 // !< is of type e.g. int2564 const char *comment, // !< comment associated with item2565 const char *name, // !< name of new item of metadata (may be in sprintf2566 // !< format)2567 ... // !< possible arguments for name format2569 psMetaDataItem *psMetaDataItemAlloc(int typeFlags, ///< type of this piece of metadata + flags 2570 const void *val, ///< value of new item N.b. a pointer even if the item 2571 ///< is of type e.g. int 2572 const char *comment, ///< comment associated with item 2573 const char *name, ///< name of new item of metadata (may be in sprintf 2574 ///< format) 2575 ... ///< possible arguments for name format 2568 2576 ); 2569 2577 2570 2578 /** Destructor */ 2571 void psMetaDataItemFree(psMetaDataItem *ms // !< piece of metadata to destroy2579 void psMetaDataItemFree(psMetaDataItem *ms ///< piece of metadata to destroy 2572 2580 ); 2573 2581 /** Constructor */ 2574 psMetaDataSet *psMetaDataSetAlloc(void); // !< make a new set of metadata2582 psMetaDataSet *psMetaDataSetAlloc(void); ///< make a new set of metadata 2575 2583 2576 2584 /** Destructor */ 2577 void psMetaDataSetFree(psMetaDataSet *ms // !< destroy a set of metadata2585 void psMetaDataSetFree(psMetaDataSet *ms ///< destroy a set of metadata 2578 2586 ); 2579 2587 … … 2581 2589 2582 2590 /// Add entry to the end of the metadata set 2583 psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, // !< Metadata set to add to2584 psMetaDataItem *restrict item // !< Metatdata to add2591 psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, ///< Metadata set to add to 2592 psMetaDataItem *restrict item ///< Metatdata to add 2585 2593 ); 2586 2594 2587 2595 /// delete entry from the metadata set 2588 psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, // !< Metadata set to delete from2589 const char *restrict key // !< Key to delete2596 psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, ///< Metadata set to delete from 2597 const char *restrict key ///< Key to delete 2590 2598 ); 2591 2599 2592 2600 /// reset the iterator to the start of the list 2593 void psMetaDataSetIterator(psMetaDataSet *ms // !< Metadata set to set iterator for2601 void psMetaDataSetIterator(psMetaDataSet *ms ///< Metadata set to set iterator for 2594 2602 ); 2595 2603 2596 2604 /// get the next entry in the sequence 2597 psMetaDataItem *psMetaDataGetNext(psMetaDataSet *restrict ms, // !< Metadata set to get from2598 const char *restrict match // !< Match this2605 psMetaDataItem *psMetaDataGetNext(psMetaDataSet *restrict ms, ///< Metadata set to get from 2606 const char *restrict match ///< Match this 2599 2607 ); 2600 2608 2601 2609 /// find the metadata with the specified key 2602 psMetaDataItem *psMetaDataLookup(const psMetaDataSet *restrict ms, // !< Metadata set to look up2603 const char *restrict key // !< Key to find2610 psMetaDataItem *psMetaDataLookup(const psMetaDataSet *restrict ms, ///< Metadata set to look up 2611 const char *restrict key ///< Key to find 2604 2612 ); 2605 2613 2606 2614 /// print metadata item to the specified stream 2607 void psMetaDataItemPrint(FILE *fd, //!< file descriptor to write to 2608 const psMetaDataItem *restrict ms, //!< item of metadata to print 2609 const char *prefix //!< print this at the beginning of each line 2610 ); 2611 \end{verbatim} 2615 void psMetaDataItemPrint(FILE *fd, ///< file descriptor to write to 2616 const psMetaDataItem *restrict ms, ///< item of metadata to print 2617 const char *prefix ///< print this at the beginning of each line 2618 ); 2619 \end{verbatim} 2620 2621 \subsection{Detector and sky positions} 2622 2623 Both detector and sky positions will be used extensively in the IPP. 2624 The first are linear coordinates which conform to Euclidean geometry 2625 while the second are angular coordinates for which additional care 2626 must often be taken. Since these both consist of two coordinates with 2627 their associated errors, we bundle these into a single generic 2628 structure, \code{psCoord}, containing \code{union}s to handle the 2629 semantic differences. A variety of functions should operate 2630 equivalently on both types of structures (\tbd{list}), while other 2631 functions must behave differently when the operand is an angular vs a 2632 linear coordinate system. 2633 2634 \begin{verbatim} 2635 /** A point in 2-D space, with errors. 2636 */ 2637 typedef union { 2638 struct { 2639 double x; ///< x position 2640 double y; ///< y position 2641 double xErr; ///< Error in x position 2642 double yErr; ///< Error in y position 2643 } xy; 2644 struct { 2645 double r; ///< RA 2646 double d; ///< Dec 2647 double rErr; ///< Error in RA 2648 double dErr; ///< Error in Dec 2649 } rd; 2650 } psCoord; 2651 \end{verbatim} 2652 2653 Three major classes of coordinate transformations are necessary. 2654 First, linear coordinates from one frame must be converted to linear 2655 coordinates in a different frame of references. Simple transformations 2656 of this type are independent of other quantities of the positions -- 2657 they are simply mapping between two linear spaces. In practice, these 2658 transformations may often be a function of the magnitude or color of 2659 the imaged object. The second type of conversion is the 2660 transformation of linear coordinates to angular coordinates and 2661 vice-versa. This conversion depends on the desired projection, and 2662 may represent the real mapping performed by the telescope or may 2663 simply represent a convenient mechanism to display 3D coordinates in 2664 useful forms. The third conversion of interest is the transformation 2665 of one set of spherical coordinates to another set. Frequently in 2666 astronomy, these conversions consist only of rotations between the two 2667 spherical coordinates systems, where the coordinates of the pole and 2668 equatorial rotation between the two systems define the 2669 transformation. Conversions between standard coordinate systems such 2670 as Galactic, Ecliptic, and various epochs of the Celestial coordinates 2671 are represented by these spherical transformations. 2672 2673 \subsubsection{Linear Coordinate Transformations} 2674 2675 We specify two types of transforms between coordinate systems. The 2676 first consists simply of two 2D polynomials to transform both 2677 components -- the output coordinates depend only on the input 2678 coordinates and no other quantities of objects at those coordinates. 2679 The second consists of two 4D polynomials in which the output 2680 coordinates are also specified to be a function of the magnitude and 2681 color of the object with the given coordinates. This type of 2682 coordinate transformation is necessary to represent the 2683 (color-dependent) optical distortions caused by the atmosphere and 2684 camera optics, and the possibly effects of charge transfer 2685 inefficiency. We specify two structures to represent the coefficients 2686 of these transformations: 2687 2688 \begin{verbatim} 2689 /** A polynomial transformation between coordinate frames. This may be a linear relationship, or may 2690 * represent a higher-order transformation. 2691 */ 2692 typedef struct { 2693 psDPolynomial2D *x; 2694 psDPolynomial2D *y; 2695 } psCoordXform; 2696 \end{verbatim} 2697 2698 The \code{psDPolynomial2D} structures represent polynomials of 2699 arbitrary order as a function of two dimensions. There is one of 2700 these structures for each of the two output dimensions. As an 2701 example, consider the simple transformation from one linear coordinate 2702 frame \code{x,y} (say a single CCD) to a second frame \code{p,q} (say, 2703 a second CCD image). If we have only first order terms in the 2704 transformation \code{psCoordXform T}, the new coordinates would be 2705 represented by the terms: 2706 % 2707 \begin{verbatim} 2708 p = T.x->coeff[0][0] + x*T.x->coeff[1][0] + y*T.x->coeff[0][1]; 2709 q = T.y->coeff[0][0] + x*T.y->coeff[1][0] + y*T.y->coeff[0][1]; 2710 \end{verbatim} 2711 % 2712 where we have excluded the basic cross-term (\code{x*y}) by using the 2713 mask: \code{T.x->mask[1][1] = 0; T.y->mask[1][1] = 0;} 2714 2715 \begin{verbatim} 2716 /** The optical distortion terms. The lowest two terms are the x and y axis of the target system. The higher 2717 * two terms represent magnitude and color terms. 2718 */ 2719 typedef struct { 2720 psDPolynomial4D *x; 2721 psDPolynomial4D *y; 2722 } psDistortion; 2723 \end{verbatim} 2724 2725 Like \code{psCoordXform}, \code{psDistortion} contains two 2726 \code{psDPolynomial4D} structures representing polynomials of 2727 arbitrary order as a function of four, rather than two dimensions. 2728 There is one of these structures for each of the two output 2729 dimensions. In this structure, the highest two dimensions could 2730 represent a magnitude and a color. As an example, consider the simple 2731 transformation from one linear coordinate frame \code{x,y} (say a 2732 single CCD) of an object with magnitude and color \code{m,c} to a 2733 second frame \code{p,q} (say, a second CCD image). If we have only 2734 first order terms in the transformation \code{psCoordXform T}, the new 2735 coordinates would be represented by the terms: 2736 % 2737 \begin{verbatim} 2738 p = T.x->coeff[0][0][0][0] + x*T.x->coeff[1][0][0][0] + y*T.x->coeff[0][1][0][0] + m*T.x->coeff[0][0][1][0] + c*T.x->coeff[0][0][0][1] 2739 q = T.y->coeff[0][0][0][0] + x*T.y->coeff[1][0][0][0] + y*T.y->coeff[0][1][0][0] + m*T.y->coeff[0][0][1][0] + c*T.y->coeff[0][0][0][1] 2740 \end{verbatim} 2741 % 2742 where we have again excluded the cross-terms (\code{x*y}) by using the 2743 mask. 2744 2745 We require corresponding functions to apply the transformations: 2746 % 2747 \begin{verbatim} 2748 /** apply the coordinate transformation to the given coordinate */ 2749 psCoord *psCoordXformApply (psCoord *out, ///< Output coordinates, or NULL 2750 const psCoordXform *frame, ///< coordinate transformation 2751 const psCoord *coords ///< input coordiate 2752 ); 2753 \end{verbatim} 2754 % 2755 \begin{verbatim} 2756 /** apply the optical distortion to the given coordinate, magnitude, color */ 2757 psCoord *psDistortionApply (psCoord *out, ///< Output coordinates, or NULL 2758 const psdistortion *pattern, ///< optical distortion pattern 2759 const psCoord *coords, ///< input coordinate 2760 float mag, ///< magnitude of object 2761 float color ///< color of object 2762 ); 2763 \end{verbatim} 2764 % 2765 2766 \subsubsection{Celestial Coordinate Conversions} 2767 2768 We need to be able to convert between ICRS, Galactic and Ecliptic 2769 coordinates, and potentially between arbitrary spherical coordinate 2770 systems. All of these basic spherical transformations represent 2771 rotations of the spherical coordinate reference. We specify a general 2772 transformation function which takes a structure \code{psCoordSphere} 2773 defining the relationship between two spherical coordinate systems. 2774 We also define a function to generate \code{psCoordSphere}, which 2775 contains the appropriate sines and cosines of the angles, based on the 2776 three angles describing the location of the pole and the relative 2777 equatorial rotations of the two systems. We also specify special 2778 coordinate transformations between standard coordinate systems which 2779 define the value of psCoordSphere internally and automatically. 2780 2781 \begin{verbatim} 2782 /** Convert to new spherical coordinate system */ 2783 psCoord * 2784 psCoordTransform (psCoord *coord, 2785 psCoordSphere *sphere) ///< ICRS coordinates to convert 2786 ; 2787 \end{verbatim} 2788 2789 \begin{verbatim} 2790 /** Construct to new spherical coordinate system */ 2791 psCoordSphere * 2792 psCoordSphereDefine (double pole1, double pole2, double rotation); 2793 \end{verbatim} 2794 2795 \begin{verbatim} 2796 /** Convert ICRS to Ecliptic */ 2797 psCoord * 2798 psCoordinatesItoE(const psCoord *restrict coordinates ///< ICRS coordinates to convert 2799 ); 2800 \end{verbatim} 2801 2802 \begin{verbatim} 2803 /** Convert Ecliptic to ICRS */ 2804 psCoord * 2805 psCoordinatesEtoI(const psCoord *restrict coordinates ///< Ecliptic coordinates to convert 2806 ); 2807 \end{verbatim} 2808 2809 \begin{verbatim} 2810 /** Convert ICRS to Galactic */ 2811 psCoord * 2812 psCoordinatesItoG(const psCoord *restrict coordinates ///< ICRS coordinates to convert 2813 ); 2814 \end{verbatim} 2815 2816 \begin{verbatim} 2817 /** Convert Galactic to ICRS */ 2818 psCoord * 2819 psCoordinatesGtoI(const psCoord *restrict coordinates ///< Galactic coordinates to convert 2820 ); 2821 \end{verbatim} 2822 2823 2824 \subsubsection{Projections} 2825 2826 We require functions to convert between spherical and linear 2827 coordinate systems based on a variety of projections. The required 2828 projections include: 2829 \begin{itemize} 2830 \item TAN 2831 \item SIN 2832 \item AIT 2833 \item PAR 2834 \item GLS 2835 \end{itemize} 2836 2837 \begin{verbatim} 2838 psCoord *psCoordProject (psCoord *coord, char *projection); 2839 \end{verbatim} 2840 2841 \subsubsection{Offsets} 2842 2843 We require a function to calculate the offset between two positions on 2844 the sky, as well as a function to apply an offset to a position. 2845 2846 \begin{verbatim} 2847 /** Get offset (RA,Dec) on the sky between two positions position1 and position2 may not be identical */ 2848 psCoord * 2849 psGetOffset(const psCoord *restrict position1, ///< Position 1 2850 const psCoord *restrict position2, ///< Position 2 2851 const char *type ///< Type of offset: Linear, Spherical/Arcsec, Spherical/Degreees etc 2852 ); 2853 \end{verbatim} 2854 2855 \begin{verbatim} 2856 /** Apply an offset to a position */ 2857 psCoord * 2858 psApplyOffset(const psCoord *restrict position, ///< Position 2859 const psCoord *restrict offset, ///< Offset 2860 const char *type ///< Type of offset: Linear, Spherical/Arcsec, Spherical/Degreees etc 2861 ); 2862 \end{verbatim} 2863 2864 2865 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 2612 2866 2613 2867 \subsection{Astronomy Images} 2614 2868 2615 \subsubsection{Terminology} 2616 2617 Some brief review of terminology would be useful so that previous 2618 definitions do not influence the understanding of this document. 2619 2620 A ``readout'' is a read of the detector. 2621 2622 A ``cell'' is defined as the smallest element of the detector readout; 2623 usually associated with an amplifier. Correspondingly, each cell has 2624 its own overscan region. There may be multiple readouts in a cell if 2625 the cell was used to provide fast guiding. 2626 2627 A ``chip'' is defined as a contiguous piece of silicon, and consists 2628 of a group of cells. 2629 2630 A ``focal plane'' is defined as a mosaic of chips, and consists of a 2631 group of chips. 2869 \subsubsection{Overview} 2870 2871 Above, we have defined a basic container for a single 2D collection of 2872 pixels (\code{psImage}), along with basic operations to manipulate the 2873 image pixels. For astronomical applications, this data structure is 2874 insufficient for two reasons. First, it does provide sufficient 2875 additional metadata to describe the data in detail. Second, astronomy 2876 applications frequent involve multiple, related images. For 2877 PanSTARRS, and for general astronomical applications, we require a 2878 richer collection of data structures which describe a very general 2879 image concept. We have defined several layers in the hierarchy which 2880 are necessary to describe the image data which will be produced by the 2881 PanSTARRS Gigapixel cameras as well as other standard astronomical 2882 images. 2883 2884 A simple 2D image is a basic data unit for much of astronomical 2885 imaging. If we consider various optical and IR array cameras, a 2886 single readout of the detector produces a collection of pixels 2887 measurements. We define our lowest-level astronomical image 2888 structure, \code{psReadout}, to contain the pixels produced by a 2889 single readout of the detector, along with metadata needed to define 2890 that readout: the origin and binning of the image relative to the 2891 original detector pixels explicitly in the structure, a pointer to the 2892 appropriate overscan region, and pointers to the general metadata and 2893 derived objects, if any. 2894 2895 A single detector may produce more than one read which is associated. 2896 For example, infrared detectors frequently produce an image 2897 immediately after the detector is reset followed by an image after the 2898 basic exposure is complete. Both readouts correspond to the same 2899 pixels, though the binning or rastering may be different between the 2900 two readouts. Another example is the video sequence produced by the 2901 PanSTARRS Gigapix camera guide cells, each of which represents a 2902 series of many images from a subraster of pixels in the detector 2903 readout portion. The second level of our image container hierarchy, 2904 \code{psCell}, consists of a collection of readouts from a single 2905 detector. 2906 2907 In the PanSTARRS Gigapix camera, the basic readout region is a 2908 fraction of the full imaging area of a single CCD chip. The chip is 2909 divided into 64 cells, any fraction of which may have been readout 2910 for a given exposure. In other cameras, such as Megacam at CFHT, the 2911 individual CCDs have multiple amplifiers addressing contiguous 2912 portions of the detector. In such cameras, each amplifier produces a 2913 separate collection of pixels. In the third level of our image 2914 container hierarchy, the data structure \code{psChip} represents a 2915 collection of different cells. 2916 2917 The top level of our image container hierarchy is a complete focal 2918 plane array (\code{psFPA}). This structure represents the collection 2919 of chips in the camera, all of which are read out in a given 2920 exposure. 2632 2921 2633 2922 For example, take a mosaic camera consisting of eight $2k\times 4k$ … … 2641 2930 a few cells may be dead). Some cells (those containing guide stars 2642 2931 for the orthogonal transfer) will contain multiple readouts. 2932 2933 These data structures represent containers with which to carry around 2934 the collection of related image data. There is no requirement on the 2935 functions or the structures that each instance of one of these data 2936 structures represent the physical hardware. For example, it is not 2937 necessary that an instance of \code{psFPA} always carry the data for 2938 all 60 (or 64) Gigapixel camera OTAs. The usage of these structures 2939 is such that all astronomical operations which apply to a CCD image 2940 should be performed on an instance of \code{psFPA}. If a particular 2941 circumstance only requires a single 2D image, then that is represented 2942 by an instance of \code{psFPA} with one \code{psChip}, which in turn 2943 has one \code{psCell}, which in turn has one \code{psReadout}. 2944 2945 These container levels also include in their definition the information 2946 needed to transform the coordinates in one of the levels to the 2947 coordinate system relevant at the higher levels. 2643 2948 2644 2949 \subsubsection{A Readout} … … 2654 2959 /** a Readout: a collection of pixels */ 2655 2960 typedef struct { 2656 int x0, y0; // !< Offset from the lower-left corner2961 int x0, y0; ///< Offset from the lower-left corner 2657 2962 psImage *image; ///< imaging area of cell 2658 2963 psDlist *objects; ///< objects derived from cell 2659 2964 psImage *overscan; ///< bias region (subimage) of cell 2660 psMetaDataSet *md; // !< Readout-level metadata2965 psMetaDataSet *md; ///< Readout-level metadata 2661 2966 } psReadout; 2662 2967 \end{verbatim} 2663 2664 2968 2665 2969 \subsubsection{A Cell} … … 2686 2990 int nReadouts; ///< number of readouts in this cell realization; each may have its own 2687 2991 ///< image, objects and overscan. 2688 struct psReadout *readouts; // !< Readouts from the cell2992 struct psReadout *readouts; ///< Readouts from the cell 2689 2993 psMetaDataSet *md; ///< Cell-level metadata 2690 2994 … … 2719 3023 psMetaDataSet *md; ///< Chip-level metadata 2720 3024 psCoordXform *chipToFPA; ///< Transformations from chip coordinates to FPA coordinates 2721 psCoordXform *FPAtoChip; // !< Transformations from FPA coordinates to chip3025 psCoordXform *FPAtoChip; ///< Transformations from FPA coordinates to chip 2722 3026 2723 3027 struct psFPA *parentFPA; ///< FPA which contains this chip … … 2734 3038 transformation will consist of two 4D polynomials (i.e.\ a function of 2735 3039 two coordinates in position, the magnitude of the object, and the 2736 colo ur of the object) in order to correct for optical distortions and3040 color of the object) in order to correct for optical distortions and 2737 3041 the effects of the atmosphere; hence we expect that it is prudent to 2738 3042 include a reverse transformation which will be derived from 2739 numerically inverting the forward transformation. Since colo urs are2740 involved in the transformation, it is necessary to specify the colo ur3043 numerically inverting the forward transformation. Since colors are 3044 involved in the transformation, it is necessary to specify the color 2741 3045 the transformation is defined for. We also include some values to 2742 characteri se the quality of the transformation: the root mean square3046 characterize the quality of the transformation: the root mean square 2743 3047 deviation for the x and y transformation fits, and the $\chi^2$ for 2744 3048 the transformation fit. … … 2756 3060 psDistortion *TPtoFP; ///< Transformation term from 2757 3061 psDistortion *FPtoTP; ///< Transformation term from 2758 psFixedPattern *pattern; // !< Fixed pattern residual offsets3062 psFixedPattern *pattern; ///< Fixed pattern residual offsets 2759 3063 psExposure *exp; ///< information about this exposure 2760 3064 psPhotSystem colorPlus, colorMinus; ///< Colour reference 2761 float rmsX, rmsY; // !< Dispersion in astrometric solution2762 float chi2; // !< chi^2 of astrometric solution3065 float rmsX, rmsY; ///< Dispersion in astrometric solution 3066 float chi2; ///< chi^2 of astrometric solution 2763 3067 } psFPA; 2764 3068 \end{verbatim} 2765 2766 3069 2767 3070 \subsubsection{Exposure information} … … 2775 3078 typedef struct { 2776 3079 // Telescope longitude, latitude and height are stored separately, since they don't change with pointing 2777 double ra, dec; // !< Telescope boresight2778 double ha; // !< Hour angle2779 double zd; // !< Zenith distance2780 double az; // !< Azimuth2781 double lst; // !< Local Sidereal Time2782 float mjd; // !< MJD of observation2783 float rotAngle; // !< Rotator position angle2784 float temp; // !< Air temperature, for estimating refraction2785 float pressure; // !< Air pressure, for calculating refraction2786 float humidity; // !< Relative humidity, for calculating refraction2787 float exptime; // !< Exposure time3080 double ra, dec; ///< Telescope boresight 3081 double ha; ///< Hour angle 3082 double zd; ///< Zenith distance 3083 double az; ///< Azimuth 3084 double lst; ///< Local Sidereal Time 3085 float mjd; ///< MJD of observation 3086 float rotAngle; ///< Rotator position angle 3087 float temp; ///< Air temperature, for estimating refraction 3088 float pressure; ///< Air pressure, for calculating refraction 3089 float humidity; ///< Relative humidity, for calculating refraction 3090 float exptime; ///< Exposure time 2788 3091 /* Derived quantities */ 2789 float posAngle; // !< Position angle2790 float parallactic; // !< Parallactic angle2791 float airmass; // !< Airmass, calculated from zenith distance2792 float pf; // !< Parallactic factor3092 float posAngle; ///< Position angle 3093 float parallactic; ///< Parallactic angle 3094 float airmass; ///< Airmass, calculated from zenith distance 3095 float pf; ///< Parallactic factor 2793 3096 char *cameraName; ///< name of camera which provided exposure 2794 3097 char *telescopeName; ///< name of telescope which provided exposure 2795 psGrommit *grommit; // !< Data needed to convert from the sky to the tangent plane3098 psGrommit *grommit; ///< Data needed to convert from the sky to the tangent plane 2796 3099 } psExposure; 2797 3100 \end{verbatim} … … 2809 3112 /** Constructor */ 2810 3113 psExposure * 2811 psExposureAlloc(double ra, double dec, // !< Telescope boresight2812 double ha, // !< Hour angle2813 double zd, // !< Zenith distance2814 double az, // !< Azimuth2815 double lst, // !< Local Sidereal Time2816 float mjd, // !< MJD2817 float rotAngle, // !< Rotator position angle2818 float temp, // !< Temperature2819 float pressure, // !< Pressure2820 float humidity, // !< Relative humidity2821 float exptime // !< Exposure time3114 psExposureAlloc(double ra, double dec, ///< Telescope boresight 3115 double ha, ///< Hour angle 3116 double zd, ///< Zenith distance 3117 double az, ///< Azimuth 3118 double lst, ///< Local Sidereal Time 3119 float mjd, ///< MJD 3120 float rotAngle, ///< Rotator position angle 3121 float temp, ///< Temperature 3122 float pressure, ///< Pressure 3123 float humidity, ///< Relative humidity 3124 float exptime ///< Exposure time 2822 3125 ); 2823 3126 \end{verbatim} … … 2827 3130 2828 3131 Astrometry is a basic functionality required for the IPP that will be 2829 used repeatedly, both for low-precision (roughly where is my favo urite3132 used repeatedly, both for low-precision (roughly where is my favorite 2830 3133 object?) and high-precision (what is the proper motion of this star?). 2831 3134 As such, it must be flexible, yet robust. Accordingly, we will wrap … … 2847 3150 2848 3151 The following steps are required to convert from the cell coordinates to 2849 the sky :3152 the sky \tbd{convert Cell->Chip and Chip->FP to psDistortion}: 2850 3153 \begin{itemize} 2851 3154 \item Cell $\longleftrightarrow$ Chip: two 2D polynomials, $(X,Y) = f(x,y)$; 2852 3155 \item Chip $\longleftrightarrow$ FP: two 2D polynomials, $(p,q) = g(X,Y)$; 2853 3156 \item FP $\longleftrightarrow$ TP: two 4D polynomials, $(l,m) = 2854 h(p,q,m,c)$, where $m$ and $c$ are the magnitude and colo ur of the3157 h(p,q,m,c)$, where $m$ and $c$ are the magnitude and color of the 2855 3158 object, respectively; and 2856 3159 \item TP $\longleftrightarrow$ Sky: SLALib transformation using a … … 2861 3164 Plane is a four-dimensional polynomial, in order to account for any 2862 3165 possible dependencies in the astrometry on the stellar magnitude and 2863 colo ur; the former serves as a check for charge transfer3166 color; the former serves as a check for charge transfer 2864 3167 inefficiencies, while the latter will correct chromatic refraction, 2865 3168 both through the atmosphere and the corrector lenses. 2866 2867 \textbf{[If the magnitude terms serve to check CTI, then shouldn't we2868 put them in the cell $\leftrightarrow$ chip section?]}2869 3169 2870 3170 We require structures to contain each of the above transformations as … … 2897 3197 \end{verbatim} 2898 3198 2899 2900 3199 \subsubsection{Fixed Pattern} 2901 3200 … … 2911 3210 /** The fixed pattern residual offsets. These are specified via a coarse grid of x and y offsets. */ 2912 3211 typedef struct { 2913 int nX, nY; // !< Number of elements in x and y2914 double x0, y0; // !< Position of the lower-left corner of the grid on the focal plane2915 double xScale, yScale; // !< Scale of the grid2916 double **x, **y; // !< The grid of offsets in x and y3212 int nX, nY; ///< Number of elements in x and y 3213 double x0, y0; ///< Position of the lower-left corner of the grid on the focal plane 3214 double xScale, yScale; ///< Scale of the grid 3215 double **x, **y; ///< The grid of offsets in x and y 2917 3216 } psFixedPattern; 2918 3217 \end{verbatim} 2919 3218 2920 3219 2921 \subsubsection{ Finding}3220 \subsubsection{Position Finding} 2922 3221 2923 3222 We require functions to return the structure containing given … … 2932 3231 /** returns Chip in FPA which contains the given FPA coordinate */ 2933 3232 psChip * 2934 psChipInFPA (psChip *out, // !< Chip to return, or NULL3233 psChipInFPA (psChip *out, ///< Chip to return, or NULL 2935 3234 const psFPA *fpa, ///< FPA description 2936 3235 const psCoord *coord ///< coordinate in FPA … … 2941 3240 /** returns Cell in Chip which contains the given chip coordinate */ 2942 3241 psCell * 2943 psCellInChip(psCell *out, // !< Cell to return, or NULL3242 psCellInChip(psCell *out, ///< Cell to return, or NULL 2944 3243 const psChip *chip, ///< chip description 2945 3244 const psCoord *coord ///< coordinate in chip … … 2954 3253 /** Return the cell in FPA which contains the given FPA coordinates */ 2955 3254 psCell * 2956 psCellInFPA(psCell *out, // !< Cell to return, or NULL2957 const psFPA *fpa, // !< FPA description2958 const psCoord *coord // !< Coordinate in FPA3255 psCellInFPA(psCell *out, ///< Cell to return, or NULL 3256 const psFPA *fpa, ///< FPA description 3257 const psCoord *coord ///< Coordinate in FPA 2959 3258 ); 2960 3259 \end{verbatim} … … 2965 3264 2966 3265 We require functions to convert between the various coordinate frames 2967 (Section~\ref{sec:coordinateFrames}). The h eirarchy of the coordinate3266 (Section~\ref{sec:coordinateFrames}). The hierarchy of the coordinate 2968 3267 frames and the transformations between each are shown in 2969 3268 Figure~\ref{fig:coco}. The functions that employ the transformations 2970 3269 are shown in Figure~\ref{fig:cocoFunc}. In addition to 2971 3270 transformations between each adjoining coordinate frame in the 2972 h eirarchy, we also require higher-level functions to convert between3271 hierarchy, we also require higher-level functions to convert between 2973 3272 the Cell and Sky coordinate frames; these will simply perform the 2974 3273 intermediate steps. … … 2993 3292 /** Convert (RA,Dec) to cell and cell coordinates */ 2994 3293 psCoord * 2995 psCoordSkyToCell(psCoord *out, // !< Coordinates to return, or NULL2996 psCell *cell, // !< Cell to return2997 const psFPA *fpa // !< FPA description3294 psCoordSkyToCell(psCoord *out, ///< Coordinates to return, or NULL 3295 psCell *cell, ///< Cell to return 3296 const psFPA *fpa ///< FPA description 2998 3297 ); 2999 3298 \end{verbatim} … … 3002 3301 /** Convert cell and cell coordinate to (RA,Dec) */ 3003 3302 psCoord * 3004 psCoordCellToSky(psCoord *out, // !< Coordinates to return, or NULL3005 const psCell *cell, // !< Cell to get coordinates for3006 const psCoord *coord // !< cell coordinates to transform3303 psCoordCellToSky(psCoord *out, ///< Coordinates to return, or NULL 3304 const psCell *cell, ///< Cell to get coordinates for 3305 const psCoord *coord ///< cell coordinates to transform 3007 3306 ); 3008 3307 \end{verbatim} … … 3011 3310 /** Quick and dirty cell to (RA,Dec) --- employs cellToSky transformation */ 3012 3311 psCoord * 3013 psCoordCellToSkyQuick(psCoord *out, // !< Coordinates to return, or NULL3014 const psCell *cell, // !< Cell description3015 const psCoord *coord // !< cell coordinates to transform3312 psCoordCellToSkyQuick(psCoord *out, ///< Coordinates to return, or NULL 3313 const psCell *cell, ///< Cell description 3314 const psCoord *coord ///< cell coordinates to transform 3016 3315 ); 3017 3316 \end{verbatim} … … 3020 3319 /** Convert (RA,Dec) to tangent plane coords */ 3021 3320 psCoord * 3022 psCoordSkyToTP(psCoord *out, // !< Coordinates to return, or NULL3023 const psExposure *exp, // !< Exposure description3024 const psCoord *coord // !< input Sky coordinate3321 psCoordSkyToTP(psCoord *out, ///< Coordinates to return, or NULL 3322 const psExposure *exp, ///< Exposure description 3323 const psCoord *coord ///< input Sky coordinate 3025 3324 ); 3026 3325 \end{verbatim} … … 3029 3328 /** Convert tangent plane coords to focal plane coordinates */ 3030 3329 psCoord * 3031 psCoordTPtoFPA(psCoord *out, // !< Coordinates to return, or NULL3032 const psFPA *fpa, // !< FPA description3033 const psCoord *coord // !< input TP coordinate3330 psCoordTPtoFPA(psCoord *out, ///< Coordinates to return, or NULL 3331 const psFPA *fpa, ///< FPA description 3332 const psCoord *coord ///< input TP coordinate 3034 3333 ); 3035 3334 \end{verbatim} … … 3038 3337 /** converts the specified FPA coord to the coord on the given Chip */ 3039 3338 psCoord * 3040 psCoordFPAtoChip (psCoord *out, // !< Coordinates to return, or NULL3339 psCoordFPAtoChip (psCoord *out, ///< Coordinates to return, or NULL 3041 3340 const psChip *chip, ///< Chip of interest 3042 3341 const psCoord *coord ///< input FPA coordinate … … 3047 3346 /** converts the specified Chip coord to the coord on the given Cell */ 3048 3347 psCoord * 3049 psCoordChiptoCell (psCoord *out, // !< Coordinates to return, or NULL3348 psCoordChiptoCell (psCoord *out, ///< Coordinates to return, or NULL 3050 3349 const psCell *cell, ///< Cell of interest 3051 3350 const psCoord *coord ///< input Chip coordinate … … 3056 3355 /** converts the specified Cell coord to the coord on the parent Chip */ 3057 3356 psCoord * 3058 psCoordCelltoChip (psCoord *out, // !< Coordinates to return, or NULL3357 psCoordCelltoChip (psCoord *out, ///< Coordinates to return, or NULL 3059 3358 const psCell *cell, ///< Cell description 3060 3359 const psCoord *coord ///< input Cell coordinate … … 3065 3364 /** converts the specified Chip coord to the coord on the parent FPA */ 3066 3365 psCoord * 3067 psCoordChiptoFPA (psCoord *out, // !< Coordinates to return, or NULL3366 psCoordChiptoFPA (psCoord *out, ///< Coordinates to return, or NULL 3068 3367 const psChip *chip, ///< Chip description 3069 3368 const psCoord *coord ///< input Chip coordinate … … 3074 3373 /** Convert focal plane coords to tangent plane coordinates */ 3075 3374 psCoord * 3076 psCoordFPAToTP(psCoord *out, // !< Coordinates to return, or NULL3077 const psFPA *fpa, // !< FPA description3078 const psCoord *coord // !< input FPA coordinate3375 psCoordFPAToTP(psCoord *out, ///< Coordinates to return, or NULL 3376 const psFPA *fpa, ///< FPA description 3377 const psCoord *coord ///< input FPA coordinate 3079 3378 ); 3080 3379 \end{verbatim} … … 3083 3382 /** Convert tangent plane coords to (RA,Dec) */ 3084 3383 psCoord * 3085 psCoordTPtoSky(psCoord *out, // !< Coordinates to return, or NULL3086 const psExposure *exp, // !< Exposure description3087 const psCoord *coord // !< input TP coordinate3384 psCoordTPtoSky(psCoord *out, ///< Coordinates to return, or NULL 3385 const psExposure *exp, ///< Exposure description 3386 const psCoord *coord ///< input TP coordinate 3088 3387 ); 3089 3388 \end{verbatim} … … 3092 3391 /** Convert Cell coords to FPA coordinates */ 3093 3392 psCoord * 3094 psCoordCellToFPA(psCoord *out, // !< Coordinates to return, or NULL3095 const psCell *cell, // !< Cell description3096 const psCoord *coord // !< Input cell coordinates3393 psCoordCellToFPA(psCoord *out, ///< Coordinates to return, or NULL 3394 const psCell *cell, ///< Cell description 3395 const psCoord *coord ///< Input cell coordinates 3097 3396 ); 3098 3397 \end{verbatim} … … 3108 3407 /** Get the airmass for a given position and sidereal time */ 3109 3408 float 3110 psGetAirmass(const psCoord *coord, // !< Position on the sky3111 double siderealTime, // !< Sidereal time3112 float height // !< Height above sea level3409 psGetAirmass(const psCoord *coord, ///< Position on the sky 3410 double siderealTime, ///< Sidereal time 3411 float height ///< Height above sea level 3113 3412 ); 3114 3413 \end{verbatim} … … 3117 3416 /** Get the parallactic angle for a given position and sidereal time */ 3118 3417 float 3119 psGetParallactic(const psCoord *coord, // !< Position on the sky3120 double siderealTime // !< Sidereal time3418 psGetParallactic(const psCoord *coord, ///< Position on the sky 3419 double siderealTime ///< Sidereal time 3121 3420 ); 3122 3421 \end{verbatim} … … 3125 3424 /** Estimate atmospheric refraction, along the parallactic */ 3126 3425 float 3127 psGetRefraction(float colour, // !< Colour of object3426 psGetRefraction(float colour, ///< Colour of object 3128 3427 psPhotSystem colorPlus, ///< Colour reference 3129 3428 psPhotSystem colorMinus, ///< Colour reference 3130 const psExposure *exp // !< Telescope pointing information, for airmass, temp and pressure3429 const psExposure *exp ///< Telescope pointing information, for airmass, temp and pressure 3131 3430 ); 3132 3431 \end{verbatim} … … 3135 3434 /** Calculate the parallax factor */ 3136 3435 double 3137 psGetParallaxFactor(const psExposure *exp // !< Exposure details3436 psGetParallaxFactor(const psExposure *exp ///< Exposure details 3138 3437 ); 3139 3438 \end{verbatim} … … 3161 3460 \begin{verbatim} 3162 3461 typedef struct { 3163 int ID; // !< ID number for this photometric system3164 char *name; // !< Name of photometric system3165 char *camera; // !< Camera for photometric system3166 char *filter; // !< Filter used for photometric system3167 char *detector; // !< Detector used for photometric system3462 int ID; ///< ID number for this photometric system 3463 char *name; ///< Name of photometric system 3464 char *camera; ///< Camera for photometric system 3465 char *filter; ///< Filter used for photometric system 3466 char *detector; ///< Detector used for photometric system 3168 3467 } psPhotSystem; 3169 3468 \end{verbatim} … … 3173 3472 \begin{verbatim} 3174 3473 typedef struct { 3175 psPhotSystem src; // !< Source photometric system3176 psPhotSystem dst; // !< Destination photometric system3474 psPhotSystem src; ///< Source photometric system 3475 psPhotSystem dst; ///< Destination photometric system 3177 3476 psPhotSystem pP, pM; ///< Primary colour reference 3178 3477 psPhotSystem sP, sM; ///< Secondary colour reference 3179 3478 float pA, sA; ///< Colour offset for primary and secondary references 3180 psPolynomial3D transform; // !< Transformation from source to destination3479 psPolynomial3D transform; ///< Transformation from source to destination 3181 3480 } psPhotTransform; 3182 3481 \end{verbatim} … … 3192 3491 are highly reddened, for example. Derived photometric quantities may 3193 3492 have been corrected for airmass variations, in which case only color 3194 terms may be measur eable. The structure defines the transformation3493 terms may be measurable. The structure defines the transformation 3195 3494 between a source photometric system (\code{src}) and a target 3196 3495 photometric system (\code{dst}). The photometric system of a primary … … 3213 3512 \subsection{Astronomical objects} 3214 3513 3215 \textbf{[Deferred.]} 3514 \subsubsection{Positions of Major SS Objects} 3515 3516 We require the ability to calculate the position of major Solar System 3517 objects, as well as Lunar phase. 3518 3519 \begin{verbatim} 3520 /** Get Sun Position */ 3521 psCoord * 3522 psGetSunPos(float mjd ///< MJD to get position for 3523 ); 3524 \end{verbatim} 3525 3526 \begin{verbatim} 3527 /** Get Moon position */ 3528 psCoord * 3529 psGetMoonPos(float mjd, ///< MJD to get position for 3530 double latitude, ///< Latitude for apparent position 3531 double longitude ///< Longitude for apparent position 3532 ); 3533 \end{verbatim} 3534 3535 \begin{verbatim} 3536 /** Get Moon phase */ 3537 float 3538 psGetMoonPhase(float mjd ///< MJD to get phase for 3539 ); 3540 \end{verbatim} 3541 3542 \begin{verbatim} 3543 /** Get Planet positions */ 3544 psCoord * 3545 psGetSolarSystemPos(const char *solarSystemObject, ///< Named S.S. object 3546 float mjd ///< MJD to get position for 3547 ); 3548 \end{verbatim} 3549 3550 \tbd{The rest of this section is tentative} 3551 3552 We may need a variety of other SLALib-type functions: 3553 3554 \begin{itemize} 3555 \item Lunation calculations to/from psTime 3556 \item rise/set for specified object 3557 \item 12 \& 18 deg twilight for closest sunrise / sunset 3558 \item length of current night 3559 \end{itemize} 3216 3560 3217 3561 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Note:
See TracChangeset
for help on using the changeset viewer.
