IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Changeset 276


Ignore:
Timestamp:
Mar 22, 2004, 12:23:02 PM (22 years ago)
Author:
eugene
Message:

merged in utils.tex (RHL), metadata.tex (RHL), and psLibSubset.tex (EAM)
added an appendix with all functions listed

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/doc/pslib/psLibSDRS.tex

    r275 r276  
    44% basic document variables
    55\title{Pan-STARRS IPP Library Design}
    6 \author{}
     6\author{Paul Price, Eugene Magnier, Robert Lupton}
    77\shorttitle{PSLib Design}
    88\group{Pan-STARRS Algorithm Group}
     
    6767\section{System Utilities}
    6868
    69 \note{INSERT HERE STUFF FROM RHL'S \file{utils.pdf}}
    70 
    71 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    72 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     69\subsection{Memory Management}
     70\hlabel{psMemBlock}
     71
     72\subsubsection{Introduction}
     73
     74The \PS{} software system will need a level of memory management
     75placed between the operating system (malloc/free) and the high level
     76routines (e.g. \code{psMetaDataAlloc}).
     77
     78This layer is in addition to the possibility that specific heavily
     79used data types may need their own special-purpose memory managers;
     80but as we have specified that all user-level objects be allocated via
     81\code{typeAlloc/typeFree} functions, we will easily be able to
     82implement such functionality without impacting on the facilities
     83described here.
     84
     85All of the memory management APIs should be provided in a header file
     86\file{psMemory.h} which is included by \file{psUtils.h}.
     87
     88\subsubsection{Rationale}
     89
     90We wish to insert our own layer of memory management for a number of
     91reasons:
     92
     93\begin{itemize}
     94\item
     95  We wish to insulate ourselves from the details of the system-provided
     96  \code{malloc}.  There is no guarantee that the goals of the system
     97  architect align with those of the \PS{} processing
     98
     99\item
     100  We need at least a wrapper layer which handles failed memory
     101  requests without requiring the application programmer to check
     102  every attempted allocation.
     103
     104\item
     105  We need to provide a mechanism for tracking and fixing memory
     106  leaks.  While it is possible to do this by linking with external
     107  libraries (\tbd{reference}), it is convenient to do so within the
     108  \PS{} framework.
     109
     110\item
     111  Similarly, we wish to provide convenient hooks to detect and diagnose
     112  memory corruption.
     113
     114\item
     115  While debugging complex scientific code, it is very useful to be
     116  able to trace a given data structure as it passed through the
     117  processing pipeline.
     118
     119\item
     120  There may be other features that we wish to add in the future (e.g.
     121  associating a type with every allocation).
     122\end{itemize}
     123
     124\subsubsection{A Minimal Specification}
     125
     126The previous section laid out a number of desiderata for a memory
     127management system.  Rather than implement our own heap-manager at this
     128stage of the project, I propose that we put in place a sufficient
     129set of data structures and APIs, but initially implement only
     130a simple subset (e.g. that we not implement a multi-bucket memory
     131manager that takes in 100Mb chunks from the system and performs
     132sophisticated defragmentation and garbage collection).
     133
     134Subject to agreement with the IfA, some of the functions proposed
     135here may be omitted from the initial implementation; in particular
     136the routines \code{psMemCheckCorruption} and \code{psMemCheckLeaks}
     137may be hard to build efficiently in a simple implementation based
     138upon adding extra fields to allocation requests.
     139
     140\paragraph{Extra information to be saved by Memory Allocation Functions}
     141
     142It is required that a table of all allocated memory blocks be
     143maintained by the \PS{} memory system.
     144
     145Each allocated block should preserve at least the information present
     146in the following struct definition:
     147\begin{verbatim}
     148  typedef struct {
     149      const unsigned long id;           // a unique ID for this allocation
     150      const char *file;                 // set from __FILE__ in e.g. p_psAlloc
     151      const int lineno;                 // set from __LINE__ in e.g. p_psAlloc
     152      int refcntr;                      // how many times pointer is referenced
     153      const void *magic;                // initialised to P_PS_MEMMAGIC
     154  } psMemBlock;
     155\end{verbatim}
     156
     157The value of \code{P_PS_MEMMAGIC} shall be \code{(void *)0xdeadbeef}%
     158\footnote{Why this choice? Tradition, and because it's easy to notice
     159  in a hex dump.}
     160
     161\paragraph{APIs for using Memory Allocation Functions}
     162
     163\begin{table}
     164\begin{verbatim}
     165void *psAlloc(size_t size);
     166void *psRealloc(void *ptr, size_t size);
     167void psFree(void *ptr);
     168
     169void *p_psAlloc(size_t size, const char *file, int lineno);
     170void *p_psRealloc(void *ptr, size_t size, const char *file, int lineno);
     171void p_psFree(void *ptr, const char *file, int lineno);
     172
     173#define psAlloc(size) p_psAlloc(size, __FILE__, __LINE__)
     174#define psRealloc(ptr, size) p_psRealloc(ptr, size, __FILE__, __LINE__)
     175#define psFree(size) p_psFree(size, __FILE__, __LINE__)
     176\end{verbatim}
     177\begin{caption}{The APIs required to use the \PS{} memory allocation routines}
     178  \hlabel{tabUsageAPI}
     179  The APIs required to use the \PS{} memory allocation routines, and as
     180  provided by \file{psMemory.h}.
     181\end{caption}
     182\end{table}
     183
     184The types and function prototypes for the part of the memory API
     185concerned with allocating and freeing memory are given in table
     186\ref{tabUsageAPI}).
     187
     188N.b.
     189\begin{itemize}
     190\item
     191  The functions \code{psAlloc}, \code{psRealloc}, and
     192  \code{psFree} are defined, and are required to be equivalent to
     193  \code{p_psAlloc}, \code{p_psRealloc}, and \code{p_psFree}
     194  with the final two arguments \code{"(unknown)"} and \code{0}.
     195
     196  In the descriptions that follow, I shall not distinguish between the
     197  functions with and without the \code{p_} prefix.
     198
     199\item
     200  Except as specified below, the functions \code{psAlloc},
     201  \code{psRealloc}, and \code{psFree} have identical semantics
     202  to the standard C library functins \code{malloc}, \code{realloc},
     203  and \code{free}.
     204 
     205\item
     206  The file \file{psMemory.h} shall take steps to ensure that
     207  code calling the functions \code{malloc}, \code{calloc}, \code{realloc},
     208  or \code{free} shall not compile (\eg{} \code{#define malloc(S) for})
     209  unless the symbol \code{PS_ALLOC_MALLOC} is defined.
     210
     211\item
     212  In all cases, application code will call
     213  \code{p_\{psAlloc,psRealloc,psFree\}} via the macros defined above.
     214 
     215\item
     216  The functions \code{psAlloc} and \code{psRealloc} shall never
     217  return a \code{NULL} pointer. If they are unable to provide
     218  the requested memory they should attempt to obtain the desired
     219  memory by calling the routine registered by \code{psMemExhaustedSetCB} (see
     220  subsubsection \ref{secMemAdvanced}), and if still unsuccessful,
     221  call \code{abort()}.
     222
     223\item
     224  The memory management routines shall maintain the field
     225  \code{psMemBlock.refcntr}. It should be set to \code{1}
     226  when a block is returned to the user. It is an error to
     227  attempt to free a block with \code{psMemBlock.refcntr != 1}
     228  (see subsubsection \ref{secMemRefcounter}).
     229 
     230\item
     231  Where practical and efficient, the memory manager shall call
     232  the routine registered using the \code{psMemProblemSetCB}
     233  (see section \ref{secMemAdvanced})
     234  whenever a corrupted block of memory is discovered. For example,
     235  doubly-freed blocks can be detected by checking \code{psMemBlock.refcntr}.
     236
     237\item
     238  There is no \code{psCalloc} function. Initialisation of data is
     239  almost always more complex than setting all bytes to 0.
     240\end{itemize}
     241
     242\paragraph{APIs for Tracing and Debugging Memory}
     243\hlabel{secMemAdvanced}
     244
     245\begin{table}
     246\begin{verbatim}
     247typedef int (*psMemCallback)(const psMemBlock *ptr);
     248typedef void (*psMemProblemCallback)(const psMemBlock *ptr,
     249                                     const char *file, int lineno);
     250typedef void *(*psMemExhaustedCallback)(size_t size);
     251
     252psMemProblemCallback psMemProblemSetCB(psMemProblemCallback func);
     253psMemExhaustedCallback psMemExhaustedSetCB(psMemExhaustedCallback func);
     254
     255psMemCallback psMemAllocateSetCB(psMemCallback func);
     256psMemCallback psMemFreeSetCB(psMemCallback func);
     257
     258int psMemGetId(void);                   // get next memory ID
     259
     260long psMemSetAllocateID(long id);       // set p_psMemAllocateID to id
     261long psMemSetFreeID(long id);           // set p_psMemFreeID to id
     262
     263int psMemCheckLeaks(
     264    int id0,                            // don't list blocks with id < id0
     265    psMemBlock ***arr,                  // pointer to array of pointers to
     266                                        //leaked blocks, or NULL
     267    FILE *fd);                          // print list of leaks to fd (or NULL)
     268int psMemCheckCorruption(int abort_on_error);
     269\end{verbatim}
     270\begin{caption}{The APIs required to use the \PS{} memory allocation routines}
     271  \hlabel{tabCallbackAPI}
     272  The APIs required to use the callback and tracing facilities
     273  in \PS{} memory allocation routines, as defined in \file{psMemory.h}.
     274\end{caption}
     275\end{table}
     276
     277The types and function prototypes for this part of the memory API
     278are given in table \ref{tabCallbackAPI}.
     279
     280\paragraph{Callback Routines}
     281
     282The four `\code{SetCB}' routines are:
     283
     284\begin{tabular}{ll|l}
     285\textbf{type} &  \textbf{Name} & \textbf{Function of callback} \\
     286psMemProblemCallback & psMemProblemSetCB &
     287Called when a problem is detected with data being managed on the heap \\
     288psMemExhaustedCallback & psMemExhaustedSetCB &
     289Called when \code{psAlloc} is unable to satisfy a memory request. \\
     290psMemCallback & psMemAllocateSetCB &
     291Callback is called when the \code{psMemBlock} with a specified ID is
     292allocated. \\
     293psMemCallback & psMemFreeSetCB &
     294Callback is called when the \code{psMemBlock} with a specified ID is
     295freed. \\
     296\end{tabular}
     297
     298N.b.
     299\begin{itemize}
     300\item
     301  In all cases, the `\code{SetCB}' routine takes a pointer to the
     302  desired callback function, and returns a pointer to the one that was
     303  previously installed. If the function pointer is \code{NULL}, the
     304  default callback function is reinstalled.
     305
     306\item
     307  The routine installed by \code{psMemExhaustedSetCB} should return
     308  a pointer to the desired memory or \code{NULL}; in the latter case
     309  \code{psAlloc} will call \code{abort()}
     310
     311\item
     312  \code{psMemGetId} returns the current value of \code{psMemBlock.id}.
     313
     314\item
     315  The handler specified by \code{psMemAllocateSetCB} is called just
     316  before the pointer with \code{psMemBlock.id} equal to
     317  \code{p_psMemAllocateID} is returned to the user. The variable
     318  \code{p_psMemAllocateID} should not be set directly in any
     319  delivered code, \code{psMemSetAllocateID} should be used instead.
     320
     321\item
     322  The handler specified by \code{psMemFreeSetCB} is called just
     323  before the pointer with \code{psMemBlock.id} equal to
     324  \code{p_psMemFreeID} is freed. The variable
     325  \code{p_psMemFreeID} should not be set directly in any delivered
     326  code, \code{psMemSetFreeID} should be used instead.
     327
     328\item
     329  The routines \code{psMemSetFreeID} and \code{psMemSetAllocateID}
     330  accept the desired ID value (see previous two items) and return
     331  the old value to the user.
     332
     333\item
     334  The return values of the handlers installed by \code{psMemAllocateSetCB}
     335  and \code{psMemFreeSetCB} are used to increment the values of
     336  \code{p_psMemAllocateID} and \code{p_psMemFreeID} respectively.
     337
     338  For example, the return value \code{0} implies that the value is unchanged;
     339  if the value is \code{2} the callback will be called again when the
     340  memory ID counter has increased by two.
     341\end{itemize}
     342
     343\paragraph{Memory Tracing and Corruption Routines}
     344
     345The routine \code{psMemCheckLeaks} may be used to check for memory
     346leaks. The return value is the number of blocks that have been
     347allocated but not freed.
     348
     349Only blocks with \code{psMemBlock.id} greater than \code{id0}
     350are checked; this allows the user to ignore blocks allocated
     351by initialisation routines.
     352
     353If the argument \code{arr} is non-\code{NULL}, then upon entering
     354the call \code{**arr} should be \code{NULL}. Upon return it is set
     355to an array of \code{psMemBlock *} pointers, one for each block
     356allocated but not freed.  It is the caller's responsibility to free
     357this array with \code{psFree}.
     358
     359If the argument \code{fd} is non\code{NULL}, a one-line summary
     360of each block that has been allocated but not freed is written to that
     361file descriptor.
     362
     363The routine \code{psMemCheckCorruption} checks the entire heap for
     364corruption, calling the routine registered with
     365\code{psMemProblemSetCB} for each block detected as being corrupted.
     366The return value is the number of corrupted blocks detected. If the
     367argument \code{abort_on_error} is true,
     368\code{psMemCheckCorruption} shall call \code{abort()} as soon as
     369memory corruption is detected.
     370
     371\paragraph{Reference Counting}
     372\hlabel{secMemRefcounter}
     373
     374The memory management routines include a field
     375\code{psMemBlock.refcntr} which must equal \code{1} whenever
     376a pointer is presented to \code{psFree}.
     377
     378The API for this field is:
     379\begin{verbatim}
     380int psMemGetRefCounter(void *vptr);        // return refcounter
     381void *psMemIncrRefCounter(void *vptr);     // increment refcounter and return vptr
     382void *psMemDecrRefCounter(void *vptr);     // decrement refcounter and return vptr
     383\end{verbatim}
     384
     385The functions \code{psMemIncrRefCounter} and \code{psMemDecrRefCounter} shall
     386return \code{NULL} if passed a \code{NULL} pointer.
     387
     388\subsubsubsection{Rationale}
     389
     390\begin{table}
     391\begin{verbatim}
     392typedef struct {
     393    char *name;
     394    int value;
     395} psSimple;
     396
     397psSimple *psSimpleAlloc(const char *name, int val)
     398{
     399    psSimple *simp = psAlloc(sizeof(psSimple));
     400    simp->name = strcpy(psAlloc(strlen(name) + 1), name);
     401    simp->value = val;
     402
     403    return simp;
     404}
     405
     406void psSimpleFree(psSimple *simp)
     407{
     408    if (simp == NULL) { return; }
     409
     410    if (psMemGetRefCounter(simp) > 1) {
     411        (void)psMemDecrRefCounter(simp);
     412        return;
     413    }
     414}
     415\end{verbatim}
     416\begin{caption}{An example of reference counting}
     417  \hlabel{tabReferenceCounting}
     418  An example of using reference counting
     419\end{caption}
     420\end{table}
     421
     422The \code{psMemBlock.refcounter} is clearly useful for detecting
     423attempts to free memory that is already free.  A more complex
     424application is for allowing pointers to complex data-objects (e.g.
     425images) to appear in more than one data structure simultaneously
     426(see table \ref{tabReferenceCounting}).
     427
     428Because of the use of the \code{refcounter} field, we can safely put items of
     429this type onto many lists:
     430\goodbreak
     431\begin{verbatim}
     432simp = psSimpleAlloc("RHL", 0);
     433psDlistAppend(list1, psMemIncrRefCounter(simp));
     434psDlistAppend(list2, psMemIncrRefCounter(simp));
     435psSimpleFree(simp);
     436\end{verbatim}
     437
     438(Note: in fact there is no need to explicitly increment the counter
     439in this case, as the \code{psDlistAppend} (section \ref{psDlist})
     440API specifies that it
     441does it for you.)
     442
     443\subsection{Tracing and Logging}
     444
     445This document defines the \PS{} Tracing and Logging APIs; the former
     446refers to debug information that we wish to be able to turn on and off
     447without recompiling (although it will \emph{not} be available in
     448production code); the latter means information about the processing
     449that must be collected and saved, even in the production system.
     450
     451We envision that we will make extensive use of \code{psTrace} throughout
     452the \PS{} code.
     453
     454\subsubsection{Tracing APIs}
     455\hlabel{psTrace}
     456
     457\begin{table}
     458  \begin{verbatim}
     459#if defined(PS_NTRACE)
     460#  define psTrace(facil, level, ...) /* do nothing */
     461#else
     462#  define psTrace(facil, level, ...) \
     463          p_psTrace(facil, level, __VA_ARGS__)
     464#endif
     465
     466void p_psTrace(const char *facil, int level, ...);
     467
     468int psSetTraceLevel(const char *facil,  // facilty of interest
     469                    int level);         // desired trace level
     470int psGetTraceLevel(const char *name);  // facilty of interest
     471
     472void psTraceReset(void);                // turn off all tracing, and free trace's allocated memory
     473
     474void psPrintTraceLevels(void);          // print trace levels
     475  \end{verbatim}
     476  \begin{caption}{The public API for the trace facility
     477      from \file{psTrace.h}.}
     478    \hlabel{tabTraceAPI}
     479  \end{caption}
     480\end{table}
     481
     482The public API for the trace facility (table \ref{tabTraceAPI})
     483should be provided in a header file \file{psTrace.h} which
     484is included by \file{psUtils.h}.
     485
     486\begin{itemize}
     487  \item
     488    Logging is provided by the function \code{psTrace},
     489    which is actually a macro.  When the macro \code{PS_NTRACE}
     490    is defined, all occurrences of  \code{psTrace} shall
     491    be replaced by whitespace.
     492
     493  \item
     494    The first argument to \code{psTrace} is a name of the form
     495    \code{aaa.bbb.ccc}. The second is an integer,
     496    \code{level}. The remaining arguments are a printf-style format
     497    and a (possibly empty) set of values for that formatting
     498    string. When this trace is active, \code{psTrace} shall generate
     499    the requested output on \code{stdout}, preceded by \code{level}
     500    spaces.
     501
     502  \item
     503    The call \code{psSetTraceLevel(name, level)} shall set the trace
     504    level for \code{name} to \code{level}.
     505
     506  \item
     507    The call \code{psGetTraceLevel(name)} shall return the level
     508    associated with \code{name}.  If \code{name} has not been
     509    associated with a level, the routine shall remove the \textit{last}
     510    element of \code{name} and attempt to look up its level; this
     511    procedure shall be applied recursively until the name is reduced
     512    to \code{""}; if this name has no level associated with
     513    it, then the value \code{0} shall be returned (see examples
     514    below).
     515
     516    \item
     517      The call \code{psTrace(name, level, ...)}
     518      shall print the message if and only if
     519      \code{psGetTraceLevel(name)} returns a value greater than
     520      or equal to \code{level}.
     521
     522    \item
     523      \code{psPrintTraceLevels} shall print a listing of all
     524      declared levels, displayed as a hierarchy with sub-components
     525      sorted within each component (see examples below).
     526
     527      Note in particular that the root of the tree, the name \code{""}
     528      should print as \code{(root)}, and nodes which have not
     529      been assigned a value should list their level as \code{.}.
     530
     531    \item
     532      All of the tracing facilities shall be SWIGed, with the exception
     533      of \code{p_psTrace}.
     534
     535    \item
     536      There is no requirement that \code{psTrace} be usable from
     537      within the functions that implement \file{psTrace.h}
     538      or \file{psMemory.h} systems.
     539
     540    \item
     541      \code{psTraceReset} shall reset all tracing to the state that it
     542      had at program initiation, including freeing any memory that the
     543      tracing subsystem may have allocated.
     544\end{itemize}
     545
     546\paragraph{Examples of the use of Tracing Facilities}
     547
     548For example, after the commands:
     549\begin{verbatim}
     550    psSetTraceLevel("utils.dlist.add.head", 9);
     551    psSetTraceLevel("utils.dlist.add", 3);
     552    psSetTraceLevel("utils.dlist.remove", 4);
     553    psSetTraceLevel("coadd", 2);
     554    psSetTraceLevel("coadd.CR.remove.morphology", 5);
     555    psSetTraceLevel("utils.hash", 2);
     556    psSetTraceLevel("utils.dlist.add", 9);
     557    psSetTraceLevel("utils", 1);
     558\end{verbatim}
     559the command \code{psPrintTraceLevels()} should print:
     560\begin{verbatim}
     561(root)               0
     562 utils               1
     563  hash               2
     564  dlist              .
     565   remove            4
     566   add               9
     567    head             9
     568 coadd               2
     569  CR                 .
     570   remove            .
     571    morphology       5
     572\end{verbatim}
     573where \code{.} means that the trace level should be inherited from its parent.
     574
     575After this set of \code{psSetTraceLevel} commands, and if
     576\code{PS_NTRACE} is not defined, the following commands
     577\begin{verbatim}
     578    psTrace("utils.dlist.remove", 2, "Removing psDList key \"%s\"\n", "my_key");
     579    psTrace("utils", 2, "Initialising utilities library\n");
     580    psTrace("", 2, "This is turned on by trace component \"\"");
     581    psTrace("utils.dlist", 2, "Initialising psDList\n");
     582    psTrace("utils.dlist.remove", 4, "Removing psDList key \"%s\" (value: \"%d\")\n", "my_key", 12345);
     583    psTrace("utils.hash.remove", 4, "Removing hash key \"%s\" (value: \"%d\")\n", "my_key", 12345);
     584    psTrace("utils.dlist.add", 1, "Adding psDList key \"%s\"\n", "your_key");
     585    psTrace("utils.dlist.find", 2, "Looking up psDList key \"%s\"\n", "some_key");
     586    psTrace("coadd.CR.remove", 4, "Removing CRs\n");
     587    psTrace("coadd.CR.remove.morphology", 4, "CRs are not fuzzy\n");
     588\end{verbatim}
     589should produce this output:
     590\begin{verbatim}
     591  Removing psDList key "my_key"
     592    Removing psDList key "my_key" (value: "12345")
     593 Adding psDList key "your_key"
     594    CRs are not fuzzy
     595\end{verbatim}
     596
     597Note that
     598\begin{description}
     599\item
     600  \code{utils.dlist} messages are at level 1, inherited from \code{utils}, so the
     601  \code{Initialising utilities library}, \code{Initialising psDList}, and
     602  \code{Looking up psDList key} messages are \emph{not} printed (the traces are at level 2).
     603
     604\item
     605  \code{utils.dlist.remove} messages are at level 4, and are printed.
     606
     607\item
     608  \code{utils.hash} messages are at level 2, and are not printed (the traces are at level 4)
     609
     610\item
     611  \code{coadd.CR.remove} is at level 2 (inherited from \code{coadd}) so \code{Removing CRs}
     612  isn't printed.  \code{coadd.CR.remove.morphology} is at level 4, so \code{CRs are not fuzzy} is printed.
     613\end{description}
     614
     615\subsubsection{Message Logging}
     616\hlabel{psLogMsg}
     617
     618\begin{table}
     619  \begin{verbatim}
     620enum { PS_LOG_ABORT = 0, PS_LOG_ERROR, PS_LOG_WARN, PS_LOG_INFO };
     621
     622enum { PS_LOG_TO_STDERR, PS_LOG_TO_STDOUT };
     623
     624void psLogMsg(const char *name, int level, const char *fmt, ...);
     625void p_psVLogMsg(const char *name, int level, const char *fmt, va_list ap);
     626
     627int psSetLogDestination(int dest);
     628void psSetLogFormat(const char *fmt);
     629
     630int psSetLogLevel(int level);
     631  \end{verbatim}
     632  \begin{caption}{API for message logging}
     633    \hlabel{tabLogMsgAPI}
     634    The API for message logging.
     635  \end{caption}
     636\end{table}
     637
     638The public API for the logging facility (table \ref{tabLogMsgAPI})
     639should be provided in a header file \file{psLogMsg.h} which
     640is included by \file{psUtils.h}.
     641
     642The function \code{psSetLogLevel} may be used to set the current
     643level of logging; the previous value is returned.
     644The default value is \code{PS_LOG_INFO}. Valid values are 0---9
     645inclusive (note that only the first four are required to have
     646symbolic names).
     647
     648A call to \code{psLogMsg(name, level, msg, ...)} shall generate
     649a log message if \code{level} is less than or equal to the
     650value most recently set using \code{psSetLogLevel}. The function
     651\code{p_psLogMsg} is identical, except that it expects a
     652final \code{va_list} argument.
     653
     654The format of the log message shall be of the form:
     655\begin{verbatim}
     656YYYY:MM:DD hh:mm:ssZ|hostname|l|name            |msg
     657\end{verbatim}
     658\code{YYYY}, \code{MM}, \code{DD}, \code{hh}, \code{mm}, and \code{ss}
     659are the year, month (Jan == 1), day of the month, hours (0--23),
     660minutes, and seconds when the log message was received.  Note that the
     661timestamp is in ISO order, and that the timezone is GMT (hence the
     662\code{Z}).
     663
     664The \code{hostname} is returned by \code{gethostname}, \code{l} is a
     665letter associated with the level (\code{A}, \code{E}, \code{W}, and
     666\code{I} for \code{PS_LOG_ABORT}, \code{PS_LOG_ERROR}, \code{PS_LOG_WARN},
     667and \code{PS_LOG_INFO} respectively. Other levels are represented
     668numerically (\code{5} etc.). The other two field, \code{name} and
     669\code{msg} are arguments to \code{psLogMsg}; note that \code{name} has
     670a fixed width of 15 characters. If \code{msg} doesn't end in a newline,
     671a single newline is emitted to terminate the message.
     672
     673An example message is:
     674\begin{verbatim}
     6752004:02:24 20:14:18Z|alibaba.IfA.Hawaii.Edu|I|utils          |Hello World
     676\end{verbatim}
     677
     678Log messages are sent to the destination most recently set using
     679\code{psSetLogDestination}.  The only two values that are initially
     680defined are \code{PS_LOG_TO_STDERR} and \code{PS_LOG_TO_STDOUT} to
     681write to \code{stderr} and \code{stdout} respectively.
     682
     683The fields included in the log message may be controlled using \code{psSetLogFormat} which
     684expects a string consisting of the letters \code{H} (host), \code{L} (level), \code{M} (message),
     685\code{N} (name), and \code{T} (time).  The default is \code{HLMNT}.
     686
    73687%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    74688
     
    84698\end{itemize}
    85699
    86 \note{INSERT HERE STUFF FROM RHL'S \file{utils.pdf}}
     700\subsection{The Pan-STARRS \texttt{psDlist} doubly-linked list type}
     701\hlabel{psDlist}
     702
     703Pan-STARRS supports doubly linked lists through a type \code{psDlist}.
     704The type is defined in the header file \file{psDlist.h}, and consists
     705of the following definitions:
     706
     707\begin{verbatim}
     708typedef struct psDlistElem {
     709    struct psDlistElem *prev;           // previous link in list
     710    struct psDlistElem *next;           // next link in list
     711    void *data;                         // real data item
     712} psDlistElem;
     713
     714typedef struct {
     715    int n;                              // number of elements on list
     716    psDlistElem *head;                  // first element on list (may be NULL)
     717    psDlistElem *tail;                  // last element on list (may be NULL)
     718    psDlistElem *iter;                  // iteration cursor; private
     719} psDlist;
     720
     721enum {                                  // Special values of index into list
     722    psDlistHead = 0,                    // at head
     723    psDlistTail = -1,                   // at tail
     724    psDlistUnknown = -2,                // unknown position
     725    psDlistPrev = -3,                   // previous element
     726    psDlistNext = -4                    // next element
     727};
     728\end{verbatim}
     729
     730The API is:
     731
     732\begin{verbatim}
     733psDlist *psDlistAlloc(void *data);        // initial data item; may be NULL
     734
     735void psDlistFree(psDlist *list,          // list to destroy
     736                void (*elemFree)(void *)); // destructor for list data, or NULL
     737
     738/*
     739 * List maintainence functions
     740 */
     741psDlist *psDlistAdd(psDlist *list,      // list to add to (may be NULL)
     742                    void *data,         // data item to add
     743                    int where);         // index, psDlistHead, or psDlistTail
     744psDlist *psDlistAppend(psDlist *list,   // list to append to (may be NULL)
     745                       void *data);     // data item to add
     746void *psDlistRemove(psDlist *list,      // list to remove element from
     747                    void *data,         // data item to remove
     748                    int which);         // index of item, or psDlistUnknown,
     749                                        // or psDlistNext, or psDlistPrev
     750void *psDlistGet(const psDlist *list,   // list to retrieve element from
     751                 int which);            // index of item, or psDlistNext,
     752                                        // or psDlistPrev
     753/*
     754 * Conversions to/from arrays
     755 */
     756psVoidPtrArray *psDlistToArray(psDlist *dlist);
     757psDlist *psArrayToDlist(psVoidPtrArray *arr);
     758\end{verbatim}
     759
     760All data items placed onto lists (e.g. with \code{psDlistAdd})
     761shall have their reference counters (section \ref{secMemRefcounter}) incremented.
     762When elements
     763are removed from a list with \code{psDlistRemove}, they shall
     764have their reference counters decremented. The action of retrieving
     765data from a list (with \code{psDlistGet}) shall not affect
     766their reference counter.
     767
     768If \code{psDlistFree}'s argument \code{elemFree} is NULL, the
     769list should be deleted, but not the elements on it (although their
     770\code{refcounter}'s should be decremented).
     771
     772Iteration over all elements of the list is provided by the functions:
     773\begin{verbatim}
     774void psDlistSetIterator(psDlist *list, int where, int which);
     775void *psDlistGetNext(psDlist *list, int which);
     776void *psDlistGetPrev(psDlist *list, int which);
     777\end{verbatim}
     778in which the \code{where} argument must be \code{PS_DLIST_HEAD} or \code{PS_DLIST_TAIL},
     779to start at the head or tail of the list, and \code{psDlistGetNext} and \code{psDlistGetPrev}
     780return the next/previous element. The argument \code{which} identifies which of potentially
     781many iteration cursors should be used; it must currently always be \code{0}.
     782
     783Explicit traversal of the list using the \code{psDlistElem}'s
     784\code{prev} and \code{next} pointers is also supported.
     785
     786The routines to convert to and from \code{psVoidPtrArray}s,
     787\code{psDlistToArray} and \code{psArrayToDlist} shall ensure that the
     788objects on the arrays and lists have had their reference pointers
     789correctly incremented (see section \ref{secArrayVoidPtr}) (\eg{} that
     790\code{psArrayToDlist(psDlistToArray(list))} returns a properly-formed
     791\code{psDlist}).
     792
     793\subsection{The \PS{} Array types}
     794
     795\begin{table}
     796  \begin{verbatim}
     797  \end{verbatim}
     798  \begin{caption}{The array creation macros defined in \file{psArray.h}}
     799    \hlabel{tabPsArray}
     800  \end{caption}
     801\end{table}
     802
     803\subsubsection{Arrays of Simple Types}
     804
     805Any \PS/ datatype \code{psType} may be associated with an array type
     806\code{psTypeArray}:
     807\begin{verbatim}
     808typedef struct {
     809  int size;
     810  int n;
     811  psType *arr;
     812} psTypeArray;
     813\end{verbatim}
     814with associated constructors and a destructor:
     815\begin{verbatim}
     816psTypeArray *psTypeAlloc(int n, int size);
     817psTypeArray *psTypeRealloc(psTypeArray *arr, int n);
     818void psTypeFree(psTypeArray *arr); 
     819\end{verbatim}
     820
     821The argument \code{n} is the dimension of the array; \code{size}
     822is the number of elements allocated ($s \ge n$).
     823
     824This type and functions may be declared and defined using two macros
     825from \file{psArray.h} (table \ref{tabPsArray}),
     826\code{PS_DECLARE_ARRAY_TYPE(psType)} and
     827\code{PS_CREATE_ARRAY_TYPE(psType)}.  The former defines the typedef
     828and declares the prototypes (and is thus suitable for use in a
     829header file); the latter generates the code for the three functions
     830\code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one
     831source file for a given type).
     832
     833The \code{psType} should be a single word (e.g. \code{psXY}); in particular,
     834there is no requirement to support a pointer type (\eg{} \code{psXY *});
     835see next section.
     836
     837\subsubsection{Arrays of Pointer Types}
     838
     839The data type created with \code{PS_CREATE_ARRAY_TYPE} (\code{psType})
     840contains an array of \code{psType}s not
     841pointers to \code{psType}s; this means that the individual elements are
     842not allocated using \code{psTypeAlloc}, are not correctly initialized,
     843and shouldn't be individually deleted with \code{psTypeFree};
     844
     845If you wish to use arrays of pointers, use the macros
     846\code{PS_DECLARE_ARRAY_PTR_TYPE(psType)} and
     847\code{PS_CREATE_ARRAY_PTR_TYPE(psType)} (table \ref{tabPsArray}). These
     848create types \code{typedef psType *psTypePtr} and \code{psTypePtrArray}:
     849\begin{verbatim}
     850typedef struct {
     851  int size;
     852  int n;
     853  psTypePtr *arr;
     854} psTypePtrArray;
     855\end{verbatim}
     856with associated constructors and a destructor:
     857\begin{verbatim}
     858psTypePtrArray *psTypePtrAlloc(int n, int size);
     859psTypePtrArray *psTypePtrRealloc(psTypePtrArray *arr, int n);
     860void psTypePtrArrayFree(psTypePtrArray *arr); 
     861\end{verbatim}
     862
     863These constructors create arrays of \code{psType *} and call
     864\code{psTypeAlloc} and \code{psTypeFree} to allocate and free the
     865elements. As for the simple arrays, The former defines the typedef and
     866declares the prototypes (and is thus suitable for use in a header
     867file) and the latter generates the code for the three functions
     868\code{psType(Alloc|Realloc|Free} (and should thus appear in exactly one
     869source file for a given type).
     870
     871The objects pointed to by these types have had their \code{refCounter}s
     872incremented (see \ref{secMemRefcounter}); to remove an element from the array you
     873need to say something like:
     874\begin{verbatim}
     875  psTypePtrArray *pt = psTypePtrArrayAlloc(10, 10);
     876  psType *xy = psMemDecrRefCounter(pt->arr[0]);
     877  pt->arr[0] = NULL;
     878\end{verbatim}
     879
     880\subsubsection{Arrays of \texttt{void *}}
     881\hlabel{secArrayVoidPtr}
     882
     883Arrays of \code{void *} are different, as the need an explicitly-specified
     884destructor.
     885
     886\file{psArray.h} shall specify a type \code{psVoidPtrArray} that
     887behaves in all respects as if it had been created with:
     888\begin{verbatim}
     889typedef void *psVoidPtr;
     890PS_DECLARE_ARRAY_TYPE(psVoidPtr);
     891PS_CREATE_ARRAY_TYPE(psVoidPtr);
     892\end{verbatim}
     893except that its destructor is specified as:
     894\begin{verbatim}
     895void psVoidPtrArrayFree(psVoidPtrArray *arr,      // array to destroy
     896                       void (*elemFree)(void *)); // destructor for array data
     897\end{verbatim}
     898
     899The routine \code{psVoidPtrArrayFree} assumes that all pointers
     900had their reference counters incremented
     901when they were inserted onto the array.\footnote{%
     902  \eg{} \code{va->arr[i] = psMemIncrRefCounter(ptr);}}
     903
     904If \code{psVoidPtrArrayFree}'s argument \code{elemFree} is NULL, the
     905list should be deleted, but not the elements on it (although their
     906\code{refcounter}'s should be decremented).
     907
     908\subsubsection{Examples of Array Types}
     909
     910The following is a complete C program that illustrates the use of
     911\code{array}s.
     912\begin{verbatim}
     913#include "psUtils.h"
     914
     915typedef struct {
     916    int x, y;
     917} psXY;
     918
     919psXY *psXYAlloc(void)
     920{
     921    return psAlloc(sizeof(psXY));
     922}
     923
     924void psXYFree(psXY *xy)
     925{
     926    psFree(xy);
     927}
     928
     929PS_DECLARE_ARRAY_TYPE(psXY);
     930PS_CREATE_ARRAY_TYPE(psXY);
     931
     932PS_DECLARE_ARRAY_PTR_TYPE(psXY);
     933PS_CREATE_ARRAY_PTR_TYPE(psXY);
     934
     935int main(void)
     936{
     937    psXYArray *t = psXYArrayAlloc(10, 15);
     938    psXYPtrArray *pt = psXYPtrArrayAlloc(10, 10);
     939
     940    for (int i = 0; i < t->n; i++) {
     941        t->arr[i].x = i;
     942        pt->arr[i]->y = 10*i;
     943    }
     944
     945    t = psXYArrayRealloc(t, 5);
     946    t = psXYArrayRealloc(t, 8);
     947
     948    for (int i = 0; i < t->n; i++) {
     949        printf("%d %d  ", t->arr[i].x, pt->arr[i]->y);
     950    }
     951    printf("\n");
     952   
     953    psXYArrayFree(t);
     954
     955    psXY *xy = psMemDecrRefCounter(pt->arr[0]);
     956    pt->arr[0] = NULL;
     957    psXYFree(xy);   
     958   
     959    psXYPtrArrayFree(pt);
     960
     961    psMemCheckLeaks(0, NULL, stderr);
     962
     963    return 0;
     964}
     965\end{verbatim}
     966
     967\subsection{Hash Tables}
     968\hlabel{psHash}
     969
     970\begin{table}
     971  \begin{verbatim}
     972typedef struct HashTable psHash;
     973
     974psHash *psHashAlloc(int nbucket);       // initial number of buckets
     975void psHashFree(psHash *table,          // hash table to be freed
     976               void (*itemFree)(void *item)); // how to free hashed data;
     977                                        // or NULL
     978
     979void *psHashInsert(psHash *table,       // table to insert in
     980                   const char *key,     // key to use
     981                   void *data,          // data to insert
     982                   void (*itemFree)(void *item)); // how to free hashed data;
     983                                        // or NULL
     984void *psHashLookup(psHash *table,       // table to lookup key in
     985                   const char *key);    // key to lookup
     986
     987void *psHashRemove(psHash *table,       // table to lookup key in
     988                   const char *key);    // key to lookup
     989  \end{verbatim}
     990  \begin{caption}{The public API for hash tables from \file{psHash.h}}
     991    \hlabel{tabPsHash}
     992  \end{caption}
     993\end{table}
     994
     995The public API for the hash table (table \ref{tabPsHash})
     996should be provided in a header file \file{psHash.h} which
     997is included by \file{psUtils.h}.
     998\footnote{
     999  We choose not to use the posix function \code{hcreate},
     1000  \code{hdestroy}, and \code{hsearch} as they only support
     1001  a single hash table at any one time.}
     1002
     1003A hash table is an abstract type \code{psHash}.  The argument
     1004\code{nbucket} to \code{psHashAlloc} is a non-binding suggestion
     1005from the user for the initial size of the hash table.
     1006
     1007If the \code{itemFree} argument to \code{psHashFree} is non-NULL,
     1008it will be used to delete the data items that have been stored
     1009in the hash table; if it is NULL this is the responsibility of
     1010the caller.
     1011
     1012The routine \code{psHashInsert} must provide a non-NULL \code{itemFree}
     1013argument if it wishes to change the value previously inserted keys;
     1014if \code{itemFree} is NULL attempting to insert a pre-existing key
     1015is an error, and the routine will return NULL.  If  \code{psHashInsert}
     1016succeeds it returns \code{data}.
     1017
     1018\code{psHashLookup} returns the \code{data} associated with the
     1019key, or NULL if the key's invalid.
     1020
     1021\code{psHashRemove} removes the entry associated with the
     1022key from the table, and returns the \code{data}; if the key's invalid it returns NULL.
     1023
     1024\subsection{Miscellaneous Utilities}
     1025
     1026The API for miscellaneous \PS{} utilities is provided by \file{psMisc.h}
     1027which shall be included by \file{psUtils.h}.
     1028
     1029\begin{table}
     1030  \begin{verbatim}
     1031#define PS_CONCAT(A, B) A ## B          // Expands to AB
     1032#define PS_CONCAT2(A, B) PS_CONCAT(A, B) // Also expands to AB
     1033#define PS_CONCAT3(A, B, C) A ## B ## C // Expands to ABC
     1034
     1035#define PS_STRING(S) #S                 // converts argument S to string
     1036   
     1037void psAbort(const char *name, const char *fmt, ...);
     1038void psError(const char *name, const char *fmt, ...);
     1039char *psStringCopy(const char *str);
     1040  \end{verbatim}
     1041  \begin{caption}{The utilities provided by \file{psMisc.h}}
     1042      \hlabel{psMisc}
     1043  \end{caption}
     1044\end{table}
     1045
     1046\code{psAbort} shall call \code{psMsgLog} with a level of \code{PS_LOG_ABORT},
     1047and then call \code{abort}.
     1048\code{psError} shall call \code{psMsgLog} with a level of \code{PS_LOG_ERROR},
     1049and then return.
     1050In cases of doubt, a good choice for
     1051\code{name} is \code{__func__}.
     1052
     1053\code{psStringCopy} shall allocate and return a copy of the input string.
    871054
    881055%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    6411608
    6421609%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     1610
     1611\subsection{Image handling}
     1612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     1613
     1614\subsection{Basic Images}
     1615
     1616The most important data product produced by the telescope is an image.
     1617The simplest image is a 2-D collection of pixels, each with some
     1618value.  We require a basic image data type:
     1619
     1620\begin{verbatim}
     1621/// basic image data structure.
     1622typedef struct psImage {
     1623    psType type;                        ///< image data type and dimension
     1624    int nx, ny;                         ///< size of image
     1625    int x0, y0;                         ///< data region relative to parent
     1626    union {
     1627        psF32 **rows;                   ///< == rows_f32
     1628        psS8  **rows_s8;                ///< pointers to psS8 data
     1629        psS16 **rows_s16;               ///< pointers to psS16 data
     1630        psS32 **rows_s32;               ///< pointers to psS32 data
     1631        psU8  **rows_u8;                ///< pointers to psU8 data
     1632        psU16 **rows_u16;               ///< pointers to psU16 data
     1633        psU32 **rows_u32;               ///< pointers to psU32 data
     1634        psF32 **rows_f32;               ///< pointers to psF32 data
     1635        psF64 **rows_f64;               ///< pointers to psF64 data
     1636    } rows;
     1637    struct psImage *parent;             ///< parent, if a subimage
     1638    struct psImage *children;           ///< children of this region
     1639    int Nchildren;                      ///< number of subimages
     1640} psImage;
     1641\end{verbatim}
     1642
     1643This structure represents an image consisting of a 2-D array of
     1644pixels.  The size of this array is given by the elements \code{(nx,
     1645ny)}.  The data type of the pixel is defined by the \code{psType type}
     1646entry (see \ref{TBD}).  (n.b. that for FITS images, these values are
     1647restricted to the datatypes equivalent to the valid BITPIX values 8,
     164816, 32, -32, -64).  The image represented in the data structure may
     1649represent a subset of the pixels in a complete array.  The offset of
     1650the \code{(0,0)} pixel in this array relative to the parent array is
     1651given by the elements \code{(x0,y0)}.  The structure may include
     1652references to subrasters (\code{children, Nchildren}) and/or to a
     1653containing array (\code{parent}).
     1654
     1655We require a variety of functions to manipulate these image
     1656structures, including creation, destruction, input, output, and
     1657various manipulations of the pixels.  The required functions are
     1658listed below.
     1659
     1660Create an image of a specified width, height, and data type.  This
     1661function must allow any of the valid image data types and not restrict
     1662to the valid FITS BITPIX types.
     1663\begin{verbatim}
     1664psImage *
     1665psImageAlloc (int nx,                   ///< image width
     1666              int ny,                   ///< image height
     1667              psType type)              ///< image data type
     1668\end{verbatim}
     1669
     1670Define a subimage of the specified area of the given image.  This
     1671function must return an error if the requested subset area lies
     1672outside of the parent image.
     1673\begin{verbatim}
     1674psImage *
     1675psImageSubset (psImage *image,          ///< parent image
     1676               int nx,                  ///< subimage width (<= image.nx - x0) 
     1677               int ny,                  ///< subimage width (<= image.ny - y0) 
     1678               int x0,                  ///< subimage x-offset (0 <= x0 < nx)   
     1679               int y0)                  ///< subimage y-offset (0 <= y0 < ny)   
     1680\end{verbatim}
     1681
     1682Free the memory associated with a specific image.  \note{does this
     1683  free the input structure or just the allocated elements?}  Free the
     1684  children of the image if they exist.
     1685\begin{verbatim}
     1686void
     1687psImageFree (psImage *image)            ///< free this image
     1688\end{verbatim}
     1689
     1690Free the memory associated with the children of a specific image. 
     1691\begin{verbatim}
     1692int
     1693psImageFreeChildren (psImage *image)    ///< free children of this image
     1694\end{verbatim}
     1695
     1696Create a copy of the specified image.  If the output target pointer is
     1697not NULL, place the result in the specified structure.
     1698\begin{verbatim}
     1699psImage *
     1700psImageCopy (psImage *output,           ///< target structure for output image data
     1701             psImage *input)            ///< copy this image
     1702\end{verbatim}
     1703
     1704Extract pixels from rectlinear region to a vector (array of floats).
     1705The output vector contains either \code{nx} or \code{ny} elements,
     1706based on the value of the direction: e.g., if \code{direction} is
     1707\tbd{+x}, there are \code{nx} elements.  The input region is collapsed
     1708in the perpendicular direction, and each element of the output vectors
     1709is derived from the statistics of the pixels at that direction
     1710coordinate.  The statistic used to derive the output vector value is
     1711specified by \code{psStats stats}.
     1712\begin{verbatim}
     1713psFloatArray *
     1714psImageSlice (psImage *input,           ///< extract slice from this image
     1715              int x,                    ///< starting x coord of region to slice
     1716              int y,                    ///< starting y coord of region to slice
     1717              int nx,                   ///< width of region in x
     1718              int ny,                   ///< width of region in y
     1719              int direction,            ///< direction of vector along slice
     1720              psStats *stats)           ///< defines statistics used to find output values
     1721\end{verbatim}
     1722
     1723Extract pixels from an image along a line to a vector (array of
     1724floats).  The vector \code{xs,ys} - \code{xe,ye} forms the basis of
     1725the output vector.  Pixels are considered in a rectangular region of
     1726width \code{dw} about this vector.  The input region is collapsed in
     1727the perpendicular direction, and each element of the output vector
     1728represents a pixel-sized boxes, where the value is derived from the
     1729statistics of the pixels interpolated along the perpendicular
     1730direction.  The statistic used to derive the output vector value is
     1731specified by \code{psStats stats}.
     1732\begin{verbatim}
     1733psFloatArray *
     1734psImageCut (psImage *input,             ///< extract cut from this image
     1735            float xs,                   ///< starting x coord of cut
     1736            float ys,                   ///< starting y coord of cut
     1737            float xe,                   ///< ending x coord of cut
     1738            float ye,                   ///< ending y coord of cut
     1739            float dw,                   ///< width of cut
     1740            psStats *stats)             ///< defines statistics used to find output values
     1741 \end{verbatim}
     1742
     1743
     1744Extract radial annulii data to a vector.  A vector is constructed
     1745where each vector elements is derived from the statistics of the
     1746pixels which land in one of a sequence of annulii.  The annulii are
     1747centered on the image pixel coordinate \code{x,y}, and have width
     1748\code{dr}.  The number of annulii is $radius / dr$.  The statistic
     1749used to derive the output vector value is specified by \code{psStats
     1750stats}
     1751\begin{verbatim}
     1752psFloatArray *
     1753psImageRadialCut (psImage *input,       ///< extract profile from this image
     1754                  float x,              ///< center x coord of annulii
     1755                  float y,              ///< center y coord of annulii
     1756                  float radius,         ///< outer radius of annulii
     1757                  float dr,             ///< radial step size of annulii
     1758                  psStats *stats)       ///< defines statistics used to find output values
     1759\end{verbatim}
     1760
     1761%/// Extract a 2-d contour from an image at the given threshold.
     1762%\begin{verbatim}
     1763%psFloatArray *
     1764%psImageContour (psImage *input,        ///< create contour for this image
     1765%               float threshold,        ///< contour image at this threshold
     1766%               int binning)            ///< bin image by this value for contour calculation
     1767%\end{verbatim}
     1768
     1769Rebin image to new scale.  A new image is constructed in which the
     1770dimensions are reduced by a factor of \code{scale}.  The output image
     1771represents a one-to-one mapping of the pixels in the input image,
     1772except for edge effects.  Each pixel in the output image is derived
     1773from the statistics of the corresponding input image pixels based on
     1774the statistics specified by \code{psStats stats}.
     1775\tbd{interpolation?}
     1776\begin{verbatim}
     1777psImage *
     1778psImageRebin (psImage *input,           ///< rebin this image
     1779              float scale,              ///< rebinning scale: doutput = scale*dinput
     1780              psStats *stats)           ///< defines statistics used to find output values
     1781\end{verbatim}
     1782
     1783Rotate the input image by given angle, specified in degrees.  The
     1784output image must contain all of the pixels from the input image in
     1785their new frame.  Pixels in the output image which do not map to input
     1786pixels should be set of \tbd{value}.  The center of rotation is always
     1787the center pixel of the image.  The rotation is specified in the sense
     1788that a positive value is a clock-wise rotation. 
     1789\begin{verbatim}
     1790psImage *
     1791psImageRotate (psImage *input,          ///< rotate this image
     1792               float angle)             ///< rotate by this amount (degrees)
     1793\end{verbatim}
     1794
     1795Shift image by an arbitrary number of pixels (\code{dx,dy}) in either
     1796direction.  If the shift values are fractional, the output pixel
     1797values shoul interpolate between the input pixel values.  The output
     1798image has the same dimensions as the input image.  Pixels which fall
     1799off the edge of the output image are loast.  Newly exposed pixels are
     1800set to the value given by \code{exposed}. 
     1801\begin{verbatim}
     1802psImage *
     1803psImageShift (psImage *input,           ///< shift this image
     1804              float dx,                 ///< shift by this amount in x
     1805              float dy,                 ///< shift by this amount in y
     1806              float exposed)            ///< set exposed pixels to this value
     1807\end{verbatim}
     1808
     1809Roll image by an integer number of pixels in either direction.  The
     1810output image is the same dimensions as the input image.  Edge pixels
     1811wrap to the other side (no values are lost).
     1812\begin{verbatim}
     1813psImage *
     1814psImageRoll (psImage *input,            ///< roll this image
     1815             int dx,                    ///< roll this amount in x
     1816             int dy)                    ///< roll this amount in y
     1817\end{verbatim}
     1818
     1819Determine statistics for image (or subimage).  The statistics to be
     1820determined are specified by \code{psStats stats}.
     1821\begin{verbatim}
     1822psStats *
     1823psImageGetStats (psImage *input,        ///< image (or subimage) to calculate stats
     1824                 psStats *stats)        ///< defines statistics to be calculated
     1825\end{verbatim}
     1826
     1827Construct a histogram from an image (or subimage).  The histogram to
     1828generate is specified by \code{psHistogram hist}.
     1829\begin{verbatim}
     1830psHistogram *
     1831psImageHistogram (psHistogram *hist,    ///< input histogram description & target
     1832                  psImage *input)       ///< determine histogram of this image
     1833\end{verbatim}
     1834
     1835Fit a 2-D polynomial surface to an image.  The input structure
     1836\code{coeffs} contains the desired order and terms of interest.
     1837\tbd{how do we specify the renomalization?}
     1838\begin{verbatim}
     1839psPolynomial2D *
     1840psImageFitPolynomial (psImage *input,   ///< image to fit
     1841                      psPolynomial2D *coeffs) ///< coefficient structure carries in desired terms
     1842\end{verbatim}
     1843
     1844Evaluate a 2-D polynomial surface to image pixels.  Given the input
     1845polynomial coefficients, return an image generated on the basis of the
     1846input image pixels which evaluates the polynomial for all pixels in
     1847the image.a
     1848\begin{verbatim}
     1849int
     1850psImageEvalPolynomial (psImage *input,  ///< image to fit
     1851                       psPolynomial2D *coeffs) ///< coefficient structure carries in desired terms
     1852\end{verbatim}
     1853
     1854Read an image or subimage from a named file.  This function is a
     1855wrapper to the FITS library function.  The input parameters allow or a
     1856subimage to be read.  The starting pixel of the region is specified by
     1857\code{x,y}, while the dimensions of the requested region are specified
     1858by \code{nx,ny}.  A value of -1 for these two parameters specifies the
     1859full array of the requested image.  If the native image is a cube, the
     1860value of z specifies the requested slice of the image.  The data is
     1861read from the extension specified by extname (matching the EXTNAME
     1862keyword) or by the extnum value (with -1 representing the PHU, 0 the
     1863first extension, etc).  This function must return an error if any of
     1864the specified parameters are out of range for the data in the image
     1865file, if the specified image file does not exist.  \tbd{what do we do
     1866with a 0D or 1D image?}
     1867\begin{verbatim}
     1868psImage *
     1869psImageReadSection (psImage *output,    ///< place data in this structure for output
     1870                    int x,              ///< starting x coord of region
     1871                    int y,              ///< starting y coord of region
     1872                    int nx,             ///< x size of region (-1 for full range)
     1873                    int ny,             ///< y size of region (-1 for full range)
     1874                    int z,              ///< plane of interest
     1875                    char *extname,      ///< MEF extension name ("PHU" for primary header)
     1876                    int extnum,         ///< MEF extension sequence number (-1 for PHU)
     1877                    char *filename)     ///< file to read data from
     1878\end{verbatim}
     1879 
     1880Read an image or subimage from file descriptor.  The input parameters
     1881and their behavior for this function are identical with those in
     1882\code{psImageReadSection}.
     1883\begin{verbatim}
     1884psImage *
     1885psImageFReadSection (psImage *output,   ///< place data in this structure for output
     1886                     int x,             ///< starting x coord of region           
     1887                     int y,             ///< starting y coord of region           
     1888                     int dx,            ///< x size of region (-1 for full range)         
     1889                     int dy,            ///< y size of region (-1 for full range)         
     1890                     int z,             ///< plane of interest                     
     1891                     char *extname,     ///< MEF extension name ("PHU" for primary header)                         
     1892                     FILE *f)           ///< file descriptor to read data from             
     1893\end{verbatim}
     1894
     1895Write an image section to named file, which may exist.  This
     1896operatation may write a portion of an image over the existing bytes of
     1897an existing image.  If the file does not exist, it should be created.
     1898If the specified extention does not exist, it should be created.  If
     1899an extension is specified and no PHU exists, a basic PHU should be
     1900created. 
     1901\begin{verbatim}
     1902psImage *
     1903psImageWriteSection (psImage *input,    ///< image to write out
     1904                     int x,             ///< starting x coord of region           
     1905                     int y,             ///< starting y coord of region           
     1906                     int z,             ///< plane of interest                     
     1907                     char *extname,     ///< MEF extension name ("PHU" for primary header)                         
     1908                     char *filename)    ///< file to write data to                 
     1909\end{verbatim}
     1910
     1911Write an image section to file descriptor.
     1912\begin{verbatim}
     1913psImage *
     1914psImageFWriteSection(psImage *input,    ///< image to write out
     1915                     int x,             ///< starting x coord of region           
     1916                     int y,             ///< starting y coord of region           
     1917                     int z,             ///< plane of interest                     
     1918                     char *extname,     ///< MEF extension name                   
     1919                     FILE *f)           ///< file descriptor to write data to             
     1920\end{verbatim}
     1921
     1922Read header data from a FITS image file into a \code{psMetaData}
     1923structure.  If the named extension does not exist, the function should
     1924return an error. 
     1925\begin{verbatim}
     1926struct psMetadata *
     1927psImageReadHeader(struct psMetadata *output,    ///< read data to this structure
     1928                  char *extname,        ///< MEF extension name ("PHU" for primary header)
     1929                  int extnum,           ///< MEF extension number (-1 for "PHU", 0 : Nextend - 1)
     1930                  char *filename)       ///< file to read from
     1931\end{verbatim}
     1932
     1933Read header data from a FITS image file descriptor into a \code{psMetaData}
     1934structure. 
     1935\begin{verbatim}
     1936struct psMetadata *
     1937psImageFReadHeader (struct psMetadata *output, ///< read data to this structure
     1938                   char *extname,       ///< MEF extension name ("PHU" for primary header)
     1939                   int extnum,          ///< MEF extension number (-1 for "PHU", 0 : Nextend - 1)
     1940                   FILE *f)             ///< file descriptor to read from
     1941\end{verbatim}
     1942
     1943Perform a 2-D FFT on the specified image.
     1944\begin{verbatim}
     1945psImage *
     1946psImageFFT (psImage *input,             ///< image to FFT
     1947            int direction)              ///< FFT direction
     1948\end{verbatim}
     1949
     1950Clip image values outside of range to given values.  All pixels with
     1951values $<$ min are set to the value vmin. All pixels with values $>$
     1952max are set to the value vmax.
     1953\begin{verbatim}
     1954int
     1955psImageClip (psImage *input,            ///< clip this image
     1956             float min,                 ///< clip pixels with values < min
     1957             float vmin,                ///< set min-clipped pixels to vmin
     1958             float max,                 ///< clip pixels with values > max
     1959             float vmax)                ///< set max-clipped pixels to vmax
     1960\end{verbatim}
     1961
     1962Clip NaN image pixels to given value.  Pixels with NaN or Inf values
     1963are set to the specified value.
     1964\begin{verbatim}
     1965int
     1966psImageClipNaN (psImage *input,         ///< clip this image
     1967                float value)            ///< set nan pixels to this value
     1968\end{verbatim}
     1969
     1970Overlay subregion of image with another image.  Replace the pixels in
     1971the \code{image} which correspond to the pixels in \code{overlay} with
     1972values derived from the values in \code{image} and \code{overlay}
     1973based on the given operator.  Valid operators are ``='' (set image
     1974value to overlay value), ``+'' (add overlay value to image value),
     1975``-'' (subtract overlay from image), ``*'' (multiply overlay times
     1976image), ``/'' (divide image by overlay). 
     1977\begin{verbatim}
     1978int
     1979psImageOverlaySection (psImage *image,          ///< input image
     1980                psImage *overlay,       ///< image to overlay
     1981                int x0,                 ///< x offset of overlay subimage
     1982                int y0,                 ///< y offset of overlay subimage
     1983                char *operator)         ///< overlay operation
     1984\end{verbatim}
    6431985
    6441986\subsection{Astrometry}
     
    11812523
    11822524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     2525
    11832526\subsection{Dates and times}
    11842527
     
    11862529
    11872530%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1188 \subsection{Image handling}
    1189 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1190 Gene --- done.
    11912531
    11922532\subsection{Metadata}
    1193 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    1194 Gene --- done.
     2533
     2534This section addresses the question of how \PS{} metadata should be
     2535represented in memory. We do not (yet) address how it should be
     2536represented on disk.
     2537
     2538\subsubsection{Metadata Representation}
     2539
     2540We propose that an item of metadata be represented as a C structure with at least the following
     2541fields:
     2542\begin{verbatim}
     2543/*
     2544 * A struct to define a single item of metadata
     2545 */
     2546typedef struct {
     2547    const int id;                       // unique ID for this item
     2548   
     2549    char *name;                         // Name of item
     2550    psMetaDataType type;                // type of this item
     2551    const union {
     2552        float f;                        // floating value
     2553        int i;                          // integer value
     2554        void *v;                        // other type
     2555    } val;                              // value of metadata
     2556    char *comment;                      // optional comment ("", not NULL)
     2557} psMetaDataItem;
     2558\end{verbatim}
     2559
     2560The \code{id} is a unique identifier for this item of metadata; experience
     2561shows that such tags are useful.
     2562
     2563The \code{psMetaDataType type} entry specifies the type of the data
     2564being represented; the possibilities are listed in section \ref{metadataTypes}.
     2565
     2566\paragraph{Possible Types of Metadata}
     2567\label{metadataTypes}
     2568
     2569The possible types of metadata are identified by the enumerated type
     2570\code{psMetaDataType} (see also table \ref{tabMetaDataTypes}); the initial defined values are:
     2571\begin{verbatim}
     2572/*
     2573 * Possible types of metadata. 
     2574 */
     2575typedef enum {                          // type of val is:
     2576    psMetaFloat,                        // float (.f)
     2577    psMetaInt,                          // int (.i)
     2578    psMetaStr,                          // string (.v)
     2579    psMetaImg,                          // image (.v)
     2580    psMetaJPEG,                         // JPEG (.v)
     2581    psMetaPNG,                          // PNG (.v)
     2582    psMetaAstrom,                       // astrometric coefficients (.v)
     2583    psMetaUnknown,                      // other (.v)
     2584    psMetaNType                         // Number of types; must be last
     2585} psMetaDataType;
     2586\end{verbatim}
     2587
     2588\begin{table}
     2589\begin{tabular}{llll}
     2590\textbf{Value} & \textbf{Type} & \textbf{member of union} & \textbf{Comments}\\
     2591\hline
     2592psMetaFloat & float & f & value, not pointer, is stored \\
     2593psMetaInt & int & i &  value, not pointer, is stored \\
     2594psMetaStr & string & v &  value, not pointer to original, is stored \\
     2595psMetaImg & psImage & v &  \\
     2596psMetaJPEG & JPEG & v &  \\
     2597psMetaPNG & PNG & v &  \\
     2598psMetaAstrom & psAstrom & v &  \\
     2599psMetaUnknown & other & v &  \\
     2600psMetaNType & (none) & & The number of types defined
     2601\end{tabular}
     2602\begin{caption}{Supported Metadata Types}
     2603\label{tabMetaDataTypes}
     2604  Possible types of metadata
     2605\end{caption}
     2606\end{table}
     2607
     2608\subsubsection{Collections of Metadata}
     2609
     2610\begin{verbatim}
     2611typedef struct {
     2612    psDlist *list;                      // list of psMetaDataItem
     2613    psHash *table;                      // hash table of the same metadata
     2614} psMetaDataSet;
     2615\end{verbatim}
     2616
     2617The type \code{psMetaDataSet} is a container class for metadata. Note that there are
     2618in fact \emph{two} representations of the metadata (each \code{psMetaDataItem} appears
     2619on both).
     2620
     2621We are using the standard \PS{} doubly-linked list types \code{psDlist} and  \code{psHash}
     2622(see \href{file:utils#psDlist}{utils.pdf:psDlist} and \href{file:utils#psHash}{utils.pdf:psHash} for details).
     2623For example:
     2624\begin{verbatim}
     2625    for (int i = 0; i < 10; i += 5) {
     2626        float sqrti = sqrt(i);
     2627        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_INT, &i, NULL, "const.%d", i));
     2628        psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_FLOAT, &sqrti, "square root", "const.sqrt%d", i));
     2629    }
     2630    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR, "Bonjour", "French", "lang.hello"));
     2631    /*
     2632     * Remove a key
     2633     */
     2634    psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
     2635    /*
     2636     * Print all metadata
     2637     */
     2638    fprintf(stdout, "------\n");
     2639    psMetaDataSetIterator(ms);
     2640    while ((meta = psMetaDataGetNext(ms, NULL)) != NULL) {
     2641        psMetaDataItemPrint(stdout, meta, "");
     2642    }
     2643    /*
     2644     * Look up a key by name
     2645     */
     2646    fprintf(stdout, "------\n");
     2647    fprintf(stdout, "Looking up by name:\n");
     2648    meta = psMetaDataLookup(ms, "const.5");
     2649    if (meta != NULL) {
     2650        psMetaDataItemPrint(stdout, meta, "");
     2651    }
     2652\end{verbatim}
     2653
     2654\subsubsection{Naming convention for MetaData}
     2655
     2656The \code{psMetaDataItem} struct includes a name.  This name should be of
     2657the form \code{name1.name2.name3$\cdots$}, e.g.\hfil\break
     2658\null\qquad\qquad\code{IPP.phase1.ota12.biassec}.
     2659
     2660We shall set in place a system for assigning the top-level `domains'
     2661to responsible individuals, and for gathering a complete list of
     2662all metadata names in use throughout the project.
     2663
     2664\paragraph{Support for Multiple Values for a Given Name}
     2665
     2666\begin{verbatim}
     2667    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     2668                                           "Bonjour", "French", "lang.hello"));
     2669    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     2670                                           "Aloha", "Hawaiian", "lang.hello"));
     2671    psMetaDataAppend(ms, psMetaDataItemAlloc(PS_META_STR | PS_META_NON_UNIQUE,
     2672                                           "Good Morning", "English", "lang.hello"));
     2673    /*
     2674     * Print all metadata starting "lang"
     2675     */
     2676    psMetaDataSetIterator(ms);
     2677    while ((meta = psMetaDataGetNext(ms, "lang")) != NULL) {
     2678        psMetaDataItemPrint(stdout, meta, "");
     2679    }
     2680\end{verbatim}
     2681
     2682It is an unfortunate fact that certain metadata keywords (such as \code{COMMENT} in a FITS header)
     2683may be repeated with different values.  The \code{psMetaDataAppend} routine is required
     2684to check that all metadata names are unique unless the type is qualified as \code{PS_META_NON_UNIQUE};
     2685in this case a unique integer will be added to each name that you specify. In this case,
     2686you may either delete individual element separately or as a complete set:
     2687\begin{verbatim}
     2688psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello.0"));
     2689psMetaDataItemFree(psMetaDataRemove(ms, "lang.hello"));
     2690\end{verbatim}
     2691
     2692\subsubsection{MetaData APIs}
     2693
     2694\begin{verbatim}
     2695psMetaDataItem *psMetaDataItemAlloc(
     2696    psMetaDataType type,                // type of this piece of metadata
     2697    const void *val,                    // value of new item
     2698                                        // N.b. a pointer even if the item
     2699                                        // is of type e.g. int
     2700    const char *comment,                // comment associated with item
     2701    const char *name,                   // name of new item of metadata (may be an sprintf format)
     2702    ...);                               // possible arguments for name format
     2703
     2704void psMetaDataItemFree(psMetaDataItem *ms); // piece of metadata to destroy
     2705
     2706psMetaDataSet *psMetaDataSetAlloc(void);          // make a new set of metadata
     2707void psMetaDataSetDel(psMetaDataSet *ms); // destroy a set of metadata
     2708
     2709/*****************************************************************************/
     2710/*
     2711 * Utilities
     2712 */
     2713psMetaDataItem *psMetaDataAppend(psMetaDataSet *restrict ms, psMetaDataItem *restrict item);
     2714psMetaDataItem *psMetaDataRemove(psMetaDataSet *restrict ms, const char *restrict key);
     2715
     2716void psMetaDataSetIterator(psMetaDataSet *ms);
     2717psMetaDataItem *psMetaDataGetNext(psMetaDataSet *ms);
     2718psMetaDataItem *psMetaDataLookup(const psMetaDataSet *ms, const char *key);
     2719
     2720void psMetaDataItemPrint(FILE *fd,              // file descriptor to write to
     2721                         const psMetaDataItem *ms); // item of metadata to print
     2722\end{verbatim}
    11952723
    11962724\subsection{Detector and sky positions}
     
    13752903\subsection{Photometry}
    13762904
    1377 Gene --- done.
     2905
     2906Photometric observations are performed in a photometric system, and
     2907are must be related to other photometric systems.  We require a data
     2908structure which defines a photometric system, as well as a structure
     2909to define the transformation between photometric systems. 
     2910
     2911The photometric system is defined by the psPhotSystem structure. 
     2912A photometric system is identified by a human-readable \code{name}
     2913(ie, SDSS.g, Landolt92.B, GPC1.OTA32.r).  Each photometric system is
     2914given a unique identifier \code{ID}.  Observations taken with a
     2915specific camera, detector, and filter represent their own photometric
     2916system, and it may be necessary to perform transformations between
     2917these systems.  Photometric systems associated with observations from
     2918a specific camera/detector/filter combination can be associated with
     2919those components.
     2920\begin{verbatim}
     2921typedef struct {
     2922    int ID;
     2923    char *name;
     2924    char *camera;
     2925    char *filter;
     2926    char *detector;
     2927} psPhotSystem;
     2928\end{verbatim}
     2929
     2930The following structure defines the transformation between two
     2931photometric systems.
     2932\begin{verbatim}
     2933typedef struct {
     2934    psPhotSystem src;
     2935    psPhotSystem dst;
     2936    psPhotSystem pP, pM;        ///< Colour reference
     2937    psPhotSystem sP, sM;        ///< Colour reference
     2938    float pA, sA;               ///<
     2939    psPolynomial3D transform;   
     2940} psPhotTransform;
     2941\end{verbatim}
     2942
     2943The transformation between two photometric systems may depend on the
     2944airmass of the observation and on the colors of the object of
     2945interest.  For a specific observation, such a transformations can be
     2946defined as a polynomial function of the color the star and the airmass
     2947of the observations.  If sufficient data exists, the transformation
     2948between the photometric systems may include more than one color,
     2949constraining the curvature of the stellar spectral energy
     2950distributions.  This latter term may be significant for stars which
     2951are highly reddened, for example.  Derived photometric quantities may
     2952have been corrected for airmass variations, in which case only color
     2953terms may be measureable.  The structure defines the transformation
     2954between a source photometric system (\code{src}) and a target
     2955photometric system (\code{dst}).  The photometric system of a primary
     2956color is defined by \code{pP, pM} such that the color is constructed
     2957as $pP - pM$.  A secondary color is defined by \code{sP, sM}.  For
     2958both, a reference color is specified (\code{pA, sA}): the polynomial
     2959transformation terms refer to colors in the form $pP - pM - pA$.  The
     2960transformation is specified as a 3D polynomial.  For a star of
     2961magnitude $M_{\rm src}$ in the source photometric system, with
     2962additional magnitude information in the other systems $M_{\rm pP}$,
     2963$M_{\rm pM}$, $M_{\rm sP}$, $M_{\rm sM}$, observed at an airmass of
     2964$z$, the magnitude of the star in the target system $M_{\rm dst}$ is
     2965given by:
     2966$M_{\rm dst} = M_{\rm src} + transform(z, M_{\rm pP} - M_{\rm pM} - pA, M_{\rm sP} - M_{\rm sM} - sA)$
    13782967
    13792968%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     
    13812970%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    13822971
     2972\appendix
     2973
     2974\section{API Summary: all functions}
     2975
     2976\subsection{System Utilities}
     2977\begin{CompactItemize}
     2978\item
     2979int {\bf ps\-Set\-Log\-Destination} (int dest)
     2980\begin{CompactList}\small\item\em Sets the log destination.\item\end{CompactList}\item
     2981int {\bf ps\-Set\-Log\-Level} (int level)
     2982\begin{CompactList}\small\item\em Sets the log level.\item\end{CompactList}\item
     2983void {\bf ps\-Set\-Log\-Format} (const char $\ast$fmt)
     2984\begin{CompactList}\small\item\em sets the log format\item\end{CompactList}\item
     2985void {\bf ps\-Log\-Msg} (const char $\ast$name, int level, const char $\ast$fmt,...)
     2986\begin{CompactList}\small\item\em Logs a message.\item\end{CompactList}\item
     2987void {\bf p\_\-ps\-VLog\-Msg} (const char $\ast$name, int level, const char $\ast$fmt, va\_\-list ap)
     2988\begin{CompactList}\small\item\em Logs a message from varargs.\item\end{CompactList}\item
     2989void $\ast$ {\bf p\_\-ps\-Alloc} (size\_\-t size, const char $\ast$file, int lineno)
     2990\begin{CompactList}\small\item\em Memory allocation. Underlying private function called by macro ps\-Alloc.\item\end{CompactList}\item
     2991void $\ast$ {\bf p\_\-ps\-Realloc} (void $\ast$ptr, size\_\-t size, const char $\ast$file, int lineno)
     2992\begin{CompactList}\small\item\em Memory re-allocation. Underlying private function called by macro ps\-Realloc.\item\end{CompactList}\item
     2993void {\bf p\_\-ps\-Free} (void $\ast$ptr, const char $\ast$file, int lineno)
     2994\begin{CompactList}\small\item\em Free memory. Underlying private function called by macro ps\-Free.\item\end{CompactList}\item
     2995int {\bf ps\-Mem\-Check\-Leaks} (int id0, {\bf ps\-Mem\-Block} $\ast$$\ast$$\ast$arr, FILE $\ast$fd)
     2996\begin{CompactList}\small\item\em Check for memory leaks.\item\end{CompactList}\item
     2997int {\bf ps\-Mem\-Check\-Corruption} (int abort\_\-on\_\-error)
     2998\begin{CompactList}\small\item\em Check for memory corruption.\item\end{CompactList}\item
     2999int {\bf ps\-Mem\-Get\-Ref\-Counter} (void $\ast$vptr)
     3000\begin{CompactList}\small\item\em Return reference counter.\item\end{CompactList}\item
     3001void $\ast$ {\bf ps\-Mem\-Incr\-Ref\-Counter} (void $\ast$vptr)
     3002\begin{CompactList}\small\item\em Increment reference counter and return the pointer.\item\end{CompactList}\item
     3003void $\ast$ {\bf ps\-Mem\-Decr\-Ref\-Counter} (void $\ast$vptr)
     3004\begin{CompactList}\small\item\em Decrement reference counter and return the pointer.\item\end{CompactList}\item
     3005{\bf ps\-Mem\-Problem\-Callback} {\bf ps\-Mem\-Problem\-Set\-CB} ({\bf ps\-Mem\-Problem\-Callback} func)
     3006\begin{CompactList}\small\item\em Set callback for problems.\item\end{CompactList}\item
     3007{\bf ps\-Mem\-Exhausted\-Callback} {\bf ps\-Mem\-Exhausted\-Set\-CB} ({\bf ps\-Mem\-Exhausted\-Callback} func)
     3008\begin{CompactList}\small\item\em Set callback for out-of-memory.\item\end{CompactList}\item
     3009{\bf ps\-Mem\-Callback} {\bf ps\-Mem\-Allocate\-Set\-CB} ({\bf ps\-Mem\-Callback} func)
     3010\begin{CompactList}\small\item\em Set call back for when a particular memory block is allocated.\item\end{CompactList}\item
     3011{\bf ps\-Mem\-Callback} {\bf ps\-Mem\-Free\-Set\-CB} ({\bf ps\-Mem\-Callback} func)
     3012\begin{CompactList}\small\item\em Set call back for when a particular memory block is freed.\item\end{CompactList}\item
     3013int {\bf ps\-Mem\-Get\-Id} (void)
     3014\begin{CompactList}\small\item\em get next memory ID\item\end{CompactList}\item
     3015long {\bf ps\-Mem\-Set\-Allocate\-ID} (long id)
     3016\begin{CompactList}\small\item\em set p\_\-ps\-Mem\-Allocate\-ID to id\item\end{CompactList}\item
     3017long {\bf ps\-Mem\-Set\-Free\-ID} (long id)
     3018\begin{CompactList}\small\item\em set p\_\-ps\-Mem\-Free\-ID to id\item\end{CompactList}\item
     3019void {\bf ps\-Abort} (const char $\ast$name, const char $\ast$fmt,...)
     3020\begin{CompactList}\small\item\em Prints an error message and aborts.\item\end{CompactList}\item
     3021void {\bf ps\-Error} (const char $\ast$name, const char $\ast$fmt,...)
     3022\begin{CompactList}\small\item\em Prints an error message and doesn't abort.\item\end{CompactList}\item
     3023char $\ast$ {\bf ps\-String\-Copy} (const char $\ast$str)
     3024\begin{CompactList}\small\item\em Allocates and returns a copy of a string.\item\end{CompactList}\item
     3025void {\bf p\_\-ps\-Trace} (const char $\ast$facil, int level,...)
     3026\begin{CompactList}\small\item\em Send a trace message.\item\end{CompactList}\item
     3027int {\bf ps\-Set\-Trace\-Level} (const char $\ast$facil, int level)
     3028\begin{CompactList}\small\item\em Set trace level.\item\end{CompactList}\item
     3029int {\bf ps\-Get\-Trace\-Level} (const char $\ast$name)
     3030\begin{CompactList}\small\item\em Get the trace level.\item\end{CompactList}\item
     3031void {\bf ps\-Trace\-Reset} (void)
     3032\begin{CompactList}\small\item\em turn off all tracing, and free trace's allocated memory\item\end{CompactList}\item
     3033void {\bf ps\-Print\-Trace\-Levels} (void)
     3034\begin{CompactList}\small\item\em print trace levels\item\end{CompactList}\end{CompactItemize}
     3035
     3036\subsection{Data Containers}
     3037\begin{CompactItemize}
     3038\item
     3039{\bf ps\-Dlist} $\ast$ {\bf ps\-Dlist\-Alloc} (void $\ast$data)
     3040\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3041void {\bf ps\-Dlist\-Free} ({\bf ps\-Dlist} $\ast$list, void($\ast$elem\-Free)(void $\ast$))
     3042\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3043{\bf ps\-Dlist} $\ast$ {\bf ps\-Dlist\-Add} ({\bf ps\-Dlist} $\ast$list, void $\ast$data, int where)
     3044\begin{CompactList}\small\item\em Add to list.\item\end{CompactList}\item
     3045{\bf ps\-Dlist} $\ast$ {\bf ps\-Dlist\-Append} ({\bf ps\-Dlist} $\ast$list, void $\ast$data)
     3046\begin{CompactList}\small\item\em Append to a list.\item\end{CompactList}\item
     3047void $\ast$ {\bf ps\-Dlist\-Remove} ({\bf ps\-Dlist} $\ast$list, void $\ast$data, int which)
     3048\begin{CompactList}\small\item\em PS\_\-DLIST\_\-PREV.\item\end{CompactList}\item
     3049void $\ast$ {\bf ps\-Dlist\-Get} (const {\bf ps\-Dlist} $\ast$list, int which)
     3050\begin{CompactList}\small\item\em Retrieve from a list.\item\end{CompactList}\item
     3051void {\bf ps\-Dlist\-Set\-Iterator} ({\bf ps\-Dlist} $\ast$list, int where, int which)
     3052\begin{CompactList}\small\item\em PS\_\-DLIST\_\-PREV.\item\end{CompactList}\item
     3053void $\ast$ {\bf ps\-Dlist\-Get\-Next} ({\bf ps\-Dlist} $\ast$list, int which)
     3054\begin{CompactList}\small\item\em PS\_\-DLIST\_\-PREV.\item\end{CompactList}\item
     3055void $\ast$ {\bf ps\-Dlist\-Get\-Prev} ({\bf ps\-Dlist} $\ast$list, int which)
     3056\begin{CompactList}\small\item\em PS\_\-DLIST\_\-PREV.\item\end{CompactList}\item
     3057{\bf ps\-Void\-Ptr\-Array} $\ast$ {\bf ps\-Dlist\-To\-Array} ({\bf ps\-Dlist} $\ast$dlist)
     3058\begin{CompactList}\small\item\em Convert doubly-linked list to an array.\item\end{CompactList}\item
     3059{\bf ps\-Dlist} $\ast$ {\bf ps\-Array\-To\-Dlist} ({\bf ps\-Void\-Ptr\-Array} $\ast$arr)
     3060\begin{CompactList}\small\item\em Convert array to a doubly-linked list.\item\end{CompactList}\item
     3061{\bf ps\-Hash} $\ast$ {\bf ps\-Hash\-Alloc} (int nbucket)
     3062\begin{CompactList}\small\item\em Allocate hash buckets in table.\item\end{CompactList}\item
     3063void {\bf ps\-Hash\-Free} ({\bf ps\-Hash} $\ast$table, void($\ast$item\-Free)(void $\ast$item))
     3064\begin{CompactList}\small\item\em Free hash buckets from table.\item\end{CompactList}\item
     3065void $\ast$ {\bf ps\-Hash\-Insert} ({\bf ps\-Hash} $\ast$table, const char $\ast$key, void $\ast$data, void($\ast$item\-Free)(void $\ast$item))
     3066\begin{CompactList}\small\item\em Insert entry into table.\item\end{CompactList}\item
     3067void $\ast$ {\bf ps\-Hash\-Lookup} ({\bf ps\-Hash} $\ast$table, const char $\ast$key)
     3068\begin{CompactList}\small\item\em Lookup key in table.\item\end{CompactList}\item
     3069void $\ast$ {\bf ps\-Hash\-Remove} ({\bf ps\-Hash} $\ast$table, const char $\ast$key)
     3070\begin{CompactList}\small\item\em Remove key from table.\item\end{CompactList}\item
     3071{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Float\-Array\-Alloc} (int s, int n)
     3072\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3073{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Float\-Array\-Realloc} ({\bf ps\-Float\-Array} $\ast$my\-Array, int s)
     3074\begin{CompactList}\small\item\em Reallocator.\item\end{CompactList}\item
     3075void {\bf ps\-Float\-Array\-Free} ({\bf ps\-Float\-Array} $\ast$restrict my\-Array)
     3076\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3077{\bf ps\-Complex\-Array} $\ast$ {\bf ps\-Complex\-Array\-Alloc} (int s, int n)
     3078\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3079{\bf ps\-Complex\-Array} $\ast$ {\bf ps\-Complex\-Array\-Realloc} ({\bf ps\-Complex\-Array} $\ast$my\-Array, int s)
     3080\begin{CompactList}\small\item\em Reallocator.\item\end{CompactList}\item
     3081void {\bf ps\-Complex\-Array\-Free} ({\bf ps\-Complex\-Array} $\ast$restrict my\-Array)
     3082\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3083{\bf ps\-Int\-Array} $\ast$ {\bf ps\-Int\-Array\-Alloc} (int s, int n)
     3084\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3085{\bf ps\-Int\-Array} $\ast$ {\bf ps\-Int\-Array\-Realloc} ({\bf ps\-Int\-Array} $\ast$my\-Array, int s)
     3086\begin{CompactList}\small\item\em Reallocator.\item\end{CompactList}\item
     3087void {\bf ps\-Int\-Array\-Free} ({\bf ps\-Int\-Array} $\ast$restrict my\-Array)
     3088\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3089{\bf ps\-Double\-Array} $\ast$ {\bf ps\-Double\-Array\-Alloc} (int s, int n)
     3090\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3091{\bf ps\-Double\-Array} $\ast$ {\bf ps\-Double\-Array\-Realloc} ({\bf ps\-Double\-Array} $\ast$my\-Array, int s)
     3092\begin{CompactList}\small\item\em Reallocator.\item\end{CompactList}\item
     3093void {\bf ps\-Double\-Array\-Free} ({\bf ps\-Double\-Array} $\ast$restrict my\-Array)
     3094\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3095{\bf ps\-Vector\-Array} $\ast$ {\bf ps\-Vector\-Array\-Alloc} (int s, int n)
     3096\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3097{\bf ps\-Vector\-Array} $\ast$ {\bf ps\-Vector\-Array\-Realloc} ({\bf ps\-Vector\-Array} $\ast$my\-Array, int s)
     3098\begin{CompactList}\small\item\em Reallocator.\item\end{CompactList}\item
     3099void {\bf ps\-Vector\-Array\-Free} ({\bf ps\-Vector\-Array} $\ast$restrict my\-Array)
     3100\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3101{\bf ps\-Void\-Ptr\-Array} $\ast$ {\bf ps\-Void\-Ptr\-Array\-Alloc} (int n, int s)
     3102\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3103{\bf ps\-Void\-Ptr\-Array} $\ast$ {\bf ps\-Void\-Ptr\-Array\-Realloc} ({\bf ps\-Void\-Ptr\-Array} $\ast$arr, int n)
     3104\begin{CompactList}\small\item\em Reallocate.\item\end{CompactList}\item
     3105void {\bf ps\-Void\-Ptr\-Array\-Free} ({\bf ps\-Void\-Ptr\-Array} $\ast$arr, void($\ast$elem\-Free)(void $\ast$))
     3106\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\end{CompactItemize}
     3107
     3108\subsection{Math Utilities}
     3109\begin{CompactItemize}
     3110\item
     3111{\bf ps\-Bit\-Mask} $\ast$ {\bf ps\-Bit\-Mask\-Alloc} (int n)
     3112\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3113void {\bf ps\-Bit\-Mask\-Free} ({\bf ps\-Bit\-Mask} $\ast$restrict my\-Mask)
     3114\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3115{\bf ps\-Bit\-Mask} $\ast$ {\bf ps\-Bit\-Mask\-Set} ({\bf ps\-Bit\-Mask} $\ast$out\-Mask, const {\bf ps\-Bit\-Mask} $\ast$my\-Mask, int bit)
     3116\begin{CompactList}\small\item\em Set a bit mask.\item\end{CompactList}\item
     3117int {\bf ps\-Bit\-Mask\-Test} (const {\bf ps\-Bit\-Mask} $\ast$check\-Mask, int bit)
     3118\begin{CompactList}\small\item\em Check a bit mask.\item\end{CompactList}\item
     3119{\bf ps\-Bit\-Mask} $\ast$ {\bf ps\-Bit\-Mask\-Op} ({\bf ps\-Bit\-Mask} $\ast$out\-Mask, const {\bf ps\-Bit\-Mask} $\ast$restrict in\-Mask1, char $\ast$operator, const {\bf ps\-Bit\-Mask} $\ast$restrict in\-Mask2)
     3120\begin{CompactList}\small\item\em apply the given operator to two bit masks\item\end{CompactList}\item
     3121{\bf ps\-Complex\-Array} $\ast$ {\bf ps\-Real\-FFT} ({\bf ps\-Complex\-Array} $\ast$restrict out, const {\bf ps\-Float\-Array} $\ast$restrict my\-Array)
     3122\begin{CompactList}\small\item\em Return Fourier Transform of an array.\item\end{CompactList}\item
     3123{\bf ps\-Complex\-Array} $\ast$ {\bf ps\-Complex\-FFT} ({\bf ps\-Complex\-Array} $\ast$restrict out, const {\bf ps\-Complex\-Array} $\ast$restrict my\-Array, int sign)
     3124\begin{CompactList}\small\item\em Return [inverse?] Fourier Transform of a complex array.\item\end{CompactList}\item
     3125{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Power\-Spec} ({\bf ps\-Float\-Array} $\ast$restrict out, const {\bf ps\-Float\-Array} $\ast$restrict my\-Array)
     3126\begin{CompactList}\small\item\em Return Power spectrum of a array.\item\end{CompactList}\item
     3127{\bf ps\-Polynomial1D} $\ast$ {\bf ps\-Polynomial1DAlloc} (int n)
     3128\begin{CompactList}\small\item\em Constructors.\item\end{CompactList}\item
     3129{\bf ps\-Polynomial2D} $\ast$ {\bf ps\-Polynomial2DAlloc} (int n\-X, int n\-Y)
     3130\item
     3131{\bf ps\-Polynomial3D} $\ast$ {\bf ps\-Polynomial3DAlloc} (int n\-X, int n\-Y, int n\-Z)
     3132\item
     3133{\bf ps\-Polynomial4D} $\ast$ {\bf ps\-Polynomial4DAlloc} (int n\-W, int n\-X, int n\-Y, int n\-Z)
     3134\item
     3135void {\bf ps\-Polynomial1DFree} ({\bf ps\-Polynomial1D} $\ast$restrict my\-Poly)
     3136\begin{CompactList}\small\item\em Destructors.\item\end{CompactList}\item
     3137void {\bf ps\-Polynomial2DFree} ({\bf ps\-Polynomial2D} $\ast$restrict my\-Poly)
     3138\item
     3139void {\bf ps\-Polynomial3DFree} ({\bf ps\-Polynomial3D} $\ast$restrict my\-Poly)
     3140\item
     3141void {\bf ps\-Polynomial4DFree} ({\bf ps\-Polynomial4D} $\ast$restrict my\-Poly)
     3142\item
     3143float {\bf ps\-Eval\-Polynomial1D} (float x, const {\bf ps\-Polynomial1D} $\ast$restrict my\-Poly)
     3144\begin{CompactList}\small\item\em Evaluate 1D polynomial.\item\end{CompactList}\item
     3145float {\bf ps\-Eval\-Polynomial2D} (float x, float y, const {\bf ps\-Polynomial2D} $\ast$restrict my\-Poly)
     3146\begin{CompactList}\small\item\em Evaluate 2D polynomial.\item\end{CompactList}\item
     3147float {\bf ps\-Eval\-Polynomial3D} (float x, float y, float z, const {\bf ps\-Polynomial3D} $\ast$restrict my\-Poly)
     3148\begin{CompactList}\small\item\em Evaluate 3D polynomial.\item\end{CompactList}\item
     3149float {\bf ps\-Eval\-Polynomial4D} (float w, float x, float y, float z, const {\bf ps\-Polynomial4D} $\ast$restrict my\-Poly)
     3150\begin{CompactList}\small\item\em Evaluate 4D polynomial.\item\end{CompactList}\item
     3151{\bf ps\-DPolynomial1D} $\ast$ {\bf ps\-DPolynomial1DAlloc} (int n)
     3152\begin{CompactList}\small\item\em Constructors.\item\end{CompactList}\item
     3153{\bf ps\-DPolynomial2D} $\ast$ {\bf ps\-DPolynomial2DAlloc} (int n\-X, int n\-Y)
     3154\item
     3155{\bf ps\-DPolynomial3D} $\ast$ {\bf ps\-DPolynomial3DAlloc} (int n\-X, int n\-Y, int n\-Z)
     3156\item
     3157{\bf ps\-DPolynomial4D} $\ast$ {\bf ps\-DPolynomial4DAlloc} (int n\-W, int n\-X, int n\-Y, int n\-Z)
     3158\item
     3159void {\bf ps\-DPolynomial1DFree} ({\bf ps\-DPolynomial1D} $\ast$restrict my\-Poly)
     3160\begin{CompactList}\small\item\em Destructors.\item\end{CompactList}\item
     3161void {\bf ps\-DPolynomial2DFree} ({\bf ps\-DPolynomial2D} $\ast$restrict my\-Poly)
     3162\item
     3163void {\bf ps\-DPolynomial3DFree} ({\bf ps\-DPolynomial3D} $\ast$restrict my\-Poly)
     3164\item
     3165void {\bf ps\-DPolynomial4DFree} ({\bf ps\-DPolynomial4D} $\ast$restrict my\-Poly)
     3166\item
     3167double {\bf ps\-Eval\-DPolynomial1D} (double x, const {\bf ps\-DPolynomial1D} $\ast$restrict my\-Poly)
     3168\begin{CompactList}\small\item\em Evaluate 1D polynomial (double precision).\item\end{CompactList}\item
     3169double {\bf ps\-Eval\-DPolynomial2D} (double x, double y, const {\bf ps\-DPolynomial2D} $\ast$restrict my\-Poly)
     3170\begin{CompactList}\small\item\em Evaluate 2D polynomial (double precision).\item\end{CompactList}\item
     3171double {\bf ps\-Eval\-DPolynomial3D} (double x, double y, double z, const {\bf ps\-DPolynomial3D} $\ast$restrict my\-Poly)
     3172\begin{CompactList}\small\item\em Evaluate 3D polynomial (double precision).\item\end{CompactList}\item
     3173double {\bf ps\-Eval\-DPolynomial4D} (double w, double x, double y, double z, const {\bf ps\-DPolynomial4D} $\ast$restrict my\-Poly)
     3174\begin{CompactList}\small\item\em Evaluate 4D polynomial (double precision).\item\end{CompactList}\item
     3175{\bf ps\-Type} $\ast$ {\bf ps\-Binary\-Op} (void $\ast$out, void $\ast$in1, char $\ast$operator, void $\ast$in2)
     3176\begin{CompactList}\small\item\em Perform a binary operation on two data items ({\bf ps\-Image} {\rm (p.\,\pageref{structpsImage})}, ps\-Vector, ps\-Scalar).\item\end{CompactList}\item
     3177{\bf ps\-Type} $\ast$ {\bf ps\-Unary\-Op} (void $\ast$out, void $\ast$in, char $\ast$operator)
     3178\begin{CompactList}\small\item\em Perform a binary operation on two data items ({\bf ps\-Image} {\rm (p.\,\pageref{structpsImage})}, ps\-Vector, ps\-Scalar).\item\end{CompactList}\item
     3179{\bf p\_\-ps\-Scalar} $\ast$ {\bf ps\-Scalar} (double value)
     3180\begin{CompactList}\small\item\em create a {\bf ps\-Type} {\rm (p.\,\pageref{structpsType})}-ed structure from a constant double value.\item\end{CompactList}\item
     3181{\bf p\_\-ps\-Scalar} $\ast$ {\bf ps\-Scalar\-Type} (char $\ast$mode,...)
     3182\begin{CompactList}\small\item\em create a {\bf ps\-Type} {\rm (p.\,\pageref{structpsType})}-ed structure from a specified type\item\end{CompactList}\item
     3183{\bf ps\-Matrix} $\ast$ {\bf ps\-Matrix\-Alloc} (int Xdimen, int Ydimen)
     3184\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3185void {\bf ps\-Matrix\-Free} ({\bf ps\-Matrix} $\ast$restrict my\-Matrix)
     3186\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3187{\bf ps\-Matrix} $\ast$ {\bf ps\-Matrix\-Invert} ({\bf ps\-Matrix} $\ast$out, const {\bf ps\-Matrix} $\ast$my\-Matrix, float $\ast$restrict determinant)
     3188\begin{CompactList}\small\item\em Invert matrix.\item\end{CompactList}\item
     3189float {\bf ps\-Matrix\-Determinant} (const {\bf ps\-Matrix} $\ast$restrict my\-Matrix)
     3190\begin{CompactList}\small\item\em Matrix determinant.\item\end{CompactList}\item
     3191{\bf ps\-Matrix} $\ast$ {\bf ps\-Matrix\-Op} ({\bf ps\-Matrix} $\ast$out, const {\bf ps\-Matrix} $\ast$matrix1, const char $\ast$op, const {\bf ps\-Matrix} $\ast$matrix2)
     3192\begin{CompactList}\small\item\em Matrix operations.\item\end{CompactList}\item
     3193{\bf ps\-Matrix} $\ast$ {\bf ps\-Matrix\-Transpose} ({\bf ps\-Matrix} $\ast$out, const {\bf ps\-Matrix} $\ast$my\-Matrix)
     3194\begin{CompactList}\small\item\em Transpose Matrix.\item\end{CompactList}\item
     3195{\bf ps\-Vector} $\ast$ {\bf ps\-Matrix\-To\-Vector} ({\bf ps\-Matrix} $\ast$my\-Matrix)
     3196\begin{CompactList}\small\item\em Convert matrix to vector.\item\end{CompactList}\item
     3197{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Minimize} (float($\ast$my\-Function)(const {\bf ps\-Float\-Array} $\ast$restrict), {\bf ps\-Float\-Array} $\ast$restrict initial\-Guess)
     3198\begin{CompactList}\small\item\em Minimize a particular function.\item\end{CompactList}\item
     3199{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Minimize\-Chi2} (float($\ast$eval\-Model)(const {\bf ps\-Float\-Array} $\ast$restrict, const {\bf ps\-Float\-Array} $\ast$restrict), const {\bf ps\-Float\-Array} $\ast$restrict domain, const {\bf ps\-Float\-Array} $\ast$restrict data, const {\bf ps\-Float\-Array} $\ast$restrict errors, {\bf ps\-Float\-Array} $\ast$restrict initial\-Guess, const {\bf ps\-Int\-Array} $\ast$restrict guess\-Mask)
     3200\begin{CompactList}\small\item\em Minimize chi$^\wedge$2 for input data.\item\end{CompactList}\item
     3201{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Get\-Array\-Polynomial} (const {\bf ps\-Float\-Array} $\ast$restrict ord, const {\bf ps\-Float\-Array} $\ast$restrict coord)
     3202\begin{CompactList}\small\item\em Derive a polynomial that goes through the points --- can be done analytically.\item\end{CompactList}\item
     3203{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Sort} ({\bf ps\-Float\-Array} $\ast$out, const {\bf ps\-Float\-Array} $\ast$my\-Array)
     3204\begin{CompactList}\small\item\em Sort an array.\item\end{CompactList}\item
     3205{\bf ps\-Int\-Array} $\ast$ {\bf ps\-Sort\-Index} ({\bf ps\-Int\-Array} $\ast$restrict out, const {\bf ps\-Float\-Array} $\ast$restrict my\-Array)
     3206\begin{CompactList}\small\item\em Sort an array, along with some other stuff.\item\end{CompactList}\item
     3207{\bf ps\-Stats} $\ast$ {\bf ps\-Array\-Stats} (const {\bf ps\-Float\-Array} $\ast$restrict my\-Array, const {\bf ps\-Int\-Array} $\ast$restrict mask\-Array, unsigned int mask\-Val, {\bf ps\-Stats} $\ast$stats)
     3208\begin{CompactList}\small\item\em Do Statistics on an array.\item\end{CompactList}\item
     3209{\bf ps\-Histogram} $\ast$ {\bf ps\-Histogram\-Alloc} (float lower, float upper, float size)
     3210\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3211{\bf ps\-Histogram} $\ast$ {\bf ps\-Histogram\-Alloc\-Generic} (const {\bf ps\-Float\-Array} $\ast$restrict lower, const {\bf ps\-Float\-Array} $\ast$restrict upper, float min\-Val, float max\-Val)
     3212\begin{CompactList}\small\item\em Generic constructor.\item\end{CompactList}\item
     3213void {\bf ps\-Histogram\-Free} ({\bf ps\-Histogram} $\ast$restrict my\-Hist)
     3214\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3215{\bf ps\-Histogram} $\ast$ {\bf ps\-Get\-Array\-Histogram} ({\bf ps\-Histogram} $\ast$restrict my\-Hist, const {\bf ps\-Float\-Array} $\ast$restrict my\-Array)
     3216\begin{CompactList}\small\item\em Calculate a histogram.\item\end{CompactList}\end{CompactItemize}
     3217
     3218\subsection{Astronomy Functions}
     3219\begin{CompactItemize}
     3220\item
     3221{\bf ps\-Chip} $\ast$ {\bf ps\-Chip\-In\-FPA} ({\bf ps\-FPA} $\ast$fpa, {\bf ps\-Coord} $\ast$coord)
     3222\begin{CompactList}\small\item\em returns Chip in FPA which contains the given FPA coordinate\item\end{CompactList}\item
     3223{\bf ps\-Cell} $\ast$ {\bf ps\-Cell\-In\-Chip} ({\bf ps\-Chip} $\ast$chip, {\bf ps\-Coord} $\ast$coord)
     3224\begin{CompactList}\small\item\em returns Cell in Chip which contains the given chip coordinate\item\end{CompactList}\item
     3225{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-Sky\-To\-TP} ({\bf ps\-Exposure} $\ast$exp, {\bf ps\-Coord} $\ast$coord)
     3226\begin{CompactList}\small\item\em Convert (RA,Dec) to tangent plane coords.\item\end{CompactList}\item
     3227{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-TPto\-FPA} ({\bf ps\-FPA} $\ast$fpa, {\bf ps\-Coord} $\ast$coord)
     3228\begin{CompactList}\small\item\em Convert tangent plane coords to focal plane coordinates.\item\end{CompactList}\item
     3229{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-FPAto\-Chip} ({\bf ps\-FPA} $\ast$fpa, {\bf ps\-Chip} $\ast$chip, {\bf ps\-Coord} $\ast$coord)
     3230\begin{CompactList}\small\item\em converts the specified FPA coord to the coord on the given Chip\item\end{CompactList}\item
     3231{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-Chipto\-Cell} ({\bf ps\-Chip} $\ast$chip, {\bf ps\-Cell} $\ast$cell, {\bf ps\-Coord} $\ast$coord)
     3232\begin{CompactList}\small\item\em converts the specified Chip coord to the coord on the given Cell\item\end{CompactList}\item
     3233{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-Cellto\-Chip} ({\bf ps\-Cell} $\ast$cell, {\bf ps\-Coord} $\ast$coord)
     3234\begin{CompactList}\small\item\em converts the specified Cell coord to the coord on the parent Chip\item\end{CompactList}\item
     3235{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-Chipto\-FPA} ({\bf ps\-Chip} $\ast$chip, {\bf ps\-Coord} $\ast$coord)
     3236\begin{CompactList}\small\item\em converts the specified Chip coord to the coord on the parent FPA\item\end{CompactList}\item
     3237{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-FPATo\-TP} ({\bf ps\-FPA} $\ast$fpa, {\bf ps\-Coord} $\ast$coord)
     3238\begin{CompactList}\small\item\em Convert focal plane coords to tangent plane coordinates.\item\end{CompactList}\item
     3239{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-TPto\-Sky} ({\bf ps\-Exposure} $\ast$exp, {\bf ps\-Coord} $\ast$coord)
     3240\begin{CompactList}\small\item\em Convert tangent plane coords to (RA,Dec).\item\end{CompactList}\item
     3241float {\bf ps\-Get\-Airmass} ({\bf ps\-Coord} $\ast$coord, double sidereal\-Time)
     3242\begin{CompactList}\small\item\em Get the airmass for a given position and sidereal time.\item\end{CompactList}\item
     3243float {\bf ps\-Get\-Parallactic} ({\bf ps\-Coord} $\ast$coord, double sidereal\-Time)
     3244\begin{CompactList}\small\item\em Get the parallactic angle for a given position and sidereal time.\item\end{CompactList}\item
     3245float {\bf ps\-Get\-Refraction} (float colour, {\bf ps\-Phot\-System} color\-Plus, {\bf ps\-Phot\-System} color\-Minus, {\bf ps\-Exposure} $\ast$exp)
     3246\begin{CompactList}\small\item\em Estimate atmospheric refraction, along the parallactic.\item\end{CompactList}\item
     3247{\bf ps\-Exposure} $\ast$ {\bf ps\-Exposure\-Alloc} (double ra, double dec, double ha, double zd, double az, double lst, float mjd, float rot\-Angle, float temp, float pressure, float humidity, float exptime)
     3248\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3249void {\bf ps\-Exposure\-Free} ({\bf ps\-Exposure} $\ast$restrict my\-Exp)
     3250\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3251double {\bf ps\-Get\-MJD} (void)
     3252\begin{CompactList}\small\item\em Get current MJD, for a timestamp.\item\end{CompactList}\item
     3253double {\bf ps\-Get\-Sidereal} (float mjd, float longitude)
     3254\begin{CompactList}\small\item\em Get current sidereal time at longitude.\item\end{CompactList}\item
     3255char $\ast$ {\bf ps\-Time\-To\-ISOTime} (ps\-Time time)
     3256\begin{CompactList}\small\item\em Convert ps\-Time to ISOTime (Human-readable date/time string YYYY/MM/DD,HH:MM:SS.SSS).\item\end{CompactList}\item
     3257double {\bf ps\-Time\-To\-UTC} (ps\-Time time)
     3258\begin{CompactList}\small\item\em Convert ps\-Time to UTC.\item\end{CompactList}\item
     3259double {\bf ps\-Time\-To\-MJD} (ps\-Time time)
     3260\begin{CompactList}\small\item\em Convert ps\-Time to MJD.\item\end{CompactList}\item
     3261double {\bf ps\-Time\-To\-JD} (ps\-Time time)
     3262\begin{CompactList}\small\item\em Convert ps\-Time to JD.\item\end{CompactList}\item
     3263timeval $\ast$ {\bf ps\-Time\-To\-Timeval} (ps\-Time time)
     3264\begin{CompactList}\small\item\em Convert ps\-Time to timeval (struct timeval).\item\end{CompactList}\item
     3265tm $\ast$ {\bf ps\-Time\-To\-Tm} (ps\-Time time)
     3266\begin{CompactList}\small\item\em Convert ps\-Time to broken-down time (struct tm).\item\end{CompactList}\item
     3267ps\-Time $\ast$ {\bf ps\-ISOTime\-To\-Time} (char $\ast$input)
     3268\begin{CompactList}\small\item\em Convert ISOTime (Human-readable date/time string YYYY/MM/DD,HH:MM:SS.SSS) to ps\-Time.\item\end{CompactList}\item
     3269ps\-Time $\ast$ {\bf ps\-UTCTo\-Time} (double input)
     3270\begin{CompactList}\small\item\em Convert UTC to ps\-Time.\item\end{CompactList}\item
     3271ps\-Time $\ast$ {\bf ps\-MJDTo\-Time} (double input)
     3272\begin{CompactList}\small\item\em Convert MJD to ps\-Time.\item\end{CompactList}\item
     3273ps\-Time $\ast$ {\bf ps\-JDTo\-Time} (double input)
     3274\begin{CompactList}\small\item\em Convert JD to ps\-Time.\item\end{CompactList}\item
     3275ps\-Time $\ast$ {\bf ps\-Timeval\-To\-Time} (struct timeval $\ast$input)
     3276\begin{CompactList}\small\item\em Convert timeval to ps\-Time (struct timeval).\item\end{CompactList}\item
     3277ps\-Time $\ast$ {\bf ps\-TMto\-Time} (struct tm $\ast$input)
     3278\begin{CompactList}\small\item\em Convert broken-to ps\-Time down time (struct tm).\item\end{CompactList}\item
     3279{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Alloc} (int nx, int ny, {\bf ps\-Type} type)
     3280\begin{CompactList}\small\item\em Create an image of the specified size and type.\item\end{CompactList}\item
     3281{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Subset} ({\bf ps\-Image} $\ast$image, int nx, int ny, int x0, int y0)
     3282\begin{CompactList}\small\item\em Create a subimage of the specified area.\item\end{CompactList}\item
     3283void {\bf ps\-Image\-Free} ({\bf ps\-Image} $\ast$image)
     3284\begin{CompactList}\small\item\em Destroy the specified image (destroy children if they exist).\item\end{CompactList}\item
     3285int {\bf ps\-Image\-Free\-Children} ({\bf ps\-Image} $\ast$image)
     3286\begin{CompactList}\small\item\em Destroy the children of the specified image.\item\end{CompactList}\item
     3287{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Copy} ({\bf ps\-Image} $\ast$output, {\bf ps\-Image} $\ast$input)
     3288\begin{CompactList}\small\item\em Create a copy of the specified image.\item\end{CompactList}\item
     3289{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Image\-Slice} ({\bf ps\-Image} $\ast$input, int x, int y, int nx, int ny, int direction, {\bf ps\-Stats} $\ast$stats)
     3290\begin{CompactList}\small\item\em Extract pixels from rectlinear region to a vector.\item\end{CompactList}\item
     3291{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Image\-Cut} ({\bf ps\-Image} $\ast$input, float xs, float ys, float xe, float ye, float dw, {\bf ps\-Stats} $\ast$stats)
     3292\begin{CompactList}\small\item\em Extract pixels along a line to a vector.\item\end{CompactList}\item
     3293{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Image\-Radial\-Cut} ({\bf ps\-Image} $\ast$input, float x, float y, float radius, float dr, {\bf ps\-Stats} $\ast$stats)
     3294\begin{CompactList}\small\item\em Extract radial annulii data to a vector.\item\end{CompactList}\item
     3295{\bf ps\-Float\-Array} $\ast$ {\bf ps\-Image\-Contour} ({\bf ps\-Image} $\ast$input, float threshold, int binning)
     3296\begin{CompactList}\small\item\em Extract a 2-d contour from an image at the given threshold.\item\end{CompactList}\item
     3297{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Rebin} ({\bf ps\-Image} $\ast$input, float scale, {\bf ps\-Stats} $\ast$stats)
     3298\begin{CompactList}\small\item\em Rebin image to new scale.\item\end{CompactList}\item
     3299{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Rotate} ({\bf ps\-Image} $\ast$input, float angle)
     3300\begin{CompactList}\small\item\em Rotate image by given angle.\item\end{CompactList}\item
     3301{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Shift} ({\bf ps\-Image} $\ast$input, float dx, float dy, float exposed)
     3302\begin{CompactList}\small\item\em Shift image by an arbitrary number of pixels in either direction.\item\end{CompactList}\item
     3303{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Roll} ({\bf ps\-Image} $\ast$input, int dx, int dy)
     3304\begin{CompactList}\small\item\em Roll image by an integer number of pixels in either direction.\item\end{CompactList}\item
     3305{\bf ps\-Stats} $\ast$ {\bf ps\-Image\-Get\-Stats} ({\bf ps\-Image} $\ast$input, {\bf ps\-Stats} $\ast$stats)
     3306\begin{CompactList}\small\item\em defines statistics to be calculated\item\end{CompactList}\item
     3307{\bf ps\-Histogram} $\ast$ {\bf ps\-Image\-Histogram} ({\bf ps\-Histogram} $\ast$hist, {\bf ps\-Image} $\ast$input)
     3308\begin{CompactList}\small\item\em Construct a histogram from an image (or subimage).\item\end{CompactList}\item
     3309{\bf ps\-Polynomial2D} $\ast$ {\bf ps\-Image\-Fit\-Polynomial} ({\bf ps\-Image} $\ast$input, {\bf ps\-Polynomial2D} $\ast$coeffs)
     3310\begin{CompactList}\small\item\em Fit a 2-D polynomial surface to an image.\item\end{CompactList}\item
     3311int {\bf ps\-Image\-Eval\-Polynomial} ({\bf ps\-Image} $\ast$input, {\bf ps\-Polynomial2D} $\ast$coeffs)
     3312\begin{CompactList}\small\item\em Evaluate a 2-D polynomial surface to image pixels.\item\end{CompactList}\item
     3313{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Read\-Section} ({\bf ps\-Image} $\ast$output, int x, int y, int dx, int dy, int z, char $\ast$extname, char $\ast$filename)
     3314\begin{CompactList}\small\item\em Read an image or subimage from a named file.\item\end{CompactList}\item
     3315{\bf ps\-Image} $\ast$ {\bf ps\-Image\-FRead\-Section} ({\bf ps\-Image} $\ast$output, int x, int y, int dx, int dy, int z, char $\ast$extname, FILE $\ast$f)
     3316\begin{CompactList}\small\item\em Read an image or subimage from file descriptor.\item\end{CompactList}\item
     3317{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Write\-Section} ({\bf ps\-Image} $\ast$input, int x, int y, int z, char $\ast$extname, char $\ast$filename)
     3318\begin{CompactList}\small\item\em Write an image section to named file (which may exist).\item\end{CompactList}\item
     3319{\bf ps\-Image} $\ast$ {\bf ps\-Image\-FWrite\-Section} ({\bf ps\-Image} $\ast$input, int x, int y, int z, char $\ast$extname, FILE $\ast$f)
     3320\begin{CompactList}\small\item\em Write an image section to named file (which may exist).\item\end{CompactList}\item
     3321ps\-Metadata $\ast$ {\bf ps\-Image\-Read\-Header} (struct ps\-Metadata $\ast$output, char $\ast$extname, char $\ast$filename)
     3322\begin{CompactList}\small\item\em Read only header from image file.\item\end{CompactList}\item
     3323ps\-Metadata $\ast$ {\bf ps\-Image\-FRead\-Header} (struct ps\-Metadata $\ast$output, char $\ast$extname, FILE $\ast$f)
     3324\begin{CompactList}\small\item\em Read only header from image file descriptor.\item\end{CompactList}\item
     3325{\bf ps\-Image} $\ast$ {\bf ps\-Image\-FFT} ({\bf ps\-Image} $\ast$input, int direction)
     3326\begin{CompactList}\small\item\em Perform an FFT on the image.\item\end{CompactList}\item
     3327int {\bf ps\-Image\-Clip} ({\bf ps\-Image} $\ast$input, float min, float vmin, float max, float vmax)
     3328\begin{CompactList}\small\item\em Clip image values outside of range to given values.\item\end{CompactList}\item
     3329int {\bf ps\-Image\-Clip\-Na\-N} ({\bf ps\-Image} $\ast$input, float value)
     3330\begin{CompactList}\small\item\em Clip Na\-N image pixels to given value.\item\end{CompactList}\item
     3331{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Binary\-Op} ({\bf ps\-Image} $\ast$out, {\bf ps\-Image} $\ast$in1, char $\ast$operator, {\bf ps\-Image} $\ast$in2)
     3332\begin{CompactList}\small\item\em Perform a binary operation on two images.\item\end{CompactList}\item
     3333{\bf ps\-Image} $\ast$ {\bf ps\-Image\-Unary\-Op} ({\bf ps\-Image} $\ast$out, {\bf ps\-Image} $\ast$in1, char $\ast$operator)
     3334\begin{CompactList}\small\item\em Perform a unary operation on an image.\item\end{CompactList}\item
     3335int {\bf ps\-Image\-Overlay\-Section} ({\bf ps\-Image} $\ast$image, {\bf ps\-Image} $\ast$overlay, int x0, int y0, char $\ast$operator)
     3336\begin{CompactList}\small\item\em Overlay subregion of image with another image.\item\end{CompactList}\item
     3337{\bf ps\-Meta\-Data\-Item} $\ast$ {\bf ps\-Meta\-Data\-Item\-Alloc} (int type\-Flags, const void $\ast$val, const char $\ast$comment, const char $\ast$name,...)
     3338\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3339void {\bf ps\-Meta\-Data\-Item\-Free} ({\bf ps\-Meta\-Data\-Item} $\ast$ms)
     3340\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3341{\bf ps\-Meta\-Data\-Set} $\ast$ {\bf ps\-Meta\-Data\-Set\-Alloc} (void)
     3342\begin{CompactList}\small\item\em Constructor.\item\end{CompactList}\item
     3343void {\bf ps\-Meta\-Data\-Set\-Free} ({\bf ps\-Meta\-Data\-Set} $\ast$ms)
     3344\begin{CompactList}\small\item\em Destructor.\item\end{CompactList}\item
     3345{\bf ps\-Meta\-Data\-Item} $\ast$ {\bf ps\-Meta\-Data\-Append} ({\bf ps\-Meta\-Data\-Set} $\ast$restrict ms, {\bf ps\-Meta\-Data\-Item} $\ast$restrict item)
     3346\item
     3347{\bf ps\-Meta\-Data\-Item} $\ast$ {\bf ps\-Meta\-Data\-Remove} ({\bf ps\-Meta\-Data\-Set} $\ast$restrict ms, const char $\ast$restrict key)
     3348\item
     3349void {\bf ps\-Meta\-Data\-Set\-Iterator} ({\bf ps\-Meta\-Data\-Set} $\ast$ms)
     3350\item
     3351{\bf ps\-Meta\-Data\-Item} $\ast$ {\bf ps\-Meta\-Data\-Get\-Next} ({\bf ps\-Meta\-Data\-Set} $\ast$restrict ms, const char $\ast$restrict match)
     3352\item
     3353{\bf ps\-Meta\-Data\-Item} $\ast$ {\bf ps\-Meta\-Data\-Lookup} (const {\bf ps\-Meta\-Data\-Set} $\ast$restrict ms, const char $\ast$restrict key)
     3354\item
     3355void {\bf ps\-Meta\-Data\-Item\-Print} (FILE $\ast$fd, const {\bf ps\-Meta\-Data\-Item} $\ast$restrict ms, const char $\ast$prefix)
     3356\item
     3357{\bf ps\-Coord} $\ast$ {\bf ps\-Coord\-Xform\-Apply} ({\bf ps\-Coord\-Xform} $\ast$frame, {\bf ps\-Coord} $\ast$coords)
     3358\begin{CompactList}\small\item\em apply the coordinate transformation to the given coordinate\item\end{CompactList}\item
     3359{\bf ps\-Coord} $\ast$ {\bf ps\-Distortion\-Apply} ({\bf ps\-Distortion} $\ast$pattern, {\bf ps\-Coord} $\ast$coords, float mag, float color)
     3360\begin{CompactList}\small\item\em apply the optical distortion to the given coordinate, magnitude, color\item\end{CompactList}\item
     3361{\bf ps\-Coord} $\ast$ {\bf ps\-Get\-Offset} (const {\bf ps\-Coord} $\ast$restrict position1, const {\bf ps\-Coord} $\ast$restrict position2, char $\ast$system)
     3362\begin{CompactList}\small\item\em Get offset (RA,Dec) on the sky between two positions position1 and position2 may not be identical.\item\end{CompactList}\item
     3363{\bf ps\-Coord} $\ast$ {\bf ps\-Apply\-Offset} (const {\bf ps\-Coord} $\ast$restrict position, const {\bf ps\-Coord} $\ast$restrict offset, char $\ast$system)
     3364\begin{CompactList}\small\item\em Apply an offset to a position.\item\end{CompactList}\item
     3365{\bf ps\-Coord} $\ast$ {\bf ps\-Get\-Sun\-Pos} (float mjd)
     3366\begin{CompactList}\small\item\em Get Sun Position.\item\end{CompactList}\item
     3367{\bf ps\-Coord} $\ast$ {\bf ps\-Get\-Moon\-Pos} (float mjd, double latitude, double longitude)
     3368\begin{CompactList}\small\item\em Get Moon position.\item\end{CompactList}\item
     3369float {\bf ps\-Get\-Moon\-Phase} (float mjd)
     3370\begin{CompactList}\small\item\em Get Moon phase.\item\end{CompactList}\item
     3371{\bf ps\-Coord} $\ast$ {\bf ps\-Get\-Solar\-System\-Pos} (char $\ast$solar\-System\-Object, float mjd)
     3372\begin{CompactList}\small\item\em Get Planet positions.\item\end{CompactList}\item
     3373{\bf ps\-Coord} $\ast$ {\bf ps\-Coordinates\-Ito\-E} (const {\bf ps\-Coord} $\ast$restrict coordinates)
     3374\begin{CompactList}\small\item\em Convert ICRS to Ecliptic.\item\end{CompactList}\item
     3375{\bf ps\-Coord} $\ast$ {\bf ps\-Coordinates\-Eto\-I} (const {\bf ps\-Coord} $\ast$restrict coordinates)
     3376\begin{CompactList}\small\item\em Convert Ecliptic to ICRS.\item\end{CompactList}\item
     3377{\bf ps\-Coord} $\ast$ {\bf ps\-Coordinates\-Ito\-G} (const {\bf ps\-Coord} $\ast$restrict coordinates)
     3378\begin{CompactList}\small\item\em Convert ICRS to Galactic.\item\end{CompactList}\item
     3379{\bf ps\-Coord} $\ast$ {\bf ps\-Coordinates\-Gto\-I} (const {\bf ps\-Coord} $\ast$restrict coordinates)
     3380\begin{CompactList}\small\item\em Convert Galactic to ICRS.\item\end{CompactList}\end{CompactItemize}
     3381
     3382
    13833383\bibliographystyle{plain} \bibliography{panstarrs}
    13843384
Note: See TracChangeset for help on using the changeset viewer.