Index: trunk/FACT++/pal/.gitignore
===================================================================
--- trunk/FACT++/pal/.gitignore	(revision 18347)
+++ trunk/FACT++/pal/.gitignore	(revision 18347)
@@ -0,0 +1,54 @@
+*~
+*.trs
+.deps
+.libs
+Makefile
+Makefile.in
+configure
+configure.in
+*.o
+*.lo
+*.la
+*.dSYM
+palTest
+make.log
+make.log.err
+config.h
+config.h.in
+config.log
+config.status
+stamp-h1
+libtool
+*.htx
+*.aux
+*.bbl
+*.blg
+*.dvi
+*.log
+*.htx_tar
+aclocal.m4
+autom4te.cache/
+componentinfo.dtd
+starconf.status
+sun267.ps
+sun267.pdf
+compile
+config.guess
+config.sub
+depcomp
+install-sh
+ltmain.sh
+missing
+stamp-h2
+pal-*.tar.gz
+pubs/adass2012/P56.pdf
+test-driver
+*.os
+.sconf_temp/
+.sconsign.dblite
+libpal.*.dylib
+libpal.a
+libpal.dylib
+sun267.fls
+sun267.out
+sun267.toc
Index: trunk/FACT++/pal/COPYING
===================================================================
--- trunk/FACT++/pal/COPYING	(revision 18347)
+++ trunk/FACT++/pal/COPYING	(revision 18347)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Index: trunk/FACT++/pal/COPYING.LESSER
===================================================================
--- trunk/FACT++/pal/COPYING.LESSER	(revision 18347)
+++ trunk/FACT++/pal/COPYING.LESSER	(revision 18347)
@@ -0,0 +1,165 @@
+                   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
Index: trunk/FACT++/pal/Makefile.am
===================================================================
--- trunk/FACT++/pal/Makefile.am	(revision 18347)
+++ trunk/FACT++/pal/Makefile.am	(revision 18347)
@@ -0,0 +1,138 @@
+## Process this file with automake to produce Makefile.in
+
+lib_LTLIBRARIES = libpal.la
+
+
+# Include palOne2One.c separately since it is a combo file
+libpal_la_SOURCES = $(PUBLIC_C_FILES) palOne2One.c $(PRIVATE_C_FILES)
+
+# If we are using a non-standard location
+libpal_la_CPPFLAGS = $(ERFA_CPPFLAGS)
+libpal_la_LDFLAGS = $(ERFA_LDFLAGS)
+
+# Force a link against ERFA and, optionally, starutil
+libpal_la_LIBADD = $(ERFA_LIBADD) $(STARUTIL_LIBADD)
+
+# Misc files
+dist_starnews_DATA = pal.news
+dist_pkgdata_DATA = COPYING COPYING.LESSER README.md
+
+# Make all library code position independent. This is handy for creating
+# shareable libraries from the static ones (Java JNI libraries).
+if !NOPIC
+libpal_la_CFLAGS = $(AM_CFLAGS) -prefer-pic
+endif
+
+# install pal as "star/pal.h"
+cincludedir = $(includedir)/star
+cinclude_HEADERS = pal.h palmac.h
+
+noinst_HEADERS = $(PRIVATE_INCLUDES)
+
+PRIVATE_INCLUDES = pal1.h pal1sofa.h
+
+PUBLIC_C_FILES = \
+palAddet.c \
+palAirmas.c \
+palAltaz.c \
+palAmp.c \
+palAmpqk.c \
+palAop.c \
+palAoppa.c \
+palAoppat.c \
+palAopqk.c \
+palAtmdsp.c \
+palCaldj.c \
+palDafin.c \
+palDe2h.c \
+palDeuler.c \
+palDfltin.c \
+palDh2e.c \
+palDjcal.c \
+palDmat.c \
+palDs2tp.c \
+palDat.c \
+palDmoon.c \
+palDrange.c \
+palDt.c \
+palDtp2s.c \
+palDtps2c.c \
+palDtt.c \
+palEcleq.c \
+palEcmat.c \
+palEl2ue.c \
+palEpco.c \
+palEpv.c \
+palEtrms.c \
+palEqecl.c \
+palEqgal.c \
+palEvp.c \
+palFk45z.c \
+palFk524.c \
+palFk54z.c \
+palGaleq.c \
+palGalsup.c \
+palGe50.c \
+palGeoc.c \
+palIntin.c \
+palMap.c \
+palMappa.c \
+palMapqk.c \
+palMapqkz.c \
+palNut.c \
+palNutc.c \
+palOap.c \
+palOapqk.c \
+palObs.c \
+palPa.c \
+palPcd.c \
+palPertel.c \
+palPertue.c \
+palPlanel.c \
+palPlanet.c \
+palPlante.c \
+palPlantu.c \
+palPm.c \
+palPolmo.c \
+palPrebn.c \
+palPrec.c \
+palPreces.c \
+palPrenut.c \
+palPv2el.c \
+palPv2ue.c \
+palPvobs.c \
+palRdplan.c \
+palRefco.c \
+palRefro.c \
+palRefv.c \
+palRefz.c \
+palRverot.c \
+palRvgalc.c \
+palRvlg.c \
+palRvlsrd.c \
+palRvlsrk.c \
+palSubet.c \
+palSupgal.c \
+palUe2el.c \
+palUe2pv.c \
+palUnpcd.c \
+palVers.c
+
+PRIVATE_C_FILES = \
+pal1Atms.c \
+pal1Atmt.c
+
+stardocs_DATA = @STAR_LATEX_DOCUMENTATION@
+
+TESTS = palTest
+
+check_PROGRAMS = palTest
+palTest_SOURCES = palTest.c
+palTest_LDADD = libpal.la
+
+# A target for making the SUN documentation. We do not do this automatically
+palsun.tex: $(PUBLIC_C_FILES)
+	-rm -f palsun.tex all.c
+	cat $(PUBLIC_C_FILES) > all.c
+	${STARCONF_DEFAULT_PREFIX}/bin/sst/prolat in=all.c out=palsun.tex single=no page=no atask=no document=no
+	-rm all.c
Index: trunk/FACT++/pal/README.md
===================================================================
--- trunk/FACT++/pal/README.md	(revision 18347)
+++ trunk/FACT++/pal/README.md	(revision 18347)
@@ -0,0 +1,76 @@
+PAL - Positional Astronomy Library
+==================================
+
+[![DOI](https://zenodo.org/badge/12517/Starlink/pal.svg)](http://dx.doi.org/10.5281/zenodo.17212)
+
+The PAL library is a partial re-implementation of Pat Wallace's popular SLALIB
+library written in C using a Gnu GPL license and layered on top of the IAU's
+SOFA library (or the BSD-licensed ERFA) where appropriate.
+PAL attempts to stick to the SLA C API where
+possible although `palObs()` has a more C-like API than the equivalent
+`slaObs()` function. In most cases it is enough to simply change the function
+prefix of a routine in order to link against PAL rather than SLALIB. Routines
+calling SOFA use modern nutation and precession models so will return slightly
+different answers than native SLALIB. PAL functions not available in SOFA were
+ported from the Fortran version of SLALIB that ships as part of the Starlink
+software and uses a GPL licence.
+
+See `pal.news` for release notes.
+
+Building
+--------
+
+A simple `configure` script is provided:
+
+    ./configure --prefix=/usr/local --without-starlink
+    make
+    make install
+
+The tests can be run using `make check`. Use `--prefix` to specify an install location.
+Given the history of the source code as a Starlink library the default will be `/star`.
+
+`--without-starlink` forces the configure script to forget about any Starlink
+configurations. This is the safe option if you run into problems when using
+a simple `--prefix` for building outside of Starlink. The configure script
+will assume Starlink is not being used by looking to see if
+`STARCONF_DEFAULT_PREFIX` environment variable is set. You may run into problems if
+`STARCONF_DEFAULT_PREFIX` is set but you use `--without-starlink`.
+
+Requirements
+------------
+
+Requires that either the SOFA C library or the ERFA library variant
+(which has a more permissive license than SOFA) be installed.  The
+`configure` script will abort if neither SOFA nor ERFA can be
+found. SOFA can be obtained either from <http://www.iausofa.org> or
+from an unofficial github repository (with a configure script) at
+<https://github.com/Starlink/sofa/downloads>.  ERFA can be downloaded
+from <https://github.com/liberfa/erfa>.
+
+Missing Functions
+-----------------
+
+Not all SLALIB functions have been added. New routines are added to PAL as demand arises.
+
+
+Language Bindings
+-----------------
+
+A Perl binding of PAL is available (<https://github.com/timj/perl-Astro-PAL>) named `Astro::PAL`
+and is available from CPAN at <https://metacpan.org/module/Astro::PAL>. This is a standalone
+distribution that comes with its own copies of PAL and SOFA and so can be installed directly
+from the `cpan` shell.
+
+A Python binding of PAL is available (<https://github.com/Starlink/palpy>). This is a standalone
+distribution that comes with its own copies of PAL and SOFA.
+
+The Starlink AST (<http://www.starlink.ac.uk/ast>) library now uses PAL and can be built
+either with a private PAL or with an external PAL.
+
+Documentation
+-------------
+
+The description paper for PAL is: ["_PAL: A Positional Astronomy Library_"](http://adsabs.harvard.edu/abs/2013ASPC..475..307J),
+Jenness, T. & Berry, D. S., in _Astronomical Data Anaysis Software and Systems XXII_,
+Friedel, D. N. (ed), ASP Conf. Ser. **475**, p307.
+
Index: trunk/FACT++/pal/SConstruct
===================================================================
--- trunk/FACT++/pal/SConstruct	(revision 18347)
+++ trunk/FACT++/pal/SConstruct	(revision 18347)
@@ -0,0 +1,208 @@
+# PAL SConstruct file
+import os
+
+version = "0.9.2"
+
+def CheckStarlink(context):
+    context.Message( "Checking for Starlink environment...")
+    if "STARLINK_DIR" in os.environ:
+        star_root = os.environ["STARCONF_DEFAULT_PREFIX"]
+        star_lib = os.path.join(star_root, "lib")
+        star_inc = os.path.join(star_root, "include")
+        star_share = os.path.join(star_root, "share")
+        star_bin = os.path.join(star_root, "bin")
+        context.env.PrependENVPath('PATH', star_bin)
+        context.Result(star_root)
+        context.env.Replace(PREFIX = star_root)
+        context.env.Append(CPPPATH=star_inc, LIBPATH=star_lib)
+        return { "root": star_root,
+                 "lib": star_lib,
+                 "include": star_inc,
+                 "bin": star_bin,
+                 "share": star_share, }
+    context.Result("failed")
+    return None
+
+# Allow --prefix to be specified. We don't use it in Starlink mode
+# though
+AddOption('--prefix',
+          dest='prefix',
+          type='string',
+          nargs=1,
+          action='store',
+          metavar='DIR',
+          help='installation prefix')
+
+env = Environment(PREFIX = "/usr/local" ) # Initialise the environment
+
+prefix = GetOption("prefix")
+if prefix:
+    env.Replace(PREFIX = prefix)
+
+
+# Basic configure checks: but not if --help or --clean
+if not GetOption("help") and not GetOption("clean"):
+    conf = Configure(env, custom_tests = {"CheckStarlink": CheckStarlink} )
+
+    if not conf.CheckCC():
+        print("!! Your compiler and/or environment is not correctly configured.")
+        Exit(0)
+
+    if conf.CheckFunc("copysign"):
+        conf.env.Append(CPPDEFINES={"HAVE_COPYSIGN": 1})
+
+    if conf.CheckFunc("isblank"):
+        conf.env.Append(CPPDEFINES={"HAVE_ISBLANK": 1})
+
+    if conf.CheckFunc("strlcpy"):
+        conf.env.Append(CPPDEFINES={"HAVE_STRLCPY": 1})
+
+    # Force -lm if we need it
+    conf.CheckLib("m","sin")
+
+    # Try to look in current directory
+    conf.env.Append(LIBPATH=["."])
+    conf.env.Append(CPPPATH=["."])
+
+    # If we are in a Starlink environment we know we have
+    # ERFA so just set things up for that. This should be done
+    # using a general SCons "are we starlink" plugin
+    starlink = conf.CheckStarlink()
+    if starlink is not None:
+        conf.env.Append(LIBS=["erfa"])
+        conf.env.Append(CPPDEFINES={"HAVE_STAR_UTIL": 1})
+        conf.env.Append(LIBS=["starutil"])
+    else:
+        # Allow PREFIX to work
+        conf.env.Append(CPPPATH=[os.path.join("$PREFIX", "include")])
+        conf.env.Append(LIBPATH=[os.path.join("$PREFIX", "lib")])
+
+        # Maybe starutil will be available
+        if conf.CheckLib("starutil"):
+            conf.env.Append(CPPDEFINES={"HAVE_STAR_UTIL": 1})
+
+        # Need to look for ERFA vs SOFA
+        if not conf.CheckLib("erfa","eraCal2jd"):
+            if conf.CheckLib("sofa_c","iauCal2jd"):
+                conf.env.Append(CPPDEFINES={"HAVE_SOFA_H": 1})
+            else:
+                print("!! Neither ERFA not SOFA library located. Can not continue. !!")
+                Exit(0)
+
+    env = conf.Finish()
+
+# PAL source code
+libpal_sources = [
+    "pal1Atms.c",
+    "pal1Atmt.c",
+    "palAddet.c",
+    "palAirmas.c",
+    "palAltaz.c",
+    "palAmp.c",
+    "palAmpqk.c",
+    "palAop.c",
+    "palAoppa.c",
+    "palAoppat.c",
+    "palAopqk.c",
+    "palAtmdsp.c",
+    "palCaldj.c",
+    "palDafin.c",
+    "palDat.c",
+    "palDe2h.c",
+    "palDeuler.c",
+    "palDfltin.c",
+    "palDh2e.c",
+    "palDjcal.c",
+    "palDmat.c",
+    "palDmoon.c",
+    "palDrange.c",
+    "palDs2tp.c",
+    "palDt.c",
+    "palDtp2s.c",
+    "palDtps2c.c",
+    "palDtt.c",
+    "palEcmat.c",
+    "palEl2ue.c",
+    "palEpco.c",
+    "palEpv.c",
+    "palEqecl.c",
+    "palEqgal.c",
+    "palEtrms.c",
+    "palEvp.c",
+    "palFk45z.c",
+    "palFk524.c",
+    "palFk54z.c",
+    "palGaleq.c",
+    "palGalsup.c",
+    "palGe50.c",
+    "palGeoc.c",
+    "palIntin.c",
+    "palMap.c",
+    "palMappa.c",
+    "palMapqk.c",
+    "palMapqkz.c",
+    "palNut.c",
+    "palNutc.c",
+    "palOap.c",
+    "palOapqk.c",
+    "palObs.c",
+    "palOne2One.c",
+    "palPa.c",
+    "palPertel.c",
+    "palPertue.c",
+    "palPlanel.c",
+    "palPlanet.c",
+    "palPlante.c",
+    "palPlantu.c",
+    "palPm.c",
+    "palPolmo.c",
+    "palPrebn.c",
+    "palPrec.c",
+    "palPreces.c",
+    "palPrenut.c",
+    "palPv2el.c",
+    "palPv2ue.c",
+    "palPvobs.c",
+    "palRdplan.c",
+    "palRefco.c",
+    "palRefro.c",
+    "palRefv.c",
+    "palRefz.c",
+    "palRverot.c",
+    "palRvgalc.c",
+    "palRvlg.c",
+    "palRvlsrd.c",
+    "palRvlsrk.c",
+    "palSubet.c",
+    "palSupgal.c",
+    "palUe2el.c",
+    "palUe2pv.c",
+    ]
+
+sun267_sources = [ "sun267.tex" ]
+sun267_pdf = env.PDF( sun267_sources )
+Default(sun267_pdf)
+
+# Compiler should look in current directory for header files
+
+staticpal = env.StaticLibrary(target="pal", source=libpal_sources)
+sharedpal = env.SharedLibrary( target="pal", source = libpal_sources,
+                               SHLIBVERSION=version )
+
+palTest = env.Program("palTest", "palTest.c", LIBS=["pal"] )
+test_alias = Alias("test", [palTest], palTest[0].abspath)
+AlwaysBuild(test_alias)
+
+installed_sharedlib = env.InstallVersionedLib(os.path.join("$PREFIX","lib"),
+                                            [sharedpal], SHLIBVERSION=version )
+installed_staticlib = env.Install("$PREFIX/lib", [staticpal] )
+
+# Just build the library by default
+Default(sharedpal)
+Default(staticpal)
+
+# install on request
+if "install" in COMMAND_LINE_TARGETS:
+    env.Alias( "install", "$PREFIX" )
+    Default(installed_sharedlib, installed_staticlib)
+
Index: trunk/FACT++/pal/bootstrap
===================================================================
--- trunk/FACT++/pal/bootstrap	(revision 18347)
+++ trunk/FACT++/pal/bootstrap	(revision 18347)
@@ -0,0 +1,134 @@
+#! /bin/sh -
+# original bootstrap file, installed by starconf 1.3, rnum=1003000
+# If you _need_ to change this file, delete `original' in the line above,
+# or else starconf may overwrite it with an updated version.
+#
+# bootstrap.installed.  Generated from bootstrap.installed.in by configure.
+#
+# Bootstrap a checked-out component of the Starlink software tree.
+# Run this script in a freshly checked-out directory to bring the
+# system to the point where you can just type ./configure;make
+#
+# Usage:
+#     ./bootstrap
+
+
+# This script should be installed, by starconf, in all `component
+# directories'.  A `component directory' is a directory which has a
+# component.xml.in file in it.  All component directories will have a
+# manifest file created and installed in .../manifests; non-component
+# directories will not have manifest files.  Everything that's
+# installed should be installed as part of some component
+# or other.
+#
+# The ./bootstrap scripts will stop recursing when they find a
+# component.xml.in file.  They'll warn if they find a component.xml.in
+# file in any AC_CONFIG_SUBDIRS directory, but ignore it, and exit
+# with an error if they do not find a component.xml.in file and there
+# are no AC_CONFIG_SUBDIRS directories in which to search further.
+# That is, the tree of directories which the top-level bootstrap
+# traverses should have component.xml.in files at or above all its
+# leaves.
+
+
+# The starconf below might update bootstrap, if a newer version is
+# available.  Unfortunately, this confuses sh, which appears _not_ to
+# keep open the script it's reading, but to reopen it afresh, or reseek
+# within the file, for each line (or something like that!?).
+# So rewrite this script to a temporary file and exec it.
+tempfile="${TMP-/tmp}/$0-$$.tmp"
+rm -f $tempfile
+echo "trap 'rm -f $tempfile' 0" >$tempfile   # remove temporary at exit
+sed '1,/^--TRAMPOLINE--/d' $0 >>$tempfile    # strip out the trampoline
+exec /bin/sh $tempfile                       # exec the temporary
+--TRAMPOLINE--
+
+
+echo "Bootstrapping `pwd` ..."
+
+if test ! -f configure.ac; then
+    echo "bootstrap: No configure.ac in directory `pwd`" >&2
+    exit 1
+fi
+
+subdirs=`autoconf --trace=AC_CONFIG_SUBDIRS:$% configure.ac`
+
+if test -f component.xml.in; then
+
+    if starconf --show buildsupport >/dev/null 2>&1; then
+
+        # starconf is in the path
+        echo "...using starconf in " `starconf --show buildsupport`
+        starconf || exit 1
+
+    else
+
+        # The temptation here is to use ./starconf.status to find the
+        # starconf that it came from and invoke that explicitly.  Don't do
+        # this, however: we don't want to be too clever, and it's better
+        # to be consistent with the way the autotools behave (the first
+        # one in your path is the one that works, and they don't have this
+        # sort of `phone home' cleverness in them).
+
+        echo "bootstrap error: The starconf application is not in your path"
+
+        # This doesn't stop us being helpful, however.
+        if test -f ./starconf.status; then
+            starconf_home=`./starconf.status --show buildsupport`
+            echo "This directory was last bootstrapped with $starconf_home/bin/starconf"
+        fi
+
+        exit 1
+    fi
+
+    # Check that there are no component.xml.in files in any subdirectories
+    if test -n "$subdirs"; then
+        for d in $subdirs
+        do
+            if test -d "$d" && test -f "$d/component.xml.in"; then
+                echo "bootstrap: warning: ignoring child $d/component.xml.in" >&2
+            fi
+        done
+    fi
+
+    # If STAR_SUPPRESS_AUTORECONF is true in the environment, then we
+    # suppress the call of `autoreconf'.  This is here _only_ so that
+    # the top-level bootstrap file can suppress multiple calls of this
+    # in bootstrap scripts in its children.  This mechanism must not
+    # be used by users, as it is likely to change without warning. 
+    if ${STAR_SUPPRESS_AUTORECONF-false}; then
+        echo "Suppressing autoreconf in" `pwd`
+    else
+        echo autoreconf --install --symlink
+        autoreconf --install --symlink || exit 1
+    fi
+
+else
+
+    # This is not a component directory, so simply recurse into the children.
+
+    # ...if there are any, that is.
+    if test -z "$subdirs"; then
+        echo "bootstrap: error: non-component directory `pwd` has no subdirs" >&2
+        exit 1
+    fi
+
+    # Bootstrap the child directories mentioned in AC_CONFIG_SUBDIRS.
+    # These bootstrap files must exist.
+    for d in $subdirs
+    do
+        if test -d "$d"; then
+            echo "Bootstrapping $d..."
+            if test -f $d/bootstrap; then
+                # good...
+                (cd $d; /bin/sh ./bootstrap)
+            else
+                echo "bootstrap: no file $d/bootstrap" >&2
+                exit 1
+            fi
+        fi
+    done
+
+fi
+
+exit 0
Index: trunk/FACT++/pal/codemeta.json
===================================================================
--- trunk/FACT++/pal/codemeta.json	(revision 18347)
+++ trunk/FACT++/pal/codemeta.json	(revision 18347)
@@ -0,0 +1,41 @@
+{
+    "@context": "https://raw.githubusercontent.com/mbjones/codemeta/master/codemeta.jsonld",
+    "@type": "Code",
+    "author": [
+        {
+            "@id": "http://orcid.org/0000-0001-5982-167X",
+            "@type": "Person",
+            "email": "tim.jenness@gmail.com",
+            "name": "Tim Jenness",
+        },
+        {
+            "@id": "http://orcid.org/0000-0001-6524-2447",
+            "@type": "Person",
+            "email": "d.berry@eaobservatory.org",
+            "name": "David Berry",
+            "affiliation": "East Asian Observatory"
+        },
+        {
+            "@id": "",
+            "@type": "Person",
+            "email": "patrick.wallace@stfc.ac.uk",
+            "name": "Patrick Wallace",
+            "affiliation": "STFC",
+        }
+    ],
+    "identifier": "http://dx.doi.org/10.5281/zenodo.17212",
+    "codeRepository": "https://github.com/Starlink/pal",
+    "dateCreated": "2012-02-08",
+    "description": "The PAL library is a partial re-implementation of Pat Wallace's popular SLALIB library written in C using a Gnu GPL license and layered on top of the IAU's SOFA library (or the BSD-licensed ERFA) where appropriate.",
+    "keywords": "astronomy, Starlink, astrometry",
+    "license": "http://opensource.org/licenses/GPL-3.0",
+    "title": "PAL: Positional Astronomy Library",
+    "version": "0.9.1",
+    "uploadedBy":
+        {
+            "@id": "http://orcid.org/0000-0001-5982-167X",
+            "@type": "Person",
+            "email": "tim.jenness@gmail.com",
+            "name": "Tim Jenness",
+        }
+}
Index: trunk/FACT++/pal/component.xml
===================================================================
--- trunk/FACT++/pal/component.xml	(revision 18347)
+++ trunk/FACT++/pal/component.xml	(revision 18347)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE component SYSTEM "componentinfo.dtd">
+<!-- component.xml.  Generated from component.xml.in by configure. -->
+
+<component id="pal" support="S">
+  <version>0.9.3</version>
+  <path>libext/pal</path>
+  <description>Positional Astronomy Library</description>
+  <abstract><p>
+    This library is a collection of code designed to aid in
+    replacing the SLA library with code from SOFA.
+
+    Where possible the API is similar to the C SLA API
+    except for the use of a "pal" prefix.
+    </p></abstract>
+  <dependencies >
+    <build>erfa</build><build>starutil</build><link>erfa</link><link>starutil</link><sourceset>star2html</sourceset>
+  </dependencies>
+  <developers>
+    <person>
+      <name>Tim Jenness</name>
+      <uname>t.jenness@jach.hawaii.edu</uname>
+    </person>
+  </developers>
+  <documentation> sun267</documentation>
+  <bugreports>starlink@jiscmail.ac.uk</bugreports>
+  <!-- <notes><p></p></notes> -->
+</component>
Index: trunk/FACT++/pal/component.xml.in
===================================================================
--- trunk/FACT++/pal/component.xml.in	(revision 18347)
+++ trunk/FACT++/pal/component.xml.in	(revision 18347)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<!DOCTYPE component SYSTEM "componentinfo.dtd">
+<!-- @configure_input@ -->
+
+<component id="@PACKAGE@" support="S">
+  <version>@PACKAGE_VERSION@</version>
+  <path>libext/pal</path>
+  <description>Positional Astronomy Library</description>
+  <abstract><p>
+    This library is a collection of code designed to aid in
+    replacing the SLA library with code from SOFA.
+
+    Where possible the API is similar to the C SLA API
+    except for the use of a "pal" prefix.
+    </p></abstract>
+  <dependencies @STAR_DEPENDENCIES_ATTRIBUTES@>
+    @STAR_DEPENDENCIES_CHILDREN@
+  </dependencies>
+  <developers>
+    <person>
+      <name>Tim Jenness</name>
+      <uname>t.jenness@jach.hawaii.edu</uname>
+    </person>
+  </developers>
+  <documentation>@STAR_DOCUMENTATION@</documentation>
+  <bugreports>@PACKAGE_BUGREPORT@</bugreports>
+  <!-- <notes><p></p></notes> -->
+</component>
Index: trunk/FACT++/pal/configure.ac
===================================================================
--- trunk/FACT++/pal/configure.ac	(revision 18347)
+++ trunk/FACT++/pal/configure.ac	(revision 18347)
@@ -0,0 +1,137 @@
+dnl    Process this file with autoconf to produce a configure script
+AC_REVISION($Revision: 27534 $)
+
+dnl    Initialisation: package name and version number
+AC_INIT([pal],[0.9.3],[starlink@jiscmail.ac.uk])
+AC_CONFIG_AUX_DIR([build-aux])
+
+dnl    Require autoconf-2.50 at least
+AC_PREREQ([2.69])
+dnl    Require Starlink automake
+AM_INIT_AUTOMAKE(1.8.2-starlink)
+
+dnl    Sanity-check: name a file in the source directory -- if this
+dnl    isn't found then configure will complain
+AC_CONFIG_SRCDIR([pal.h])
+
+dnl    Include defaults for Starlink configurations
+STAR_DEFAULTS
+
+dnl    Would like the version number as an integer
+AC_DEFINE_UNQUOTED([PACKAGE_VERSION_INTEGER], $PACKAGE_VERSION_INTEGER,
+                    [Integer version number, in the form major*1e6+minor*1e3+release])
+
+dnl    Find required versions of the programs we need for configuration
+AC_PROG_CC
+LT_INIT
+
+#   If --with-pic=no is set we should honour that.
+AM_CONDITIONAL(NOPIC, test x$pic_mode = xno)
+
+dnl    copysign and isblank are a c99 feature
+AC_CHECK_FUNCS(copysign)
+AC_CHECK_FUNCS(isblank)
+
+dnl    Use strlcpy if it is available
+AC_SEARCH_LIBS([strlcpy], [bsd])
+AS_IF([test "x$ac_cv_search_strlcpy" = "x-lbsd"], [AC_CHECK_HEADERS([bsd/string.h])])
+AC_CHECK_FUNCS([strlcpy])
+
+# Need the math library
+AC_CHECK_LIB([m],[sin])
+
+dnl    We can not simply test for Starlink starutil because
+dnl    when configure runs in a Starlink build starutil will not
+dnl    have been built yet. If --without-starlink has been used
+dnl    $STARLINK will be unset but to play safe we also check STARCONF_DEFAULT_PREFIX
+dnl    If we do not have Starlink we can do the test anyhow just in case
+
+if test -n "$STARCONF_DEFAULT_PREFIX" -a -n "$STARLINK"
+then
+  AC_MSG_NOTICE([Assuming a Starlink environment])
+  AC_SUBST( STARUTIL_LIBADD, "${libdir}/libstarutil.la" )
+  AC_SUBST( ERFA_LIBADD, "${libdir}/liberfa.la" )
+  AC_SUBST( ERFA_LDFLAGS, "" )
+  AC_DEFINE( [HAVE_STAR_UTIL_H], [1], [Define to 1 if you have the <star/util.h> header file])
+else
+
+  #   Allow ERFA/SOFA location to be specified using --with-erfa=$ERFA_DIR
+  #   Assumes that the value supplied here is the root and lib and include directories
+  #   are below it. --with-erfa=no or --without-erfa will result in ERFA being
+  #   located in $PREFIX tree. This option is only effective if Starlink is not
+  #   active.
+  AC_ARG_WITH(erfa,
+              AS_HELP_STRING([--with-erfa],
+                             [Location of ERFA/SOFA tree]),
+              [if test -z "$withval" -o "$withval" = yes; then
+                   unset ERFA_DIR
+               elif test "X$withval" = Xno; then
+                   unset ERFA_DIR
+               elif test -d "$withval"; then
+                   ERFA_DIR="$withval"
+               else
+                   unset ERFA_DIR
+                   AC_MSG_WARN([--with-erfa given nonexistent directory; ignored: using default instead])
+               fi])
+  if test -n "$ERFA_DIR"; then
+      AC_MSG_NOTICE([ERFA/SOFA tree located at $ERFA_DIR])
+      erfa_includedir="${ERFA_DIR}/include"
+      erfa_libdir="${ERFA_DIR}/lib"
+  else
+      ERFA_DIR=${prefix}
+      erfa_includedir=${includedir}
+      erfa_libdir=${libdir}
+      AC_MSG_NOTICE([Looking for ERFA/SOFA in default location of $ERFA_DIR])
+  fi
+
+  dnl AC_CHECK_HEADERS does not search $includedir
+  save_CPPFLAGS="$CPPFLAGS"
+  eval CPPFLAGS=\"$CPPFLAGS -I${includedir} -I${erfa_includedir}\"
+  eval CPPFLAGS=\"$CPPFLAGS\"
+  AC_CHECK_HEADERS( star/util.h )
+  CPPFLAGS="$save_CPPFLAGS"
+
+  dnl for some reason AC_CHECK_LIB does not look in the --prefix hierarchy so
+  dnl $libdir is not searched.
+  dnl and we use eval twice to convert $libdir -> $exec_prefix/lib -> $prefix/lib
+  save_LDFLAGS="$LDFLAGS"
+  eval LDFLAGS=\"$LDFLAGS -L${libdir} -L${erfa_libdir}\"
+  eval LDFLAGS=\"$LDFLAGS\"
+
+  AC_CHECK_LIB([starutil],[star_strlcpy],
+               [AC_SUBST(STARUTIL_LIBADD, "-lstarutil")],
+               [AC_SUBST(STARUTIL_LIBADD, "")])
+
+  AC_CHECK_LIB([erfa],[eraCal2jd],
+               [AC_SUBST(ERFA_LIBADD, "-lerfa")],
+               [
+                AC_CHECK_LIB([sofa_c],[iauCal2jd],
+                             [AC_SUBST(ERFA_LIBADD, "-lsofa_c")
+                              AC_DEFINE([HAVE_SOFA_H],[1],"Build with SOFA library")],
+                             [AC_MSG_ERROR(Neither ERFA nor SOFA library located. Can not continue)])
+               ])
+  LDFLAGS="$save_LDFLAGS"
+
+  dnl  Ensure that we use the $prefix values and the ERFA values
+  AC_SUBST( ERFA_LDFLAGS, "-L${libdir} -L${erfa_libdir}" )
+  AC_SUBST( ERFA_CPPFLAGS, "-I${includedir} -I${erfa_includedir}" )
+
+  dnl  Disable document building regardless of --without-stardocs
+  _star_build_docs=:
+fi
+
+dnl    Declare the build and use dependencies for this package
+STAR_DECLARE_DEPENDENCIES(build, [erfa starutil])
+STAR_DECLARE_DEPENDENCIES(link,  [erfa starutil])
+
+dnl    List the sun/ssn/... numbers which document this package and
+dnl    which are present as .tex files in this directory.
+STAR_LATEX_DOCUMENTATION(sun267)
+
+dnl    If you wish to configure extra files, you can add them to this
+dnl    declaration.
+AC_CONFIG_FILES(Makefile component.xml)
+AC_CONFIG_HEADERS( config.h )
+
+dnl    This is the bit that does the actual work
+AC_OUTPUT
Index: trunk/FACT++/pal/pal.h
===================================================================
--- trunk/FACT++/pal/pal.h	(revision 18347)
+++ trunk/FACT++/pal/pal.h	(revision 18347)
@@ -0,0 +1,551 @@
+#ifndef PALHDEF
+#define PALHDEF
+
+/*
+*+
+*  Name:
+*     pal.h
+
+*  Purpose:
+*     Function prototypes for PAL routines.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Include file
+
+*  Description:
+*     Function prototypes for PAL routines.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version. Define all SLA prototypes in PAL form even
+*        though none are implemented.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+
+void palAddet ( double rm, double dm, double eq, double *rc, double *dc );
+
+void palAfin ( const char *string, int *iptr, float *a, int *j );
+
+double palAirmas ( double zd );
+
+void palAltaz ( double ha, double dec, double phi,
+                double *az, double *azd, double *azdd,
+                double *el, double *eld, double *eldd,
+                double *pa, double *pad, double *padd );
+
+void palAmp ( double ra, double da, double date, double eq,
+              double *rm, double *dm );
+
+void palAmpqk ( double ra, double da, double amprms[21],
+                double *rm, double *dm );
+
+void palAop ( double rap, double dap, double date, double dut,
+              double elongm, double phim, double hm, double xp,
+              double yp, double tdk, double pmb, double rh,
+              double wl, double tlr,
+              double *aob, double *zob, double *hob,
+              double *dob, double *rob );
+
+void palAoppa ( double date, double dut, double elongm, double phim,
+                double hm, double xp, double yp, double tdk, double pmb,
+                double rh, double wl, double tlr, double aoprms[14] );
+
+void palAoppat ( double date, double aoprms[14] );
+
+void palAopqk ( double rap, double dap, const double aoprms[14],
+                double *aob, double *zob, double *hob,
+                double *dob, double *rob );
+
+void palAtmdsp ( double tdk, double pmb, double rh, double wl1,
+                 double a1, double b1, double wl2, double *a2, double *b2 );
+
+void palAv2m ( float axvec[3], float rmat[3][3] );
+
+float palBear ( float a1, float b1, float a2, float b2 );
+
+void palCaf2r ( int ideg, int iamin, float asec, float *rad, int *j );
+
+void palCaldj ( int iy, int im, int id, double *djm, int *j );
+
+void palCalyd ( int iy, int im, int id, int *ny, int *nd, int *j );
+
+void palCc2s ( float v[3], float *a, float *b );
+
+void palCc62s ( float v[6], float *a, float *b, float *r,
+                float *ad, float *bd, float *rd );
+
+void palCd2tf ( int ndp, float days, char *sign, int ihmsf[4] );
+
+void palCldj ( int iy, int im, int id, double *djm, int *j );
+
+void palClyd ( int iy, int im, int id, int *ny, int *nd, int *jstat );
+
+void palCombn ( int nsel, int ncand, int list[], int *j );
+
+void palCr2af ( int ndp, float angle, char *sign, int idmsf[4] );
+
+void palCr2tf ( int ndp, float angle, char *sign, int ihmsf[4] );
+
+void palCs2c ( float a, float b, float v[3] );
+
+void palCs2c6 ( float a, float b, float r, float ad,
+                float bd, float rd, float v[6] );
+
+void palCtf2d ( int ihour, int imin, float sec, float *days, int *j );
+
+void palCtf2r ( int ihour, int imin, float sec, float *rad, int *j );
+
+void palDaf2r ( int ideg, int iamin, double asec, double *rad, int *j );
+
+void palDafin ( const char *string, int *iptr, double *a, int *j );
+
+double palDat ( double dju );
+
+void palDav2m ( double axvec[3], double rmat[3][3] );
+
+double palDbear ( double a1, double b1, double a2, double b2 );
+
+void palDbjin ( const char *string, int *nstrt,
+                double *dreslt, int *jf1, int *jf2 );
+
+void palDc62s ( double v[6], double *a, double *b, double *r,
+                double *ad, double *bd, double *rd );
+
+void palDcc2s ( double v[3], double *a, double *b );
+
+void palDcmpf ( double coeffs[6], double *xz, double *yz, double *xs,
+                double *ys, double *perp, double *orient );
+
+void palDcs2c ( double a, double b, double v[3] );
+
+void palDd2tf ( int ndp, double days, char *sign, int ihmsf[4] );
+
+void palDe2h ( double ha, double dec, double phi,
+               double *az, double *el );
+
+void palDeuler ( const char *order, double phi, double theta, double psi,
+                 double rmat[3][3] );
+
+void palDfltin ( const char *string, int *nstrt, double *dreslt, int *jflag );
+
+void palDh2e ( double az, double el, double phi, double *ha, double *dec);
+
+void palDimxv ( double dm[3][3], double va[3], double vb[3] );
+
+void palDjcal ( int ndp, double djm, int iymdf[4], int *j );
+
+void palDjcl ( double djm, int *iy, int *im, int *id, double *fd, int *j );
+
+void palDm2av ( double rmat[3][3], double axvec[3] );
+
+void palDmat ( int n, double *a, double *y, double *d, int *jf, int *iw );
+
+void palDmoon ( double date, double pv[6] );
+
+void palDmxm ( double a[3][3], double b[3][3], double c[3][3] );
+
+void palDmxv ( double dm[3][3], double va[3], double vb[3] );
+
+double palDpav ( double v1[3], double v2[3] );
+
+void palDr2af ( int ndp, double angle, char *sign, int idmsf[4] );
+
+void palDr2tf ( int ndp, double angle, char *sign, int ihmsf[4] );
+
+double palDrange ( double angle );
+
+double palDranrm ( double angle );
+
+void palDs2c6 ( double a, double b, double r, double ad, double bd,
+                double rd, double v[6] );
+
+void palDs2tp ( double ra, double dec, double raz, double decz,
+                double *xi, double *eta, int *j );
+
+double palDsep ( double a1, double b1, double a2, double b2 );
+
+double palDsepv ( double v1[3], double v2[3] );
+
+double palDt ( double epoch );
+
+void palDtf2d ( int ihour, int imin, double sec, double *days, int *j );
+
+void palDtf2r ( int ihour, int imin, double sec, double *rad, int *j );
+
+void palDtp2s ( double xi, double eta, double raz, double decz,
+                double *ra, double *dec );
+
+void palDtp2v ( double xi, double eta, double v0[3], double v[3] );
+
+void palDtps2c ( double xi, double eta, double ra, double dec,
+                 double *raz1, double *decz1,
+                 double *raz2, double *decz2, int *n );
+
+void palDtpv2c ( double xi, double eta, double v[3],
+                 double v01[3], double v02[3], int *n );
+
+double palDtt ( double dju );
+
+void palDv2tp ( double v[3], double v0[3], double *xi, double *eta, int *j );
+
+double palDvdv ( double va[3], double vb[3] );
+
+void palDvn ( double v[3], double uv[3], double *vm );
+
+void palDvxv ( double va[3], double vb[3], double vc[3] );
+
+void palE2h ( float ha, float dec, float phi, float *az, float *el );
+
+void palEarth ( int iy, int id, float fd, float posvel[6] );
+
+void palEcleq ( double dl, double db, double date, double *dr, double *dd );
+
+void palEcmat ( double date, double rmat[3][3] );
+
+void palEcor ( float rm, float dm, int iy, int id, float fd,
+               float *rv, float *tl );
+
+void palEg50 ( double dr, double dd, double *dl, double *db );
+
+void palEl2ue ( double date, int jform, double epoch, double orbinc,
+                double anode, double perih, double aorq, double e,
+                double aorl, double dm, double u[13], int *jstat );
+
+double palEpb ( double date );
+
+double palEpb2d ( double epb );
+
+double palEpco ( char k0, char k, double e );
+
+double palEpj ( double date );
+
+double palEpj2d ( double epj );
+
+void palEpv( double date, double ph[3], double vh[3],
+             double pb[3], double vb[3] );
+
+void palEqecl ( double dr, double dd, double date, double *dl, double *db );
+
+double palEqeqx ( double date );
+
+void palEqgal ( double dr, double dd, double *dl, double *db );
+
+void palEtrms ( double ep, double ev[3] );
+
+void palEuler ( const char *order, float phi, float theta, float psi,
+                float rmat[3][3] );
+
+void palEvp ( double date, double deqx,
+              double dvb[3], double dpb[3],
+              double dvh[3], double dph[3] );
+
+void palFitxy ( int itype, int np, double xye[][2], double xym[][2],
+                double coeffs[6], int *j );
+
+void palFk425 ( double r1950, double d1950, double dr1950,
+                double dd1950, double p1950, double v1950,
+                double *r2000, double *d2000, double *dr2000,
+                double *dd2000, double *p2000, double *v2000 );
+
+void palFk45z ( double r1950, double d1950, double bepoch,
+                double *r2000, double *d2000 );
+
+void palFk524 ( double r2000, double d2000, double dr2000,
+                double dd2000, double p2000, double v2000,
+                double *r1950, double *d1950, double *dr1950,
+                double *dd1950, double *p1950, double *v1950 );
+
+void palFk52h ( double r5, double d5, double dr5, double dd5,
+                double *dr, double *dh, double *drh, double *ddh );
+
+void palFk54z ( double r2000, double d2000, double bepoch,
+                double *r1950, double *d1950,
+                double *dr1950, double *dd1950 );
+
+void palFk5hz ( double r5, double d5, double epoch,
+                double *rh, double *dh );
+
+void palFlotin ( const char *string, int *nstrt, float *reslt, int *jflag );
+
+void palGaleq ( double dl, double db, double *dr, double *dd );
+
+void palGalsup ( double dl, double db, double *dsl, double *dsb );
+
+void palGe50 ( double dl, double db, double *dr, double *dd );
+
+void palGeoc ( double p, double h, double *r, double *z );
+
+double palGmst ( double ut1 );
+
+double palGmsta ( double date, double ut1 );
+
+void palH2e ( float az, float el, float phi, float *ha, float *dec );
+
+void palH2fk5 ( double dr, double dh, double drh, double ddh,
+                double *r5, double *d5, double *dr5, double *dd5 );
+
+void palHfk5z ( double rh, double dh, double epoch,
+                double *r5, double *d5, double *dr5, double *dd5 );
+
+void palImxv ( float rm[3][3], float va[3], float vb[3] );
+
+void palInt2in ( const char *string, int *nstrt, int *ireslt, int *jflag );
+
+void palIntin ( const char *string, int *nstrt, long *ireslt, int *jflag );
+
+void palInvf ( double fwds[6], double bkwds[6], int *j );
+
+void palKbj ( int jb, double e, char *k, int *j );
+
+void palM2av ( float rmat[3][3], float axvec[3] );
+
+void palMap ( double rm, double dm, double pr, double pd,
+              double px, double rv, double eq, double date,
+              double *ra, double *da );
+
+void palMappa ( double eq, double date, double amprms[21] );
+
+void palMapqk ( double rm, double dm, double pr, double pd,
+                double px, double rv, double amprms[21],
+                double *ra, double *da );
+
+void palMapqkz ( double rm, double dm, double amprms[21],
+                 double *ra, double *da );
+
+void palMoon ( int iy, int id, float fd, float posvel[6] );
+
+void palMxm ( float a[3][3], float b[3][3], float c[3][3] );
+
+void palMxv ( float rm[3][3], float va[3], float vb[3] );
+
+void palNut ( double date, double rmatn[3][3] );
+
+void palNutc ( double date, double *dpsi, double *deps, double *eps0 );
+
+void palNutc80 ( double date, double *dpsi, double *deps, double *eps0 );
+
+void palOap ( const char *type, double ob1, double ob2, double date,
+              double dut, double elongm, double phim, double hm,
+              double xp, double yp, double tdk, double pmb,
+              double rh, double wl, double tlr,
+              double *rap, double *dap );
+
+void palOapqk ( const char *type, double ob1, double ob2, const double aoprms[14],
+                double *rap, double *dap );
+
+int palObs( size_t n, const char * c,
+            char * ident, size_t identlen,
+            char * name, size_t namelen,
+            double * w, double * p, double * h );
+
+double palPa ( double ha, double dec, double phi );
+
+double palPav ( float v1[3], float v2[3] );
+
+void palPcd ( double disco, double *x, double *y );
+
+void palPda2h ( double p, double d, double a,
+                double *h1, int *j1, double *h2, int *j2 );
+
+void palPdq2h ( double p, double d, double q,
+                double *h1, int *j1, double *h2, int *j2 );
+
+void palPermut ( int n, int istate[], int iorder[], int *j );
+
+void palPertel (int jform, double date0, double date1,
+                double epoch0, double orbi0, double anode0,
+                double perih0, double aorq0, double e0, double am0,
+                double *epoch1, double *orbi1, double *anode1,
+                double *perih1, double *aorq1, double *e1, double *am1,
+                int *jstat );
+
+void palPertue ( double date, double u[13], int *jstat );
+
+void palPlanel ( double date, int jform, double epoch, double orbinc,
+                 double anode, double perih, double aorq,  double e,
+                 double aorl, double dm, double pv[6], int *jstat );
+
+void palPlanet ( double date, int np, double pv[6], int *j );
+
+void palPlante ( double date, double elong, double phi, int jform,
+                 double epoch, double orbinc, double anode, double perih,
+                 double aorq, double e, double aorl, double dm,
+                 double *ra, double *dec, double *r, int *jstat );
+
+void palPlantu ( double date, double elong, double phi, const double u[13],
+                 double *ra, double *dec, double *r, int *jstat );
+
+void palPm ( double r0, double d0, double pr, double pd,
+             double px, double rv, double ep0, double ep1,
+             double *r1, double *d1 );
+
+void palPolmo ( double elongm, double phim, double xp, double yp,
+                double *elong, double *phi, double *daz );
+
+void palPrebn ( double bep0, double bep1, double rmatp[3][3] );
+
+void palPrec ( double ep0, double ep1, double rmatp[3][3] );
+
+void palPrecl ( double ep0, double ep1, double rmatp[3][3] );
+
+void palPreces ( const char sys[3], double ep0, double ep1,
+                 double *ra, double *dc );
+
+void palPrenut ( double epoch, double date, double rmatpn[3][3] );
+
+void palPv2el ( const double pv[6], double date, double pmass, int jformr,
+                int *jform, double *epoch, double *orbinc,
+                double *anode, double *perih, double *aorq, double *e,
+                double *aorl, double *dm, int *jstat );
+
+void palPv2ue ( const double pv[6], double date, double pmass,
+                double u[13], int *jstat );
+
+void palPvobs ( double p, double h, double stl, double pv[6] );
+
+void palPxy ( int np, double xye[][2], double xym[][2],
+              double coeffs[6],
+              double xyp[][2], double *xrms, double *yrms, double *rrms );
+
+float palRange ( float angle );
+
+float palRanorm ( float angle );
+
+double palRcc ( double tdb, double ut1, double wl, double u, double v );
+
+void palRdplan ( double date, int np, double elong, double phi,
+                 double *ra, double *dec, double *diam );
+
+void palRefco ( double hm, double tdk, double pmb, double rh,
+                double wl, double phi, double tlr, double eps,
+                double *refa, double *refb );
+
+void palRefcoq ( double tdk, double pmb, double rh, double wl,
+                double *refa, double *refb );
+
+void palRefro ( double zobs, double hm, double tdk, double pmb,
+                double rh, double wl, double phi, double tlr, double eps,
+                double *ref );
+
+void palRefv ( double vu[3], double refa, double refb, double vr[3] );
+
+void palRefz ( double zu, double refa, double refb, double *zr );
+
+double palRverot ( double phi, double ra, double da, double st );
+
+double palRvgalc ( double r2000, double d2000 );
+
+double palRvlg ( double r2000, double d2000 );
+
+double palRvlsrd ( double r2000, double d2000 );
+
+double palRvlsrk ( double r2000, double d2000 );
+
+void palS2tp ( float ra, float dec, float raz, float decz,
+               float *xi, float *eta, int *j );
+
+float palSep ( float a1, float b1, float a2, float b2 );
+
+float palSepv ( float v1[3], float v2[3] );
+
+void palSmat ( int n, float *a, float *y, float *d, int *jf, int *iw );
+
+void palSubet ( double rc, double dc, double eq,
+                double *rm, double *dm );
+
+void palSupgal ( double dsl, double dsb, double *dl, double *db );
+
+void palSvd ( int m, int n, int mp, int np,
+              double *a, double *w, double *v, double *work,
+              int *jstat );
+
+void palSvdcov ( int n, int np, int nc,
+                 double *w, double *v, double *work, double *cvm );
+
+void palSvdsol ( int m, int n, int mp, int np,
+                 double *b, double *u, double *w, double *v,
+                 double *work, double *x );
+
+void palTp2s ( float xi, float eta, float raz, float decz,
+               float *ra, float *dec );
+
+void palTp2v ( float xi, float eta, float v0[3], float v[3] );
+
+void palTps2c ( float xi, float eta, float ra, float dec,
+                float *raz1, float *decz1,
+                float *raz2, float *decz2, int *n );
+
+void palTpv2c ( float xi, float eta, float v[3],
+                float v01[3], float v02[3], int *n );
+
+void palUe2el ( const double u[13], int jformr,
+                int *jform, double *epoch, double *orbinc,
+                double *anode, double *perih, double *aorq, double *e,
+                double *aorl, double *dm, int *jstat );
+
+void palUe2pv ( double date, double u[13], double pv[], int *jstat );
+
+void palUnpcd ( double disco, double *x, double *y );
+
+void palV2tp ( float v[3], float v0[3], float *xi, float *eta, int *j );
+
+float palVdv ( float va[3], float vb[3] );
+
+int palVers ( char * verstring, size_t verlen );
+
+void palVn ( float v[3], float uv[3], float *vm );
+
+void palVxv ( float va[3], float vb[3], float vc[3] );
+
+void palXy2xy ( double x1, double y1, double coeffs[6],
+                double *x2, double *y2 );
+
+double palZd ( double ha, double dec, double phi );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
Index: trunk/FACT++/pal/pal.news
===================================================================
--- trunk/FACT++/pal/pal.news	(revision 18347)
+++ trunk/FACT++/pal/pal.news	(revision 18347)
@@ -0,0 +1,134 @@
+PAL Library
+
+The Starlink Positional Astronomy Library (PAL) is a C implementation of the
+SLALIB API. It is distributed under the GPL and uses the SOFA library wherever
+possible.
+
+V0.9.3
+
+- Fix value of small in palFk524. Typo in port from Fortran
+  had removed the "e" in the number. Thanks to @danielsf.
+
+- Add test for palFk524
+
+V0.9.2
+
+Thanks to Github user @nega0 for some BSD build fixes.
+
+More STARCONF_DEFAULT_PREFIX fixes for Scons file and for
+document building.
+
+New configure option: --with-erfa to allow the ERFA
+root location to be specified.
+
+V0.9.1
+
+Now checks for STARCONF_DEFAULT_PREFIX environment variable
+when deciding whether a Starlink environment is present. This
+was more reliable than checking for STARLINK_DIR.
+
+V0.9.0
+
+Add palPcd and palUnpcd
+
+V0.8.0
+
+Add palEcleq
+
+V0.7.0
+
+Add palPolmo.
+
+V0.6.0
+
+New function, palVers, provides API access to the PAL
+version number as a string or integer.
+
+V0.5.1
+
+The configure script was getting confused if run outside of
+Starlink without using --without-starlink. This was because
+$STARLINK is set in the script if it is not set and the
+configure script was assuming $STARLINK would be unset
+outside of a Starlink environment. The configure script
+now keys off $STARLINK_DIR but that may interact badly
+if STARLINK_DIR is set and --without-starlink is used.
+
+An experimental SConstruct build script is now available
+for users of scons.
+
+SUN/267 has been synced up with the associated source files.
+
+palIntin now respects the isblank configure check (as it
+should have done all along).
+
+Minor clean ups of some source prologues.
+
+V0.5.0
+
+Now works with ERFA <https://github.com/liberfa/erfa>.
+The configure script has been modified to first check
+for ERFA and then check for SOFA.
+
+V0.4.0
+
+New routines ported from SLA: palRefv, palAtmdsp
+New routine inherited from SOFA: palRefcoq
+
+Minimum SOFA version now 2013-12-02
+
+palObs: Now includes telescope positions for APEX and NANTEN2
+
+The autotools build scripts now require autoconf version 2.69.
+
+Thanks to Github user @nega0 for some BSD build fixes.
+
+A subset of the routines have been relicensed using LGPL
+to allow them to be included in the AST library. Thanks to
+Patrick Wallace for giving this permission.
+
+A paper on PAL has been published at ADASS:
+  http://adsabs.harvard.edu/abs/2013ASPC..475..307J
+
+V0.3.0
+
+Add refraction code and support palOap and palAop. For closer compatibility
+with SLA for testing purposes the refraction routines internally use
+clones of slaNutc, slaEqeqx, slaGmst and slaGeoc. Once the code has
+been verified further the PAL/SOFA routines will be used instead. Switching
+routines seems to change the results in palTest by about 0.05 arcsec.
+
+V0.2.0
+
+Improve configure script when not in a Starlink build environment. Use
+
+  ./configure --prefix=/path/to/install
+
+when Starlink is not available and add --without-starlink if Starlink
+is present but should not be used.
+
+V0.1.5
+
+Explcitly look for libm rather than relying on SOFA to pull it in.
+
+V0.1.4
+
+Check for isblank() function and fall back if it is missing.
+
+V0.1.3
+
+Improve copysign() detection.
+
+V0.1.2
+
+Check for copysign() c99 function and fall back if it is missing.
+
+V0.1.1
+
+The palDrange function has been modified so that it now returns +PI if
+the supplied angle is +PI (previously, it returned -PI in these cases).
+
+
+V0.1.0
+
+Initial release with sufficient SLALIB API for AST and the Astro::Coords perl module.
Index: trunk/FACT++/pal/pal1.h
===================================================================
--- trunk/FACT++/pal/pal1.h	(revision 18347)
+++ trunk/FACT++/pal/pal1.h	(revision 18347)
@@ -0,0 +1,68 @@
+/*
+*+
+*  Name:
+*     pal1.h
+
+*  Purpose:
+*     Definitions of private PAL functions
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Include file
+
+*  Invocation:
+*     #include "pal1.h"
+
+*  Description:
+*     Function prototypes for private PAL functions. Will not be
+*     installed.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#ifndef PAL1HDEF
+#define PAL1HDEF
+
+void pal1Atms ( double rt, double tt, double dnt, double gamal,
+                double r, double * dn, double * rdndr );
+
+void pal1Atmt ( double r0, double t0, double alpha, double gamm2,
+                double delm2, double c1, double c2, double c3, double c4,
+                double c5, double c6, double r,
+                double *t, double *dn, double *rdndr );
+
+#endif
Index: trunk/FACT++/pal/pal1Atms.c
===================================================================
--- trunk/FACT++/pal/pal1Atms.c	(revision 18347)
+++ trunk/FACT++/pal/pal1Atms.c	(revision 18347)
@@ -0,0 +1,95 @@
+/*
+*+
+*  Name:
+*     pal1Atms
+
+*  Purpose:
+*     Calculate stratosphere parameters
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void pal1Atms ( double rt, double tt, double dnt, double gamal,
+*                     double r, double * dn, double * rdndr );
+
+*  Arguments:
+*     rt = double (Given)
+*         Height of the tropopause from centre of the Earth (metre)
+*     tt = double (Given)
+*         Temperature at the tropopause (K)
+*     dnt = double (Given)
+*         Refractive index at the tropopause
+*     gamal = double (Given)
+*         Constant of the atmospheric model = G*MD/R
+*     r = double (Given)
+*         Current distance from the centre of the Earth (metre)
+*     dn = double * (Returned)
+*         Refractive index at r
+*     rdndr = double * (Returned)
+*         r * rate the refractive index is changing at r
+
+*  Description:
+*     Refractive index and derivative with respect to height for the
+*     stratosphere.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Internal routine used by palRefro.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal1.h"
+
+void pal1Atms ( double rt, double tt, double dnt, double gamal,
+                double r, double * dn, double * rdndr ) {
+
+  double b;
+  double w;
+
+  b = gamal / tt;
+  w = (dnt - 1.0) * exp( -b * (r-rt) );
+  *dn = 1.0 + w;
+  *rdndr = -r * b * w;
+
+}
+
Index: trunk/FACT++/pal/pal1Atmt.c
===================================================================
--- trunk/FACT++/pal/pal1Atmt.c	(revision 18347)
+++ trunk/FACT++/pal/pal1Atmt.c	(revision 18347)
@@ -0,0 +1,119 @@
+/*
+*+
+*  Name:
+*     pal1Atmt
+
+*  Purpose:
+*     Calculate troposphere parameters
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void pal1Atmt ( double r0, double t0, double alpha, double gamm2,
+*                     double delm2, double c1, double c2, double c3,
+*                     double c4, double c5, double c6, double r,
+*                     double *t, double *dn, double *rdndr );
+
+*  Arguments:
+*     r0 = double (Given)
+*         Height of observer from centre of the Earth (metre)
+*     t0 = double (Given)
+*         Temperature of the observer (K)
+*     alpha = double (Given)
+*         Alpha (see HMNAO paper)
+*     gamm2 = double (Given)
+*         Gamma minus 2 (see HMNAO paper)
+*     delm2 = double (Given)
+*         Delta minus 2 (see HMNAO paper)
+*     c1 = double (Given)
+*         Useful term (see palRefro source)
+*     c2 = double (Given)
+*         Useful term (see palRefro source)
+*     c3 = double (Given)
+*         Useful term (see palRefro source)
+*     c4 = double (Given)
+*         Useful term (see palRefro source)
+*     c5 = double (Given)
+*         Useful term (see palRefro source)
+*     c6 = double (Given)
+*         Useful term (see palRefro source)
+*     r = double (Given)
+*         Current distance from the centre of the Earth (metre)
+*     t = double * (Returned)
+*         Temperature at r (K)
+*     dn = double * (Returned)
+*         Refractive index at r.
+*     rdndr = double * (Returned)
+*         r * rate the refractive index is changing at r.
+
+*  Description:
+*     Refractive index and derivative with respect to height for
+*     the troposphere.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Internal routine used by palRefro
+*     - Note that in the optical case c5 and c6 are zero.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version, copied from Fortran SLA source.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "palmac.h"
+#include "pal1.h"
+
+void pal1Atmt ( double r0, double t0, double alpha, double gamm2,
+                double delm2, double c1, double c2, double c3, double c4,
+                double c5, double c6, double r,
+                double *t, double *dn, double *rdndr ) {
+
+  double tt0;
+  double tt0gm2;
+  double tt0dm2;
+
+  *t = DMAX( DMIN( t0 - alpha*(r-r0), 320.0), 100.0 );
+  tt0 = *t / t0;
+  tt0gm2 = pow( tt0, gamm2 );
+  tt0dm2 = pow( tt0, delm2 );
+  *dn = 1.0 + ( c1 * tt0gm2 - ( c2 - c5 / *t ) * tt0dm2 ) * tt0;
+  *rdndr = r * ( -c3 * tt0gm2 + ( c4 - c6 / tt0 ) * tt0dm2 );
+
+}
Index: trunk/FACT++/pal/pal1sofa.h
===================================================================
--- trunk/FACT++/pal/pal1sofa.h	(revision 18347)
+++ trunk/FACT++/pal/pal1sofa.h	(revision 18347)
@@ -0,0 +1,142 @@
+/*
+*+
+*  Name:
+*     pal1sofa.h
+
+*  Purpose:
+*     Mappings of ERFA names to SOFA names
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Include file
+
+*  Invocation:
+*     #include "pal1sofa.h"
+
+*  Description:
+*     PAL will work with both SOFA and ERFA libraries and the
+*     difference is generally a change in prefix. This include
+*     file maps the ERFA form of functions to the SOFA form
+*     and includes the relevant sofa.h vs erfa.h file.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - PAL uses the ERFA form by default.
+
+*  History:
+*     2014-07-29 (TIMJ):
+*        Initial version
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2014 Tim Jenness
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#ifndef PAL1SOFAHDEF
+#define PAL1SOFAHDEF
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+# if HAVE_SOFA_H
+
+#  include "sofa.h"
+#  include "sofam.h"
+
+   /* Must replace ERFA with SOFA */
+
+#  define eraA2af iauA2af
+#  define eraA2tf iauA2tf
+#  define eraAf2a iauAf2a
+#  define eraAnp iauAnp
+#  define eraAnpm iauAnpm
+#  define eraC2s iauC2s
+#  define eraCal2jd iauCal2jd
+#  define eraD2tf iauD2tf
+#  define eraDat iauDat
+#  define eraEe06a iauEe06a
+#  define eraEpb iauEpb
+#  define eraEpb2jd iauEpb2jd
+#  define eraEpj iauEpj
+#  define eraEpj2jd iauEpj2jd
+#  define eraEpv00 iauEpv00
+#  define eraFk5hz iauFk5hz
+#  define eraGd2gc iauGd2gc
+#  define eraGmst06 iauGmst06
+#  define eraHfk5z iauHfk5z
+#  define eraIr iauIr
+#  define eraJd2cal iauJd2cal
+#  define eraNut06a iauNut06a
+#  define eraObl06 iauObl06
+#  define eraP06e iauP06e
+#  define eraPap iauPap
+#  define eraPas iauPas
+#  define eraPdp iauPdp
+#  define eraPlan94 iauPlan94
+#  define eraPmat06 iauPmat06
+#  define eraPn iauPn
+#  define eraPnm06a iauPnm06a
+#  define eraPxp iauPxp
+#  define eraRefco iauRefco
+#  define eraRm2v iauRm2v
+#  define eraRv2m iauRv2m
+#  define eraRx iauRx
+#  define eraRxp iauRxp
+#  define eraRxpv iauRxpv
+#  define eraRxr iauRxr
+#  define eraRy iauRy
+#  define eraRz iauRz
+#  define eraS2c iauS2c
+#  define eraSepp iauSepp
+#  define eraSeps iauSeps
+#  define eraStarpm iauStarpm
+#  define eraTf2a iauTf2a
+#  define eraTf2d iauTf2d
+#  define eraTr iauTr
+#  define eraTrxp iauTrxp
+
+/* These are from sofam.h */
+
+#  define ERFA_WGS84 WGS84
+
+#  define ERFA_DJ00 DJ00
+#  define ERFA_DJY DJY
+#  define ERFA_DAU DAU
+
+# else
+
+#  include "erfa.h"
+#  include "erfam.h"
+
+/* No further action required */
+
+# endif
+
+#endif
Index: trunk/FACT++/pal/palAddet.c
===================================================================
--- trunk/FACT++/pal/palAddet.c	(revision 18347)
+++ trunk/FACT++/pal/palAddet.c	(revision 18347)
@@ -0,0 +1,112 @@
+/*
+*+
+*  Name:
+*     palAddet
+
+*  Purpose:
+*     Add the E-terms to a pre IAU 1976 mean place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAddet ( double rm, double dm, double eq,
+*                     double *rc, double *dc );
+
+*  Arguments:
+*     rm = double (Given)
+*        RA without E-terms (radians)
+*     dm = double (Given)
+*        Dec without E-terms (radians)
+*     eq = double (Given)
+*        Besselian epoch of mean equator and equinox
+*     rc = double * (Returned)
+*        RA with E-terms included (radians)
+*     dc = double * (Returned)
+*        Dec with E-terms included (radians)
+
+*  Description:
+*     Add the E-terms (elliptic component of annual aberration)
+*     to a pre IAU 1976 mean place to conform to the old
+*     catalogue convention.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     Most star positions from pre-1984 optical catalogues (or
+*     derived from astrometry using such stars) embody the
+*     E-terms.  If it is necessary to convert a formal mean
+*     place (for example a pulsar timing position) to one
+*     consistent with such a star catalogue, then the RA,Dec
+*     should be adjusted using this routine.
+
+*  See Also:
+*     Explanatory Supplement to the Astronomical Ephemeris,
+*     section 2D, page 48.
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palAddet ( double rm, double dm, double eq, double *rc, double *dc ) {
+  double a[3];   /* The E-terms */
+  double v[3];
+  int i;
+
+  /* Note the preference for IAU routines */
+
+  /* Retrieve the E-terms */
+  palEtrms( eq, a );
+
+  /* Spherical to Cartesian */
+  eraS2c( rm, dm, v );
+
+  /* Include the E-terms */
+  for (i=0; i<3; i++) {
+    v[i] += a[i];
+  }
+
+  /* Cartesian to spherical */
+  eraC2s( v, rc, dc );
+
+  /* Bring RA into conventional range */
+  *rc = eraAnp( *rc );
+
+}
Index: trunk/FACT++/pal/palAirmas.c
===================================================================
--- trunk/FACT++/pal/palAirmas.c	(revision 18347)
+++ trunk/FACT++/pal/palAirmas.c	(revision 18347)
@@ -0,0 +1,99 @@
+/*
+*+
+*  Name:
+*     palAirmas
+
+*  Purpose:
+*     Air mass at given zenith distance
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palAirmas( double zd );
+
+*  Arguments:
+*     zd = double (Given)
+*        Observed zenith distance (radians)
+
+*  Description:
+*     Calculates the airmass at the observed zenith distance.
+
+*  Authors:
+*     PTW: Patrick Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The "observed" zenith distance referred to above means "as
+*       affected by refraction".
+*     - Uses Hardie's (1962) polynomial fit to Bemporad's data for
+*       the relative air mass, X, in units of thickness at the zenith
+*       as tabulated by Schoenberg (1929). This is adequate for all
+*       normal needs as it is accurate to better than 0.1% up to X =
+*       6.8 and better than 1% up to X = 10. Bemporad's tabulated
+*       values are unlikely to be trustworthy to such accuracy
+*       because of variations in density, pressure and other
+*       conditions in the atmosphere from those assumed in his work.
+*     - The sign of the ZD is ignored.
+*     - At zenith distances greater than about ZD = 87 degrees the
+*       air mass is held constant to avoid arithmetic overflows.
+
+*  See Also:
+*     - Hardie, R.H., 1962, in "Astronomical Techniques"
+*         ed. W.A. Hiltner, University of Chicago Press, p180.
+*     - Schoenberg, E., 1929, Hdb. d. Ap.,
+*         Berlin, Julius Springer, 2, 268.
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version from the SLA/F version including documentation.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory.
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+
+double palAirmas ( double zd ) {
+  double seczm1;
+  double airmass;
+
+  /* Have maximum zenith distance of 87 deg */
+  const double MAXZD = 87.0 * PAL__DD2R;
+
+  zd = fabs(zd);
+  zd = ( zd > MAXZD ? MAXZD : zd );
+
+  seczm1 = (1.0 / cos(zd)) - 1.0;
+  airmass = 1.0 + seczm1*(0.9981833 - seczm1*(0.002875 + 0.0008083*seczm1));
+  return airmass;
+}
Index: trunk/FACT++/pal/palAltaz.c
===================================================================
--- trunk/FACT++/pal/palAltaz.c	(revision 18347)
+++ trunk/FACT++/pal/palAltaz.c	(revision 18347)
@@ -0,0 +1,200 @@
+/*
+*+
+*  Name:
+*     palAltaz
+
+*  Purpose:
+*     Positions, velocities and accelerations for an altazimuth telescope mount
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palAltaz ( double ha, double dec, double phi,
+*                double *az, double *azd, double *azdd,
+*                double *el, double *eld, double *eldd,
+*                double *pa, double *pad, double *padd );
+
+*  Arguments:
+*     ha = double (Given)
+*        Hour angle (radians)
+*     dec = double (Given)
+*        Declination (radians)
+*     phi = double (Given)
+*        Observatory latitude (radians)
+*     az = double * (Returned)
+*        Azimuth (radians)
+*     azd = double * (Returned)
+*        Azimuth velocity (radians per radian of HA)
+*     azdd = double * (Returned)
+*        Azimuth acceleration (radians per radian of HA squared)
+*     el = double * (Returned)
+*        Elevation (radians)
+*     eld = double * (Returned)
+*        Elevation velocity (radians per radian of HA)
+*     eldd = double * (Returned)
+*        Elevation acceleration (radians per radian of HA squared)
+*     pa = double * (Returned)
+*        Parallactic angle (radians)
+*     pad = double * (Returned)
+*        Parallactic angle velocity (radians per radian of HA)
+*     padd = double * (Returned)
+*        Parallactic angle acceleration (radians per radian of HA squared)
+
+
+*  Description:
+*     Positions, velocities and accelerations for an altazimuth
+*     telescope mount.
+
+*  Authors:
+*     PTW: P. T. Wallace
+*     TIMJ: Tim Jenness (Cornell)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Natural units are used throughout.  HA, DEC, PHI, AZ, EL
+*       and ZD are in radians.  The velocities and accelerations
+*       assume constant declination and constant rate of change of
+*       hour angle (as for tracking a star);  the units of AZD, ELD
+*       and PAD are radians per radian of HA, while the units of AZDD,
+*       ELDD and PADD are radians per radian of HA squared.  To
+*       convert into practical degree- and second-based units:
+*
+*         angles * 360/2pi -> degrees
+*         velocities * (2pi/86400)*(360/2pi) -> degree/sec
+*         accelerations * ((2pi/86400)**2)*(360/2pi) -> degree/sec/sec
+*
+*       Note that the seconds here are sidereal rather than SI.  One
+*       sidereal second is about 0.99727 SI seconds.
+*
+*       The velocity and acceleration factors assume the sidereal
+*       tracking case.  Their respective numerical values are (exactly)
+*       1/240 and (approximately) 1/3300236.9.
+*
+*     - Azimuth is returned in the range 0-2pi;  north is zero,
+*       and east is +pi/2.  Elevation and parallactic angle are
+*       returned in the range +/-pi.  Parallactic angle is +ve for
+*       a star west of the meridian and is the angle NP-star-zenith.
+*
+*     - The latitude is geodetic as opposed to geocentric.  The
+*       hour angle and declination are topocentric.  Refraction and
+*       deficiencies in the telescope mounting are ignored.  The
+*       purpose of the routine is to give the general form of the
+*       quantities.  The details of a real telescope could profoundly
+*       change the results, especially close to the zenith.
+*
+*     - No range checking of arguments is carried out.
+*
+*     - In applications which involve many such calculations, rather
+*       than calling the present routine it will be more efficient to
+*       use inline code, having previously computed fixed terms such
+*       as sine and cosine of latitude, and (for tracking a star)
+*       sine and cosine of declination.
+
+*  History:
+*     2014-09-30 (TIMJ):
+*        Initial version. Ported from Fortran SLA
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 P.T. Wallace
+*     Copyright (C) 2014 Cornell University
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void
+palAltaz ( double ha, double dec, double phi,
+           double *az, double *azd, double *azdd,
+           double *el, double *eld, double *eldd,
+           double *pa, double *pad, double *padd ) {
+
+  const double TINY = 1E-30;
+
+  double sh,ch,sd,cd,sp,cp,chcd,sdcp,x,y,z,rsq,r,a,e,c,s,
+    q,qd,ad,ed,edr,add,edd,qdd;
+
+
+  /*  Useful functions */
+  sh=sin(ha);
+  ch=cos(ha);
+  sd=sin(dec);
+  cd=cos(dec);
+  sp=sin(phi);
+  cp=cos(phi);
+  chcd=ch*cd;
+  sdcp=sd*cp;
+  x=-chcd*sp+sdcp;
+  y=-sh*cd;
+  z=chcd*cp+sd*sp;
+  rsq=x*x+y*y;
+  r=sqrt(rsq);
+
+  /*  Azimuth and elevation */
+  if (rsq == 0.0) {
+    a=0.0;
+  } else {
+    a=atan2(y,x);
+  }
+  if (a < 0.0) a += PAL__D2PI;
+  e=atan2(z,r);
+
+  /*  Parallactic angle */
+  c=cd*sp-ch*sdcp;
+  s=sh*cp;
+  if (c*c+s*s > 0) {
+    q=atan2(s,c);
+  } else {
+    q= PAL__DPI - ha;
+  }
+
+  /*  Velocities and accelerations (clamped at zenith/nadir) */
+  if (rsq < TINY) {
+    rsq=TINY;
+    r=sqrt(rsq);
+  }
+  qd=-x*cp/rsq;
+  ad=sp+z*qd;
+  ed=cp*y/r;
+  edr=ed/r;
+  add=edr*(z*sp+(2.0-rsq)*qd);
+  edd=-r*qd*ad;
+  qdd=edr*(sp+2.0*z*qd);
+
+  /*  Results */
+  *az=a;
+  *azd=ad;
+  *azdd=add;
+  *el=e;
+  *eld=ed;
+  *eldd=edd;
+  *pa=q;
+  *pad=qd;
+  *padd=qdd;
+
+}
Index: trunk/FACT++/pal/palAmp.c
===================================================================
--- trunk/FACT++/pal/palAmp.c	(revision 18347)
+++ trunk/FACT++/pal/palAmp.c	(revision 18347)
@@ -0,0 +1,84 @@
+/*
+*+
+*  Name:
+*     palAmp
+
+*  Purpose:
+*     Convert star RA,Dec from geocentric apparaent to mean place.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*      void palAmp ( double ra, double da, double date, double eq,
+*                    double *rm, double *dm );
+
+*  Arguments:
+*     ra = double (Given)
+*        Apparent RA (radians)
+*     dec = double (Given)
+*        Apparent Dec (radians)
+*     date = double (Given)
+*        TDB for apparent place (JD-2400000.5)
+*     eq = double (Given)
+*        Equinox: Julian epoch of mean place.
+*     rm = double * (Returned)
+*        Mean RA (radians)
+*     dm = double * (Returned)
+*        Mean Dec (radians)
+
+*  Description:
+*     Convert star RA,Dec from geocentric apparent to mean place. The
+*     mean coordinate system is close to ICRS. See palAmpqk for details.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - See palMappa and palAmpqk for details.
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2001 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palAmp ( double ra, double da, double date, double eq,
+              double *rm, double *dm ) {
+  double amprms[21];
+  palMappa( eq, date, amprms );
+  palAmpqk( ra, da, amprms, rm, dm );
+}
Index: trunk/FACT++/pal/palAmpqk.c
===================================================================
--- trunk/FACT++/pal/palAmpqk.c	(revision 18347)
+++ trunk/FACT++/pal/palAmpqk.c	(revision 18347)
@@ -0,0 +1,128 @@
+/*
+*+
+*  Name:
+*     palAmpqk
+
+*  Purpose:
+*     Convert star RA,Dec from geocentric apparent to mean place.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAmpqk ( double ra, double da, double amprms[21],
+*                     double *rm, double *dm )
+
+*  Arguments:
+*     ra = double (Given)
+*        Apparent RA (radians).
+*     da = double (Given)
+*        Apparent Dec (radians).
+*     amprms = double[21] (Given)
+*        Star-independent mean-to-apparent parameters (see palMappa):
+*        (0)      time interval for proper motion (Julian years)
+*        (1-3)    barycentric position of the Earth (AU)
+*        (4-6)    not used
+*        (7)      not used
+*        (8-10)   abv: barycentric Earth velocity in units of c
+*        (11)     sqrt(1-v*v) where v=modulus(abv)
+*        (12-20)  precession/nutation (3,3) matrix
+*     rm = double (Returned)
+*        Mean RA (radians).
+*     dm = double (Returned)
+*        Mean Dec (radians).
+
+*  Description:
+*     Convert star RA,Dec from geocentric apparent to mean place. The "mean"
+*     coordinate system is in fact close to ICRS. Use of this function
+*     is appropriate when efficiency is important and where many star
+*     positions are all to be transformed for one epoch and equinox.  The
+*     star-independent parameters can be obtained by calling the palMappa
+*     function.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (PTW):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2000 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palAmpqk ( double ra, double da, double amprms[21], double *rm,
+                double *dm ){
+
+/* Local Variables: */
+   double ab1;                 /* sqrt(1-v*v) where v=modulus of Earth vel */
+   double abv[3];              /* Earth velocity wrt SSB (c, FK5) */
+   double p1[3], p2[3], p3[3]; /* work vectors */
+   double ab1p1, p1dv, p1dvp1, w;
+   int i, j;
+
+/* Unpack some of the parameters */
+   ab1  = amprms[11];
+   for( i = 0; i < 3; i++ ) {
+      abv[i] = amprms[i + 8];
+   }
+
+/* Apparent RA,Dec to Cartesian */
+   eraS2c( ra, da, p3 );
+
+/* Precession and nutation */
+   eraTrxp( (double(*)[3]) &amprms[12], p3, p2 );
+
+/* Aberration */
+   ab1p1 = ab1 + 1.0;
+   for( i = 0; i < 3; i++ ) {
+      p1[i] = p2[i];
+   }
+   for( j = 0; j < 2; j++ ) {
+      p1dv = eraPdp( p1, abv );
+      p1dvp1 = 1.0 + p1dv;
+      w = 1.0 + p1dv / ab1p1;
+      for( i = 0; i < 3; i++ ) {
+         p1[i] = ( p1dvp1 * p2[i] - w * abv[i] ) / ab1;
+      }
+      eraPn( p1, &w, p3 );
+      for( i = 0; i < 3; i++ ) {
+         p1[i] = p3[i];
+      }
+   }
+
+/* Mean RA,Dec */
+   eraC2s( p1, rm, dm );
+   *rm = eraAnp( *rm );
+}
Index: trunk/FACT++/pal/palAop.c
===================================================================
--- trunk/FACT++/pal/palAop.c	(revision 18347)
+++ trunk/FACT++/pal/palAop.c	(revision 18347)
@@ -0,0 +1,238 @@
+/*
+*+
+*  Name:
+*     palAop
+
+*  Purpose:
+*     Apparent to observed place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAop ( double rap, double dap, double date, double dut,
+*                   double elongm, double phim, double hm, double xp,
+*                   double yp, double tdk, double pmb, double rh,
+*                   double wl, double tlr,
+*                   double *aob, double *zob, double *hob,
+*                   double *dob, double *rob );
+
+*  Arguments:
+*     rap = double (Given)
+*        Geocentric apparent right ascension
+*     dap = double (Given)
+*        Geocentirc apparent declination
+*     date = double (Given)
+*        UTC date/time (Modified Julian Date, JD-2400000.5)
+*     dut = double (Given)
+*        delta UT: UT1-UTC (UTC seconds)
+*     elongm = double (Given)
+*        Mean longitude of the observer (radians, east +ve)
+*     phim = double (Given)
+*        Mean geodetic latitude of the observer (radians)
+*     hm = double (Given)
+*        Observer's height above sea level (metres)
+*     xp = double (Given)
+*        Polar motion x-coordinates (radians)
+*     yp = double (Given)
+*        Polar motion y-coordinates (radians)
+*     tdk = double (Given)
+*        Local ambient temperature (K; std=273.15)
+*     pmb = double (Given)
+*        Local atmospheric pressure (mb; std=1013.25)
+*     rh = double (Given)
+*        Local relative humidity (in the range 0.0-1.0)
+*     wl = double (Given)
+*        Effective wavelength (micron, e.g. 0.55)
+*     tlr = double (Given)
+*        Tropospheric laps rate (K/metre, e.g. 0.0065)
+*     aob = double * (Returned)
+*        Observed azimuth (radians: N=0; E=90)
+*     zob = double * (Returned)
+*        Observed zenith distance (radians)
+*     hob = double * (Returned)
+*        Observed Hour Angle (radians)
+*     dob = double * (Returned)
+*        Observed Declination (radians)
+*     rob = double * (Returned)
+*        Observed Right Ascension (radians)
+
+
+*  Description:
+*     Apparent to observed place for sources distant from the solar system.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - This routine returns zenith distance rather than elevation
+*       in order to reflect the fact that no allowance is made for
+*       depression of the horizon.
+*
+*     - The accuracy of the result is limited by the corrections for
+*       refraction.  Providing the meteorological parameters are
+*       known accurately and there are no gross local effects, the
+*       predicted apparent RA,Dec should be within about 0.1 arcsec
+*       for a zenith distance of less than 70 degrees.  Even at a
+*       topocentric zenith distance of 90 degrees, the accuracy in
+*       elevation should be better than 1 arcmin;  useful results
+*       are available for a further 3 degrees, beyond which the
+*       palRefro routine returns a fixed value of the refraction.
+*       The complementary routines palAop (or palAopqk) and palOap
+*       (or palOapqk) are self-consistent to better than 1 micro-
+*       arcsecond all over the celestial sphere.
+*
+*     - It is advisable to take great care with units, as even
+*       unlikely values of the input parameters are accepted and
+*       processed in accordance with the models used.
+*
+*     - "Apparent" place means the geocentric apparent right ascension
+*       and declination, which is obtained from a catalogue mean place
+*       by allowing for space motion, parallax, precession, nutation,
+*       annual aberration, and the Sun's gravitational lens effect.  For
+*       star positions in the FK5 system (i.e. J2000), these effects can
+*       be applied by means of the palMap etc routines.  Starting from
+*       other mean place systems, additional transformations will be
+*       needed;  for example, FK4 (i.e. B1950) mean places would first
+*       have to be converted to FK5, which can be done with the
+*       palFk425 etc routines.
+*
+*     - "Observed" Az,El means the position that would be seen by a
+*       perfect theodolite located at the observer.  This is obtained
+*       from the geocentric apparent RA,Dec by allowing for Earth
+*       orientation and diurnal aberration, rotating from equator
+*       to horizon coordinates, and then adjusting for refraction.
+*       The HA,Dec is obtained by rotating back into equatorial
+*       coordinates, using the geodetic latitude corrected for polar
+*       motion, and is the position that would be seen by a perfect
+*       equatorial located at the observer and with its polar axis
+*       aligned to the Earth's axis of rotation (n.b. not to the
+*       refracted pole).  Finally, the RA is obtained by subtracting
+*       the HA from the local apparent ST.
+*
+*     - To predict the required setting of a real telescope, the
+*       observed place produced by this routine would have to be
+*       adjusted for the tilt of the azimuth or polar axis of the
+*       mounting (with appropriate corrections for mount flexures),
+*       for non-perpendicularity between the mounting axes, for the
+*       position of the rotator axis and the pointing axis relative
+*       to it, for tube flexure, for gear and encoder errors, and
+*       finally for encoder zero points.  Some telescopes would, of
+*       course, exhibit other properties which would need to be
+*       accounted for at the appropriate point in the sequence.
+*
+*     - This routine takes time to execute, due mainly to the
+*       rigorous integration used to evaluate the refraction.
+*       For processing multiple stars for one location and time,
+*       call palAoppa once followed by one call per star to palAopqk.
+*       Where a range of times within a limited period of a few hours
+*       is involved, and the highest precision is not required, call
+*       palAoppa once, followed by a call to palAoppat each time the
+*       time changes, followed by one call per star to palAopqk.
+*
+*     - The DATE argument is UTC expressed as an MJD.  This is,
+*       strictly speaking, wrong, because of leap seconds.  However,
+*       as long as the delta UT and the UTC are consistent there
+*       are no difficulties, except during a leap second.  In this
+*       case, the start of the 61st second of the final minute should
+*       begin a new MJD day and the old pre-leap delta UT should
+*       continue to be used.  As the 61st second completes, the MJD
+*       should revert to the start of the day as, simultaneously,
+*       the delta UTC changes by one second to its post-leap new value.
+*
+*     - The delta UT (UT1-UTC) is tabulated in IERS circulars and
+*       elsewhere.  It increases by exactly one second at the end of
+*       each UTC leap second, introduced in order to keep delta UT
+*       within +/- 0.9 seconds.
+*
+*     - IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+*       The longitude required by the present routine is east-positive,
+*       in accordance with geographical convention (and right-handed).
+*       In particular, note that the longitudes returned by the
+*       palObs routine are west-positive, following astronomical
+*       usage, and must be reversed in sign before use in the present
+*       routine.
+*
+*     - The polar coordinates XP,YP can be obtained from IERS
+*       circulars and equivalent publications.  The maximum amplitude
+*       is about 0.3 arcseconds.  If XP,YP values are unavailable,
+*       use XP=YP=0.0.  See page B60 of the 1988 Astronomical Almanac
+*       for a definition of the two angles.
+*
+*     - The height above sea level of the observing station, HM,
+*       can be obtained from the Astronomical Almanac (Section J
+*       in the 1988 edition), or via the routine palObs.  If P,
+*       the pressure in millibars, is available, an adequate
+*       estimate of HM can be obtained from the expression
+*
+*             HM ~ -29.3*TSL*LOG(P/1013.25).
+*
+*       where TSL is the approximate sea-level air temperature in K
+*       (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+*       section 52).  Similarly, if the pressure P is not known,
+*       it can be estimated from the height of the observing
+*       station, HM, as follows:
+*
+*             P ~ 1013.25*EXP(-HM/(29.3*TSL)).
+*
+*       Note, however, that the refraction is nearly proportional to the
+*       pressure and that an accurate P value is important for precise
+*       work.
+*
+*     - The azimuths etc produced by the present routine are with
+*       respect to the celestial pole.  Corrections to the terrestrial
+*       pole can be computed using palPolmo.
+
+*  History:
+*     2012-08-25 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palAop ( double rap, double dap, double date, double dut,
+              double elongm, double phim, double hm, double xp,
+              double yp, double tdk, double pmb, double rh,
+              double wl, double tlr,
+              double *aob, double *zob, double *hob,
+              double *dob, double *rob ) {
+
+  double aoprms[14];
+
+  palAoppa(date,dut,elongm,phim,hm,xp,yp,tdk,pmb,rh,wl,tlr,
+           aoprms);
+  palAopqk(rap,dap,aoprms,aob,zob,hob,dob,rob);
+
+}
Index: trunk/FACT++/pal/palAoppa.c
===================================================================
--- trunk/FACT++/pal/palAoppa.c	(revision 18347)
+++ trunk/FACT++/pal/palAoppa.c	(revision 18347)
@@ -0,0 +1,963 @@
+/*
+*+
+*  Name:
+*     palAoppa
+
+*  Purpose:
+*     Precompute apparent to observed place parameters
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAoppa ( double date, double dut, double elongm, double phim,
+*                     double hm, double xp, double yp, double tdk, double pmb,
+*                     double rh, double wl, double tlr, double aoprms[14] );
+
+*  Arguments:
+*     date = double (Given)
+*        UTC date/time (modified Julian Date, JD-2400000.5)
+*     dut = double (Given)
+*        delta UT:  UT1-UTC (UTC seconds)
+*     elongm = double (Given)
+*        mean longitude of the observer (radians, east +ve)
+*     phim = double (Given)
+*        mean geodetic latitude of the observer (radians)
+*     hm = double (Given)
+*        observer's height above sea level (metres)
+*     xp = double (Given)
+*        polar motion x-coordinate (radians)
+*     yp = double (Given)
+*        polar motion y-coordinate (radians)
+*     tdk = double (Given)
+*        local ambient temperature (K; std=273.15)
+*     pmb = double (Given)
+*        local atmospheric pressure (mb; std=1013.25)
+*     rh = double (Given)
+*        local relative humidity (in the range 0.0-1.0)
+*     wl = double (Given)
+*        effective wavelength (micron, e.g. 0.55)
+*     tlr = double (Given)
+*        tropospheric lapse rate (K/metre, e.g. 0.0065)
+*     aoprms = double [14] (Returned)
+*        Star-independent apparent-to-observed parameters
+*
+*         (0)      geodetic latitude (radians)
+*         (1,2)    sine and cosine of geodetic latitude
+*         (3)      magnitude of diurnal aberration vector
+*         (4)      height (hm)
+*         (5)      ambient temperature (tdk)
+*         (6)      pressure (pmb)
+*         (7)      relative humidity (rh)
+*         (8)      wavelength (wl)
+*         (9)     lapse rate (tlr)
+*         (10,11)  refraction constants A and B (radians)
+*         (12)     longitude + eqn of equinoxes + sidereal DUT (radians)
+*         (13)     local apparent sidereal time (radians)
+
+*  Description:
+*     Precompute apparent to observed place parameters required by palAopqk
+*     and palOapqk.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - It is advisable to take great care with units, as even
+*       unlikely values of the input parameters are accepted and
+*       processed in accordance with the models used.
+*
+*     - The DATE argument is UTC expressed as an MJD.  This is,
+*       strictly speaking, improper, because of leap seconds.  However,
+*       as long as the delta UT and the UTC are consistent there
+*       are no difficulties, except during a leap second.  In this
+*       case, the start of the 61st second of the final minute should
+*       begin a new MJD day and the old pre-leap delta UT should
+*       continue to be used.  As the 61st second completes, the MJD
+*       should revert to the start of the day as, simultaneously,
+*       the delta UTC changes by one second to its post-leap new value.
+*
+*     - The delta UT (UT1-UTC) is tabulated in IERS circulars and
+*       elsewhere.  It increases by exactly one second at the end of
+*       each UTC leap second, introduced in order to keep delta UT
+*       within +/- 0.9 seconds.
+*
+*     - IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+*       The longitude required by the present routine is east-positive,
+*       in accordance with geographical convention (and right-handed).
+*       In particular, note that the longitudes returned by the
+*       palObs routine are west-positive, following astronomical
+*       usage, and must be reversed in sign before use in the present
+*       routine.
+*
+*     - The polar coordinates XP,YP can be obtained from IERS
+*       circulars and equivalent publications.  The maximum amplitude
+*       is about 0.3 arcseconds.  If XP,YP values are unavailable,
+*       use XP=YP=0.0.  See page B60 of the 1988 Astronomical Almanac
+*       for a definition of the two angles.
+*
+*     - The height above sea level of the observing station, HM,
+*       can be obtained from the Astronomical Almanac (Section J
+*       in the 1988 edition), or via the routine palObs.  If P,
+*       the pressure in millibars, is available, an adequate
+*       estimate of HM can be obtained from the expression
+*
+*             HM ~ -29.3*TSL*log(P/1013.25).
+*
+*       where TSL is the approximate sea-level air temperature in K
+*       (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+*       section 52).  Similarly, if the pressure P is not known,
+*       it can be estimated from the height of the observing
+*       station, HM, as follows:
+*
+*             P ~ 1013.25*exp(-HM/(29.3*TSL)).
+*
+*       Note, however, that the refraction is nearly proportional to the
+*       pressure and that an accurate P value is important for precise
+*       work.
+*
+*     - Repeated, computationally-expensive, calls to palAoppa for
+*       times that are very close together can be avoided by calling
+*       palAoppa just once and then using palAoppat for the subsequent
+*       times.  Fresh calls to palAoppa will be needed only when
+*       changes in the precession have grown to unacceptable levels or
+*       when anything affecting the refraction has changed.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version, ported directly from Fortran SLA.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "math.h"
+
+#include "pal.h"
+#include "palmac.h"
+
+/* These are local SLA implementations to aid in testing. Switch
+ * to native PAL implementations when tests are complete. */
+static void pal__Geoc( double p, double h, double *r, double * z );
+static void pal__Nutc ( double date, double * dpsi, double *deps, double * eps0 );
+static double pal__Eqeqx( double date );
+
+void palAoppa ( double date, double dut, double elongm, double phim,
+                double hm, double xp, double yp, double tdk, double pmb,
+                double rh, double wl, double tlr, double aoprms[14] ) {
+
+  /* Constants */
+  const double C = 173.14463331; /* Speed of light (AU per day) */
+  const double SOLSID = 1.0027379093; /* Ratio between solar and sidereal time */
+
+  /* Local variables */
+  double cphim,xt,yt,zt,xc,yc,zc,elong,phi,uau,vau;
+
+  /*  Observer's location corrected for polar motion */
+  cphim = cos(phim);
+  xt = cos(elongm)*cphim;
+  yt = sin(elongm)*cphim;
+  zt = sin(phim);
+  xc = xt-xp*zt;
+  yc = yt+yp*zt;
+  zc = xp*xt-yp*yt+zt;
+  if (xc == 0.0 && yc == 0.0) {
+    elong = 0.0;
+  } else {
+    elong = atan2(yc,xc);
+  }
+  phi = atan2(zc,sqrt(xc*xc+yc*yc));
+  aoprms[0] = phi;
+  aoprms[1] = sin(phi);
+  aoprms[2] = cos(phi);
+
+  /*  magnitude of the diurnal aberration vector */
+  pal__Geoc(phi,hm,&uau,&vau);
+  aoprms[3] = PAL__D2PI*uau*SOLSID/C;
+
+  /*  copy the refraction parameters and compute the a & b constants */
+  aoprms[4] = hm;
+  aoprms[5] = tdk;
+  aoprms[6] = pmb;
+  aoprms[7] = rh;
+  aoprms[8] = wl;
+  aoprms[9] = tlr;
+  palRefco(hm,tdk,pmb,rh,wl,phi,tlr,1e-10,
+           &aoprms[10],&aoprms[11]);
+
+  /*  longitude + equation of the equinoxes + sidereal equivalent of DUT
+   *  (ignoring change in equation of the equinoxes between UTC and TDB) */
+  aoprms[12] = elong+pal__Eqeqx(date)+dut*SOLSID*PAL__DS2R;
+
+  /*  sidereal time */
+  palAoppat(date,aoprms);
+
+}
+
+/* Private reimplementation of slaEqeqx for testing the algorithm */
+
+#include <math.h>
+
+static void pal__Geoc( double p, double h, double *r, double * z ) {
+  /*  earth equatorial radius (metres) */
+  const double A0=6378140.0;
+
+  /*  reference spheroid flattening factor and useful function */
+  const double f = 1.0/298.257;
+  double b;
+
+  /*  astronomical unit in metres */
+  const double AU = 1.49597870e11;
+
+  double sp,cp,c,s;
+
+  b = pow( 1.0-f, 2.0 );
+
+  /*  geodetic to geocentric conversion */
+  sp = sin(p);
+  cp = cos(p);
+  c = 1.0/sqrt(cp*cp+b*sp*sp);
+  s = b*c;
+  *r = (A0*c+h)*cp/AU;
+  *z = (A0*s+h)*sp/AU;
+
+}
+
+static double pal__Eqeqx( double date ) {
+
+  const double T2AS=1296000.0;
+
+  double pal_eqeqx;
+  double t, om, dpsi, deps, eps0;
+
+  /*  interval between basic epoch j2000.0 and current epoch (jc) */
+  t=(date-51544.5)/36525.0;
+
+  /*  longitude of the mean ascending node of the lunar orbit on the
+   *   ecliptic, measured from the mean equinox of date */
+  om=PAL__DAS2R*(450160.280+(-5.0*T2AS-482890.539
+                               +(7.455+0.008*t)*t)*t);
+
+  /*  nutation */
+  pal__Nutc(date,&dpsi,&deps,&eps0);
+
+  /*  equation of the equinoxes */
+  pal_eqeqx=dpsi*cos(eps0)+PAL__DAS2R*(0.00264*sin(om)+
+                                 0.000063*sin(om+om));
+
+  return pal_eqeqx;
+}
+
+#include "palmac.h"
+
+static void pal__Nutc ( double date, double * dpsi, double *deps, double * eps0 ) {
+
+  const double DJC = 36525.0;
+  const double DJM0 = 51544.5;
+  const double TURNAS = 1296000.0;
+
+  #define NTERMS 194
+
+  int j;
+  double t,el,elp,f,d,om,ve,ma,ju,sa,theta,c,s,dp,de;
+
+  int na[         194 ][9] = {
+    {            0 ,            0 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            0 ,           -2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            2 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,           -2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,           -1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            3 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,           -1 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,           -2 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            1 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            1 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            1 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            1 ,            0 ,            1 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            4 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -2 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            0 ,           -2 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            4 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            4 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,           -1 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            3 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            3 ,            0 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            4 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            4 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            3 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            0 ,            4 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,           -1 ,            0 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -1 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            1 ,            0 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            4 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,           -1 ,            0 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            0 ,           -2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            1 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            3 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,           -2 ,            4 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,           -1 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,           -1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            3 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            1 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            1 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            2 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,           -1 ,            0 ,            2 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,           -2 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            1 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            4 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,           -1 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,            1 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            2 ,           -1 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            2 ,           -2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            1 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,            4 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            2 ,           -2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            1 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            2 ,           -1 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,           -1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            4 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            1 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            2 ,            1 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            4 ,           -2 ,            2 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            1 ,            0 ,            0 ,           -1 ,            0 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            4 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            1 ,            0 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,            0 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            4 ,            0 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {           -1 ,            0 ,            0 ,            4 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            0 ,            2 ,            2 ,            1 ,            0 ,            0 ,            0 ,            0  },
+    {            2 ,            1 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            5 ,           -5 ,            5 ,           -3 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            2 ,            0  },
+    {            0 ,            0 ,            1 ,           -1 ,            1 ,            0 ,            0 ,           -1 ,            0  },
+    {            0 ,            0 ,           -1 ,            1 ,           -1 ,            1 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -1 ,            1 ,            0 ,            0 ,            2 ,            0 ,            0  },
+    {            0 ,            0 ,            3 ,           -3 ,            3 ,            0 ,            0 ,           -1 ,            0  },
+    {            0 ,            0 ,           -8 ,            8 ,           -7 ,            5 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -1 ,            1 ,           -1 ,            0 ,            2 ,            0 ,            0  },
+    {            0 ,            0 ,           -2 ,            2 ,           -2 ,            2 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -6 ,            6 ,           -6 ,            4 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -2 ,            2 ,           -2 ,            0 ,            8 ,           -3 ,            0  },
+    {            0 ,            0 ,            6 ,           -6 ,            6 ,            0 ,           -8 ,            3 ,            0  },
+    {            0 ,            0 ,            4 ,           -4 ,            4 ,           -2 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -3 ,            3 ,           -3 ,            2 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            4 ,           -4 ,            3 ,            0 ,           -8 ,            3 ,            0  },
+    {            0 ,            0 ,           -4 ,            4 ,           -5 ,            0 ,            8 ,           -3 ,            0  },
+    {            0 ,            0 ,            0 ,            0 ,            0 ,            2 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,           -4 ,            4 ,           -4 ,            3 ,            0 ,            0 ,            0  },
+    {            0 ,            1 ,           -1 ,            1 ,           -1 ,            0 ,            0 ,            1 ,            0  },
+    {            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            1 ,            0  },
+    {            0 ,            0 ,            1 ,           -1 ,            1 ,            1 ,            0 ,            0 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            2 ,            0 ,           -2 ,            0 ,            0  },
+    {            0 ,           -1 ,           -7 ,            7 ,           -7 ,            5 ,            0 ,            0 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,            2 ,            0 ,            0 ,           -2 ,            0  },
+    {           -2 ,            0 ,            2 ,            0 ,            1 ,            0 ,            0 ,           -3 ,            0  },
+    {            0 ,            0 ,            2 ,           -2 ,            2 ,            0 ,            0 ,           -2 ,            0  },
+    {            0 ,            0 ,            1 ,           -1 ,            1 ,            0 ,            0 ,            1 ,            0  },
+    {            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            2  },
+    {            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            0 ,            1  },
+    {            2 ,            0 ,           -2 ,            0 ,           -2 ,            0 ,            0 ,            3 ,            0  },
+    {            0 ,            0 ,            1 ,           -1 ,            1 ,            0 ,            0 ,           -2 ,            0  },
+    {            0 ,            0 ,           -7 ,            7 ,           -7 ,            5 ,            0 ,            0 ,            0  }
+  };
+  double psi[         194 ][4] = {
+    {    3341.5000000000000      ,    17206241.800000001      ,    3.1000000000000001      ,    17409.500000000000       },
+    {   -1716.8000000000000      ,   -1317185.3000000000      ,    1.3999999999999999      ,   -156.80000000000001       },
+    {    285.69999999999999      ,   -227667.00000000000      ,   0.29999999999999999      ,   -23.500000000000000       },
+    {   -68.599999999999994      ,   -207448.00000000000      ,    0.0000000000000000      ,   -21.399999999999999       },
+    {    950.29999999999995      ,    147607.89999999999      ,   -2.2999999999999998      ,   -355.00000000000000       },
+    {   -66.700000000000003      ,   -51689.099999999999      ,   0.20000000000000001      ,    122.59999999999999       },
+    {   -108.59999999999999      ,    71117.600000000006      ,    0.0000000000000000      ,    7.0000000000000000       },
+    {    35.600000000000001      ,   -38740.199999999997      ,   0.10000000000000001      ,   -36.200000000000003       },
+    {    85.400000000000006      ,   -30127.599999999999      ,    0.0000000000000000      ,   -3.1000000000000001       },
+    {    9.0000000000000000      ,    21583.000000000000      ,   0.10000000000000001      ,   -50.299999999999997       },
+    {    22.100000000000001      ,    12822.799999999999      ,    0.0000000000000000      ,    13.300000000000001       },
+    {    3.3999999999999999      ,    12350.799999999999      ,    0.0000000000000000      ,    1.3000000000000000       },
+    {   -21.100000000000001      ,    15699.400000000000      ,    0.0000000000000000      ,    1.6000000000000001       },
+    {    4.2000000000000002      ,    6313.8000000000002      ,    0.0000000000000000      ,    6.2000000000000002       },
+    {   -22.800000000000001      ,    5796.8999999999996      ,    0.0000000000000000      ,    6.0999999999999996       },
+    {    15.699999999999999      ,   -5961.1000000000004      ,    0.0000000000000000      ,  -0.59999999999999998       },
+    {    13.100000000000000      ,   -5159.1000000000004      ,    0.0000000000000000      ,   -4.5999999999999996       },
+    {    1.8000000000000000      ,    4592.6999999999998      ,    0.0000000000000000      ,    4.5000000000000000       },
+    {   -17.500000000000000      ,    6336.0000000000000      ,    0.0000000000000000      ,   0.69999999999999996       },
+    {    16.300000000000001      ,   -3851.0999999999999      ,    0.0000000000000000      ,  -0.40000000000000002       },
+    {   -2.7999999999999998      ,    4771.6999999999998      ,    0.0000000000000000      ,   0.50000000000000000       },
+    {    13.800000000000001      ,   -3099.3000000000002      ,    0.0000000000000000      ,  -0.29999999999999999       },
+    {   0.20000000000000001      ,    2860.3000000000002      ,    0.0000000000000000      ,   0.29999999999999999       },
+    {    1.3999999999999999      ,    2045.3000000000000      ,    0.0000000000000000      ,    2.0000000000000000       },
+    {   -8.5999999999999996      ,    2922.5999999999999      ,    0.0000000000000000      ,   0.29999999999999999       },
+    {   -7.7000000000000002      ,    2587.9000000000001      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {    8.8000000000000007      ,   -1408.0999999999999      ,    0.0000000000000000      ,    3.7000000000000002       },
+    {    1.3999999999999999      ,    1517.5000000000000      ,    0.0000000000000000      ,    1.5000000000000000       },
+    {   -1.8999999999999999      ,   -1579.7000000000000      ,    0.0000000000000000      ,    7.7000000000000002       },
+    {    1.3000000000000000      ,   -2178.5999999999999      ,    0.0000000000000000      ,  -0.20000000000000001       },
+    {   -4.7999999999999998      ,    1286.8000000000000      ,    0.0000000000000000      ,    1.3000000000000000       },
+    {    6.2999999999999998      ,    1267.2000000000000      ,    0.0000000000000000      ,   -4.0000000000000000       },
+    {   -1.0000000000000000      ,    1669.3000000000000      ,    0.0000000000000000      ,   -8.3000000000000007       },
+    {    2.3999999999999999      ,   -1020.0000000000000      ,    0.0000000000000000      ,  -0.90000000000000002       },
+    {    4.5000000000000000      ,   -766.89999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.1000000000000001      ,    756.50000000000000      ,    0.0000000000000000      ,   -1.7000000000000000       },
+    {   -1.3999999999999999      ,   -1097.3000000000000      ,    0.0000000000000000      ,  -0.50000000000000000       },
+    {    2.6000000000000001      ,   -663.00000000000000      ,    0.0000000000000000      ,  -0.59999999999999998       },
+    {   0.80000000000000004      ,   -714.10000000000002      ,    0.0000000000000000      ,    1.6000000000000001       },
+    {   0.40000000000000002      ,   -629.89999999999998      ,    0.0000000000000000      ,  -0.59999999999999998       },
+    {   0.29999999999999999      ,    580.39999999999998      ,    0.0000000000000000      ,   0.59999999999999998       },
+    {   -1.6000000000000001      ,    577.29999999999995      ,    0.0000000000000000      ,   0.50000000000000000       },
+    {  -0.90000000000000002      ,    644.39999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    2.2000000000000002      ,   -534.00000000000000      ,    0.0000000000000000      ,  -0.50000000000000000       },
+    {   -2.5000000000000000      ,    493.30000000000001      ,    0.0000000000000000      ,   0.50000000000000000       },
+    {  -0.10000000000000001      ,   -477.30000000000001      ,    0.0000000000000000      ,   -2.3999999999999999       },
+    {  -0.90000000000000002      ,    735.00000000000000      ,    0.0000000000000000      ,   -1.7000000000000000       },
+    {   0.69999999999999996      ,    406.19999999999999      ,    0.0000000000000000      ,   0.40000000000000002       },
+    {   -2.7999999999999998      ,    656.89999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.59999999999999998      ,    358.00000000000000      ,    0.0000000000000000      ,    2.0000000000000000       },
+    {  -0.69999999999999996      ,    472.50000000000000      ,    0.0000000000000000      ,   -1.1000000000000001       },
+    {  -0.10000000000000001      ,   -300.50000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.2000000000000000      ,    435.10000000000002      ,    0.0000000000000000      ,   -1.0000000000000000       },
+    {    1.8000000000000000      ,   -289.39999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.59999999999999998      ,   -422.60000000000002      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.80000000000000004      ,   -287.60000000000002      ,    0.0000000000000000      ,   0.59999999999999998       },
+    {   -38.600000000000001      ,   -392.30000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.69999999999999996      ,   -281.80000000000001      ,    0.0000000000000000      ,   0.59999999999999998       },
+    {   0.59999999999999998      ,   -405.69999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.2000000000000000      ,    229.00000000000000      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {    1.1000000000000001      ,   -264.30000000000001      ,    0.0000000000000000      ,   0.50000000000000000       },
+    {  -0.69999999999999996      ,    247.90000000000001      ,    0.0000000000000000      ,  -0.50000000000000000       },
+    {  -0.20000000000000001      ,    218.00000000000000      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {   0.59999999999999998      ,   -339.00000000000000      ,    0.0000000000000000      ,   0.80000000000000004       },
+    {  -0.69999999999999996      ,    198.69999999999999      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {   -1.5000000000000000      ,    334.00000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,    334.00000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,   -198.09999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -106.59999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.50000000000000000      ,    165.80000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    134.80000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.90000000000000002      ,   -151.59999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -129.69999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.80000000000000004      ,   -132.80000000000001      ,    0.0000000000000000      ,  -0.10000000000000001       },
+    {   0.50000000000000000      ,   -140.69999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    138.40000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    129.00000000000000      ,    0.0000000000000000      ,  -0.29999999999999999       },
+    {   0.50000000000000000      ,   -121.20000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.29999999999999999      ,    114.50000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    101.80000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -3.6000000000000001      ,   -101.90000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.80000000000000004      ,   -109.40000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.20000000000000001      ,   -97.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.69999999999999996      ,    157.30000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.20000000000000001      ,   -83.299999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.29999999999999999      ,    93.299999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    92.099999999999994      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.50000000000000000      ,    133.59999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    81.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    123.90000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.29999999999999999      ,    128.09999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,    74.099999999999994      ,    0.0000000000000000      ,  -0.29999999999999999       },
+    {  -0.20000000000000001      ,   -70.299999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.40000000000000002      ,    66.599999999999994      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -66.700000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.69999999999999996      ,    69.299999999999997      ,    0.0000000000000000      ,  -0.29999999999999999       },
+    {    0.0000000000000000      ,   -70.400000000000006      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    101.50000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.50000000000000000      ,   -69.099999999999994      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    58.500000000000000      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {   0.10000000000000001      ,   -94.900000000000006      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {    0.0000000000000000      ,    52.899999999999999      ,    0.0000000000000000      ,  -0.20000000000000001       },
+    {   0.10000000000000001      ,    86.700000000000003      ,    0.0000000000000000      ,  -0.20000000000000001       },
+    {  -0.10000000000000001      ,   -59.200000000000003      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {   0.29999999999999999      ,   -58.799999999999997      ,    0.0000000000000000      ,   0.10000000000000001       },
+    {  -0.29999999999999999      ,    49.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    56.899999999999999      ,    0.0000000000000000      ,  -0.10000000000000001       },
+    {   0.29999999999999999      ,   -50.200000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    53.399999999999999      ,    0.0000000000000000      ,  -0.10000000000000001       },
+    {   0.10000000000000001      ,   -76.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    45.299999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -46.799999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.20000000000000001      ,   -44.600000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.20000000000000001      ,   -48.700000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -46.799999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -42.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    46.399999999999999      ,    0.0000000000000000      ,  -0.10000000000000001       },
+    {   0.20000000000000001      ,   -67.299999999999997      ,    0.0000000000000000      ,   0.10000000000000001       },
+    {    0.0000000000000000      ,   -65.799999999999997      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {  -0.10000000000000001      ,   -43.899999999999999      ,    0.0000000000000000      ,   0.29999999999999999       },
+    {    0.0000000000000000      ,   -38.899999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.29999999999999999      ,    63.899999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    41.200000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -36.100000000000001      ,    0.0000000000000000      ,   0.20000000000000001       },
+    {  -0.29999999999999999      ,    58.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    36.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -39.700000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -57.700000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    33.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    36.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    55.700000000000003      ,    0.0000000000000000      ,  -0.10000000000000001       },
+    {   0.10000000000000001      ,   -35.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -31.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    30.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.29999999999999999      ,    49.200000000000003      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    49.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    33.600000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -33.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -31.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    28.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -25.199999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -26.199999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    41.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    24.500000000000000      ,    0.0000000000000000      ,   0.10000000000000001       },
+    {   -16.199999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -22.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    23.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    37.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.20000000000000001      ,   -25.699999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    25.199999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -24.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    24.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -20.699999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -20.800000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,    33.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    32.899999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -32.600000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    19.899999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.10000000000000001      ,    19.600000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -18.699999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -19.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.10000000000000001      ,   -28.600000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    4.0000000000000000      ,    178.80000000000001      ,   -11.800000000000001      ,   0.29999999999999999       },
+    {    39.799999999999997      ,   -107.30000000000000      ,   -5.5999999999999996      ,   -1.0000000000000000       },
+    {    9.9000000000000004      ,    164.00000000000000      ,   -4.0999999999999996      ,   0.10000000000000001       },
+    {   -4.7999999999999998      ,   -135.30000000000001      ,   -3.3999999999999999      ,  -0.10000000000000001       },
+    {    50.500000000000000      ,    75.000000000000000      ,    1.3999999999999999      ,   -1.2000000000000000       },
+    {   -1.1000000000000001      ,   -53.500000000000000      ,    1.3000000000000000      ,    0.0000000000000000       },
+    {   -45.000000000000000      ,   -2.3999999999999999      ,  -0.40000000000000002      ,    6.5999999999999996       },
+    {   -11.500000000000000      ,   -61.000000000000000      ,  -0.90000000000000002      ,   0.40000000000000002       },
+    {    4.4000000000000004      ,   -68.400000000000006      ,   -3.3999999999999999      ,    0.0000000000000000       },
+    {    7.7000000000000002      ,   -47.100000000000001      ,   -4.7000000000000002      ,   -1.0000000000000000       },
+    {   -42.899999999999999      ,   -12.600000000000000      ,   -1.2000000000000000      ,    4.2000000000000002       },
+    {   -42.799999999999997      ,    12.699999999999999      ,   -1.2000000000000000      ,   -4.2000000000000002       },
+    {   -7.5999999999999996      ,   -44.100000000000001      ,    2.1000000000000001      ,  -0.50000000000000000       },
+    {   -64.099999999999994      ,    1.7000000000000000      ,   0.20000000000000001      ,    4.5000000000000000       },
+    {    36.399999999999999      ,   -10.400000000000000      ,    1.0000000000000000      ,    3.5000000000000000       },
+    {    35.600000000000001      ,    10.199999999999999      ,    1.0000000000000000      ,   -3.5000000000000000       },
+    {   -1.7000000000000000      ,    39.500000000000000      ,    2.0000000000000000      ,    0.0000000000000000       },
+    {    50.899999999999999      ,   -8.1999999999999993      ,  -0.80000000000000004      ,   -5.0000000000000000       },
+    {    0.0000000000000000      ,    52.299999999999997      ,    1.2000000000000000      ,    0.0000000000000000       },
+    {   -42.899999999999999      ,   -17.800000000000001      ,   0.40000000000000002      ,    0.0000000000000000       },
+    {    2.6000000000000001      ,    34.299999999999997      ,   0.80000000000000004      ,    0.0000000000000000       },
+    {  -0.80000000000000004      ,   -48.600000000000001      ,    2.3999999999999999      ,  -0.10000000000000001       },
+    {   -4.9000000000000004      ,    30.500000000000000      ,    3.7000000000000002      ,   0.69999999999999996       },
+    {    0.0000000000000000      ,   -43.600000000000001      ,    2.1000000000000001      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -25.399999999999999      ,    1.2000000000000000      ,    0.0000000000000000       },
+    {    2.0000000000000000      ,    40.899999999999999      ,   -2.0000000000000000      ,    0.0000000000000000       },
+    {   -2.1000000000000001      ,    26.100000000000001      ,   0.59999999999999998      ,    0.0000000000000000       },
+    {    22.600000000000001      ,   -3.2000000000000002      ,  -0.50000000000000000      ,  -0.50000000000000000       },
+    {   -7.5999999999999996      ,    24.899999999999999      ,  -0.40000000000000002      ,  -0.20000000000000001       },
+    {   -6.2000000000000002      ,    34.899999999999999      ,    1.7000000000000000      ,   0.29999999999999999       },
+    {    2.0000000000000000      ,    17.399999999999999      ,  -0.40000000000000002      ,   0.10000000000000001       },
+    {   -3.8999999999999999      ,    20.500000000000000      ,    2.3999999999999999      ,   0.59999999999999998       }
+  };
+  double eps[         194 ][4] = {
+    {    9205365.8000000007      ,   -1506.2000000000000      ,    885.70000000000005      ,  -0.20000000000000001       },
+    {    573095.90000000002      ,   -570.20000000000005      ,   -305.00000000000000      ,  -0.29999999999999999       },
+    {    97845.500000000000      ,    147.80000000000001      ,   -48.799999999999997      ,  -0.20000000000000001       },
+    {   -89753.600000000006      ,    28.000000000000000      ,    46.899999999999999      ,    0.0000000000000000       },
+    {    7406.6999999999998      ,   -327.10000000000002      ,   -18.199999999999999      ,   0.80000000000000004       },
+    {    22442.299999999999      ,   -22.300000000000001      ,   -67.599999999999994      ,    0.0000000000000000       },
+    {   -683.60000000000002      ,    46.799999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    20070.700000000001      ,    36.000000000000000      ,    1.6000000000000001      ,    0.0000000000000000       },
+    {    12893.799999999999      ,    39.500000000000000      ,   -6.2000000000000002      ,    0.0000000000000000       },
+    {   -9593.2000000000007      ,    14.400000000000000      ,    30.199999999999999      ,  -0.10000000000000001       },
+    {   -6899.5000000000000      ,    4.7999999999999998      ,  -0.59999999999999998      ,    0.0000000000000000       },
+    {   -5332.5000000000000      ,  -0.10000000000000001      ,    2.7000000000000002      ,    0.0000000000000000       },
+    {   -125.20000000000000      ,    10.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -3323.4000000000001      ,  -0.90000000000000002      ,  -0.29999999999999999      ,    0.0000000000000000       },
+    {    3142.3000000000002      ,    8.9000000000000004      ,   0.29999999999999999      ,    0.0000000000000000       },
+    {    2552.5000000000000      ,    7.2999999999999998      ,   -1.2000000000000000      ,    0.0000000000000000       },
+    {    2634.4000000000001      ,    8.8000000000000007      ,   0.20000000000000001      ,    0.0000000000000000       },
+    {   -2424.4000000000001      ,    1.6000000000000001      ,  -0.40000000000000002      ,    0.0000000000000000       },
+    {   -123.30000000000000      ,    3.8999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    1642.4000000000001      ,    7.2999999999999998      ,  -0.80000000000000004      ,    0.0000000000000000       },
+    {    47.899999999999999      ,    3.2000000000000002      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    1321.2000000000000      ,    6.2000000000000002      ,  -0.59999999999999998      ,    0.0000000000000000       },
+    {   -1234.0999999999999      ,  -0.29999999999999999      ,   0.59999999999999998      ,    0.0000000000000000       },
+    {   -1076.5000000000000      ,  -0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -61.600000000000001      ,    1.8000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -55.399999999999999      ,    1.6000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    856.89999999999998      ,   -4.9000000000000004      ,   -2.1000000000000001      ,    0.0000000000000000       },
+    {   -800.70000000000005      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    685.10000000000002      ,  -0.59999999999999998      ,   -3.7999999999999998      ,    0.0000000000000000       },
+    {   -16.899999999999999      ,   -1.5000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    695.70000000000005      ,    1.8000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    642.20000000000005      ,   -2.6000000000000001      ,   -1.6000000000000001      ,    0.0000000000000000       },
+    {    13.300000000000001      ,    1.1000000000000001      ,  -0.10000000000000001      ,    0.0000000000000000       },
+    {    521.89999999999998      ,    1.6000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    325.80000000000001      ,    2.0000000000000000      ,  -0.10000000000000001      ,    0.0000000000000000       },
+    {   -325.10000000000002      ,  -0.50000000000000000      ,   0.90000000000000002      ,    0.0000000000000000       },
+    {    10.100000000000000      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    334.50000000000000      ,    1.6000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    307.10000000000002      ,   0.40000000000000002      ,  -0.90000000000000002      ,    0.0000000000000000       },
+    {    327.19999999999999      ,   0.50000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -304.60000000000002      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    304.00000000000000      ,   0.59999999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -276.80000000000001      ,  -0.50000000000000000      ,   0.10000000000000001      ,    0.0000000000000000       },
+    {    268.89999999999998      ,    1.3000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    271.80000000000001      ,    1.1000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    271.50000000000000      ,  -0.40000000000000002      ,  -0.80000000000000004      ,    0.0000000000000000       },
+    {   -5.2000000000000002      ,   0.50000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -220.50000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -20.100000000000001      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -191.00000000000000      ,   0.10000000000000001      ,   0.50000000000000000      ,    0.0000000000000000       },
+    {   -4.0999999999999996      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    130.59999999999999      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    3.0000000000000000      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    122.90000000000001      ,   0.80000000000000004      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    3.7000000000000002      ,  -0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    123.09999999999999      ,   0.40000000000000002      ,  -0.29999999999999999      ,    0.0000000000000000       },
+    {   -52.700000000000003      ,    15.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    120.70000000000000      ,   0.29999999999999999      ,  -0.29999999999999999      ,    0.0000000000000000       },
+    {    4.0000000000000000      ,  -0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    126.50000000000000      ,   0.50000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    112.70000000000000      ,   0.50000000000000000      ,  -0.29999999999999999      ,    0.0000000000000000       },
+    {   -106.09999999999999      ,  -0.29999999999999999      ,   0.29999999999999999      ,    0.0000000000000000       },
+    {   -112.90000000000001      ,  -0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    3.6000000000000001      ,  -0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    107.40000000000001      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -10.900000000000000      ,   0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.90000000000000002      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    85.400000000000006      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -88.799999999999997      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -71.000000000000000      ,  -0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -70.299999999999997      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    64.500000000000000      ,   0.40000000000000002      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    69.799999999999997      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    66.099999999999994      ,   0.40000000000000002      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -61.000000000000000      ,  -0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -59.500000000000000      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -55.600000000000001      ,    0.0000000000000000      ,   0.20000000000000001      ,    0.0000000000000000       },
+    {    51.700000000000003      ,   0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -49.000000000000000      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -52.700000000000003      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -49.600000000000001      ,    1.3999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    46.299999999999997      ,   0.40000000000000002      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    49.600000000000001      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -5.0999999999999996      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -44.000000000000000      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -39.899999999999999      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -39.500000000000000      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -3.8999999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -42.100000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -17.199999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -2.2999999999999998      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -39.200000000000003      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -38.399999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    36.799999999999997      ,   0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    34.600000000000001      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -32.700000000000003      ,   0.29999999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    30.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.40000000000000002      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    29.300000000000001      ,   0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    31.600000000000001      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.80000000000000004      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -27.899999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    2.8999999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -25.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    25.000000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    27.500000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -24.399999999999999      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    24.899999999999999      ,   0.20000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -22.800000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.90000000000000002      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    24.399999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    23.899999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    22.500000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    20.800000000000001      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    20.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    21.500000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -20.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    1.3999999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.20000000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    19.000000000000000      ,    0.0000000000000000      ,  -0.10000000000000001      ,    0.0000000000000000       },
+    {    20.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -2.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -17.600000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    19.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -2.3999999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -18.399999999999999      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    17.100000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.40000000000000002      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    18.399999999999999      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,    17.399999999999999      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.59999999999999998      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -15.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -16.800000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    16.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -2.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.5000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -14.300000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    14.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -13.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -14.300000000000001      ,  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -13.699999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    13.100000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.7000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -12.800000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   -14.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    12.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -12.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {  -0.80000000000000004      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    10.900000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -10.800000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    10.500000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -10.400000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -11.199999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    10.500000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -1.3999999999999999      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    0.0000000000000000      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.69999999999999996      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -10.300000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -10.000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    9.5999999999999996      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {    9.4000000000000004      ,   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.59999999999999998      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -87.700000000000003      ,    4.4000000000000004      ,  -0.40000000000000002      ,   -6.2999999999999998       },
+    {    46.299999999999997      ,    22.399999999999999      ,   0.50000000000000000      ,   -2.3999999999999999       },
+    {    15.600000000000000      ,   -3.3999999999999999      ,   0.10000000000000001      ,   0.40000000000000002       },
+    {    5.2000000000000002      ,    5.7999999999999998      ,   0.20000000000000001      ,  -0.10000000000000001       },
+    {   -30.100000000000001      ,    26.899999999999999      ,   0.69999999999999996      ,    0.0000000000000000       },
+    {    23.199999999999999      ,  -0.50000000000000000      ,    0.0000000000000000      ,   0.59999999999999998       },
+    {    1.0000000000000000      ,    23.199999999999999      ,    3.3999999999999999      ,    0.0000000000000000       },
+    {   -12.199999999999999      ,   -4.2999999999999998      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -2.1000000000000001      ,   -3.7000000000000002      ,  -0.20000000000000001      ,   0.10000000000000001       },
+    {   -18.600000000000001      ,   -3.7999999999999998      ,  -0.40000000000000002      ,    1.8000000000000000       },
+    {    5.5000000000000000      ,   -18.699999999999999      ,   -1.8000000000000000      ,  -0.50000000000000000       },
+    {   -5.5000000000000000      ,   -18.699999999999999      ,    1.8000000000000000      ,  -0.50000000000000000       },
+    {    18.399999999999999      ,   -3.6000000000000001      ,   0.29999999999999999      ,   0.90000000000000002       },
+    {  -0.59999999999999998      ,    1.3000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -5.5999999999999996      ,   -19.500000000000000      ,    1.8999999999999999      ,    0.0000000000000000       },
+    {    5.5000000000000000      ,   -19.100000000000001      ,   -1.8999999999999999      ,    0.0000000000000000       },
+    {   -17.300000000000001      ,  -0.80000000000000004      ,    0.0000000000000000      ,   0.90000000000000002       },
+    {   -3.2000000000000002      ,   -8.3000000000000007      ,  -0.80000000000000004      ,   0.29999999999999999       },
+    {  -0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -5.4000000000000004      ,    7.7999999999999998      ,  -0.29999999999999999      ,    0.0000000000000000       },
+    {   -14.800000000000001      ,    1.3999999999999999      ,    0.0000000000000000      ,   0.29999999999999999       },
+    {   -3.7999999999999998      ,   0.40000000000000002      ,    0.0000000000000000      ,  -0.20000000000000001       },
+    {    12.600000000000000      ,    3.2000000000000002      ,   0.50000000000000000      ,   -1.5000000000000000       },
+    {   0.10000000000000001      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -13.600000000000000      ,    2.3999999999999999      ,  -0.10000000000000001      ,    0.0000000000000000       },
+    {   0.90000000000000002      ,    1.2000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   -11.900000000000000      ,  -0.50000000000000000      ,    0.0000000000000000      ,   0.29999999999999999       },
+    {   0.40000000000000002      ,    12.000000000000000      ,   0.29999999999999999      ,  -0.20000000000000001       },
+    {    8.3000000000000007      ,    6.0999999999999996      ,  -0.10000000000000001      ,   0.10000000000000001       },
+    {    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000      ,    0.0000000000000000       },
+    {   0.40000000000000002      ,   -10.800000000000001      ,   0.29999999999999999      ,    0.0000000000000000       },
+    {    9.5999999999999996      ,    2.2000000000000002      ,   0.29999999999999999      ,   -1.2000000000000000       }
+  };
+
+  /*  interval between fundamental epoch j2000.0 and given epoch (jc). */
+  t = (date-DJM0)/DJC;
+
+  /*  mean anomaly of the moon. */
+  el  = 134.96340251*PAL__DD2R+
+    fmod(t*(1717915923.2178+
+            t*(        31.8792+
+                       t*(         0.051635+
+                                   t*(       - 0.00024470)))),TURNAS)*PAL__DAS2R;
+
+  /*  mean anomaly of the sun. */
+  elp = 357.52910918*PAL__DD2R+
+    fmod(t*( 129596581.0481+
+             t*(       - 0.5532+
+                       t*(         0.000136+
+                                   t*(       - 0.00001149)))),TURNAS)*PAL__DAS2R;
+      
+  /*  mean argument of the latitude of the moon. */
+  f   =  93.27209062*PAL__DD2R+
+    fmod(t*(1739527262.8478+
+           t*(      - 12.7512+
+                    t*(      -  0.001037+
+                             t*(         0.00000417)))),TURNAS)*PAL__DAS2R;
+
+  /*  mean elongation of the moon from the sun. */
+  d   = 297.85019547*PAL__DD2R+
+    fmod(t*(1602961601.2090+
+           t*(       - 6.3706+
+                     t*(         0.006539+
+                                 t*(       - 0.00003169)))),TURNAS)*PAL__DAS2R;
+
+  /*  mean longitude of the ascending node of the moon. */
+  om  = 125.04455501*PAL__DD2R+
+    fmod(t*( - 6962890.5431+
+            t*(         7.4722+
+                        t*(         0.007702+
+                                    t*(       - 0.00005939)))),TURNAS)*PAL__DAS2R;
+
+  /*  mean longitude of venus. */
+  ve    = 181.97980085*PAL__DD2R+fmod(210664136.433548*t,TURNAS)*PAL__DAS2R;
+
+  /*  mean longitude of mars.*/
+  ma    = 355.43299958*PAL__DD2R+fmod( 68905077.493988*t,TURNAS)*PAL__DAS2R;
+
+  /*  mean longitude of jupiter. */
+  ju    =  34.35151874*PAL__DD2R+fmod( 10925660.377991*t,TURNAS)*PAL__DAS2R;
+
+  /*  mean longitude of saturn. */
+  sa    =  50.07744430*PAL__DD2R+fmod(  4399609.855732*t,TURNAS)*PAL__DAS2R;
+
+  /*  geodesic nutation (fukushima 1991) in microarcsec. */
+  dp = -153.1*sin(elp)-1.9*sin(2*elp);
+  de = 0.0;
+
+  /*  shirai & fukushima (2001) nutation series. */
+  for (j=NTERMS-1; j >= 0; j--) {
+    theta = ((double)na[j][0])*el+
+      ((double)na[j][1])*elp+
+      ((double)na[j][2])*f+
+      ((double)na[j][3])*d+
+      ((double)na[j][4])*om+
+      ((double)na[j][5])*ve+
+      ((double)na[j][6])*ma+
+      ((double)na[j][7])*ju+
+      ((double)na[j][8])*sa;
+    c = cos(theta);
+    s = sin(theta);
+    dp += (psi[j][0] + psi[j][2]*t)*c + (psi[j][1] + psi[j][3]*t)*s;
+    de += (eps[j][0] + eps[j][2]*t)*c + (eps[j][1] + eps[j][3]*t)*s;
+  }
+
+  /*  change of units, and addition of the precession correction.*/
+  *dpsi = (dp*1e-6-0.042888-0.29856*t)*PAL__DAS2R;
+  *deps = (de*1e-6-0.005171-0.02408*t)*PAL__DAS2R;
+
+  /*  mean obliquity of date (simon et al. 1994). */
+  *eps0 = (84381.412+
+          (-46.80927+
+           (-0.000152+
+            (0.0019989+
+             (-0.00000051+
+              (-0.000000025)*t)*t)*t)*t)*t)*PAL__DAS2R;
+
+}
Index: trunk/FACT++/pal/palAoppat.c
===================================================================
--- trunk/FACT++/pal/palAoppat.c	(revision 18347)
+++ trunk/FACT++/pal/palAoppat.c	(revision 18347)
@@ -0,0 +1,103 @@
+/*
+*+
+*  Name:
+*     palAoppat
+
+*  Purpose:
+*     Recompute sidereal time to support apparent to observed place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAoppat( double date, double aoprms[14] );
+
+*  Arguments:
+*     date = double (Given)
+*         UTC date/time (modified Julian Date, JD-2400000.5)
+*         (see palAoppa description for comments on leap seconds)
+*     aoprms = double[14] (Given & Returned)
+*         Star-independent apparent-to-observed parameters. Updated
+*         by this routine. Requires element 12 to be the longitude +
+*         eqn of equinoxes + sidereal DUT and fills in element 13
+*         with the local apparent sidereal time (in radians).
+
+*  Description:
+*     This routine recomputes the sidereal time in the apparent to
+*     observed place star-independent parameter block.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - See palAoppa for more information.
+*     - The star-independent parameters are not treated as an opaque
+*       struct in order to retain compatibility with SLA.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version, ported from Fortran SLA source.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+static double pal__Gmst( double ut1 );
+
+void palAoppat( double date, double aoprms[14] ) {
+  aoprms[13] = pal__Gmst(date) + aoprms[12];
+}
+
+/* Use a private implementation of palGmst for testing that matches
+   the SLA rather than SOFA/ERFA implementation. This is used for comparing
+   SLA with PAL refraction code. */
+
+#include "math.h"
+#include "palmac.h"
+
+static double pal__Gmst( double ut1 ) {
+
+  double tu;
+  double gmst;
+
+  /*  Julian centuries from fundamental epoch J2000 to this UT */
+  tu=(ut1-51544.5)/36525;
+
+  /*  GMST at this UT */
+   gmst=palDranrm(fmod(ut1,1.0)*PAL__D2PI+
+                  (24110.54841+
+                   (8640184.812866+
+                    (0.093104-6.2e-6*tu)*tu)*tu)*PAL__DS2R);
+   return gmst;
+}
Index: trunk/FACT++/pal/palAopqk.c
===================================================================
--- trunk/FACT++/pal/palAopqk.c	(revision 18347)
+++ trunk/FACT++/pal/palAopqk.c	(revision 18347)
@@ -0,0 +1,288 @@
+/*
+*+
+*  Name:
+*     palAopqk
+
+*  Purpose:
+*     Quick apparent to observed place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAopqk ( double rap, double dap, const double aoprms[14],
+*                     double *aob, double *zob, double *hob,
+*                     double *dob, double *rob );
+
+*  Arguments:
+*     rap = double (Given)
+*        Geocentric apparent right ascension
+*     dap = double (Given)
+*        Geocentric apparent declination
+*     aoprms = const double [14] (Given)
+*        Star-independent apparent-to-observed parameters.
+*
+*         [0]      geodetic latitude (radians)
+*         [1,2]    sine and cosine of geodetic latitude
+*         [3]      magnitude of diurnal aberration vector
+*         [4]      height (HM)
+*         [5]      ambient temperature (T)
+*         [6]      pressure (P)
+*         [7]      relative humidity (RH)
+*         [8]      wavelength (WL)
+*         [9]      lapse rate (TLR)
+*         [10,11]  refraction constants A and B (radians)
+*         [12]     longitude + eqn of equinoxes + sidereal DUT (radians)
+*         [13]     local apparent sidereal time (radians)
+*     aob = double * (Returned)
+*        Observed azimuth (radians: N=0,E=90)
+*     zob = double * (Returned)
+*        Observed zenith distance (radians)
+*     hob = double * (Returned)
+*        Observed Hour Angle (radians)
+*     dob = double * (Returned)
+*        Observed Declination (radians)
+*     rob = double * (Returned)
+*        Observed Right Ascension (radians)
+
+*  Description:
+*     Quick apparent to observed place.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - This routine returns zenith distance rather than elevation
+*       in order to reflect the fact that no allowance is made for
+*       depression of the horizon.
+*
+*     - The accuracy of the result is limited by the corrections for
+*       refraction.  Providing the meteorological parameters are
+*       known accurately and there are no gross local effects, the
+*       observed RA,Dec predicted by this routine should be within
+*       about 0.1 arcsec for a zenith distance of less than 70 degrees.
+*       Even at a topocentric zenith distance of 90 degrees, the
+*       accuracy in elevation should be better than 1 arcmin;  useful
+*       results are available for a further 3 degrees, beyond which
+*       the palRefro routine returns a fixed value of the refraction.
+*       The complementary routines palAop (or palAopqk) and palOap
+*       (or palOapqk) are self-consistent to better than 1 micro-
+*       arcsecond all over the celestial sphere.
+*
+*     - It is advisable to take great care with units, as even
+*       unlikely values of the input parameters are accepted and
+*       processed in accordance with the models used.
+*
+*     - "Apparent" place means the geocentric apparent right ascension
+*       and declination, which is obtained from a catalogue mean place
+*       by allowing for space motion, parallax, precession, nutation,
+*       annual aberration, and the Sun's gravitational lens effect.  For
+*       star positions in the FK5 system (i.e. J2000), these effects can
+*       be applied by means of the palMap etc routines.  Starting from
+*       other mean place systems, additional transformations will be
+*       needed;  for example, FK4 (i.e. B1950) mean places would first
+*       have to be converted to FK5, which can be done with the
+*       palFk425 etc routines.
+*
+*     - "Observed" Az,El means the position that would be seen by a
+*       perfect theodolite located at the observer.  This is obtained
+*       from the geocentric apparent RA,Dec by allowing for Earth
+*       orientation and diurnal aberration, rotating from equator
+*       to horizon coordinates, and then adjusting for refraction.
+*       The HA,Dec is obtained by rotating back into equatorial
+*       coordinates, using the geodetic latitude corrected for polar
+*       motion, and is the position that would be seen by a perfect
+*       equatorial located at the observer and with its polar axis
+*       aligned to the Earth's axis of rotation (n.b. not to the
+*       refracted pole).  Finally, the RA is obtained by subtracting
+*       the HA from the local apparent ST.
+*
+*     - To predict the required setting of a real telescope, the
+*       observed place produced by this routine would have to be
+*       adjusted for the tilt of the azimuth or polar axis of the
+*       mounting (with appropriate corrections for mount flexures),
+*       for non-perpendicularity between the mounting axes, for the
+*       position of the rotator axis and the pointing axis relative
+*       to it, for tube flexure, for gear and encoder errors, and
+*       finally for encoder zero points.  Some telescopes would, of
+*       course, exhibit other properties which would need to be
+*       accounted for at the appropriate point in the sequence.
+*
+*     - The star-independent apparent-to-observed-place parameters
+*       in AOPRMS may be computed by means of the palAoppa routine.
+*       If nothing has changed significantly except the time, the
+*       palAoppat routine may be used to perform the requisite
+*       partial recomputation of AOPRMS.
+*
+*     - At zenith distances beyond about 76 degrees, the need for
+*       special care with the corrections for refraction causes a
+*       marked increase in execution time.  Moreover, the effect
+*       gets worse with increasing zenith distance.  Adroit
+*       programming in the calling application may allow the
+*       problem to be reduced.  Prepare an alternative AOPRMS array,
+*       computed for zero air-pressure;  this will disable the
+*       refraction corrections and cause rapid execution.  Using
+*       this AOPRMS array, a preliminary call to the present routine
+*       will, depending on the application, produce a rough position
+*       which may be enough to establish whether the full, slow
+*       calculation (using the real AOPRMS array) is worthwhile.
+*       For example, there would be no need for the full calculation
+*       if the preliminary call had already established that the
+*       source was well below the elevation limits for a particular
+*       telescope.
+*
+*     - The azimuths etc produced by the present routine are with
+*       respect to the celestial pole.  Corrections to the terrestrial
+*       pole can be computed using palPolmo.
+
+*  History:
+*     2012-08-25 (TIMJ):
+*        Initial version, copied from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2003 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+
+void palAopqk ( double rap, double dap, const double aoprms[14],
+                double *aob, double *zob, double *hob,
+                double *dob, double *rob ) {
+
+  /*  Breakpoint for fast/slow refraction algorithm:
+   *  ZD greater than arctan(4), (see palRefco routine)
+   *  or vector Z less than cosine(arctan(Z)) = 1/sqrt(17) */
+  const double zbreak = 0.242535625;
+  int i;
+
+  double  sphi,cphi,st,v[3],xhd,yhd,zhd,diurab,f,
+    xhdt,yhdt,zhdt,xaet,yaet,zaet,azobs,
+    zdt,refa,refb,zdobs,dzd,dref,ce,
+    xaeo,yaeo,zaeo,hmobs,dcobs,raobs;
+
+  /*  sin, cos of latitude */
+  sphi = aoprms[1];
+  cphi = aoprms[2];
+
+  /*  local apparent sidereal time */
+  st = aoprms[13];
+
+  /*  apparent ra,dec to cartesian -ha,dec */
+  palDcs2c( rap-st, dap, v );
+  xhd = v[0];
+  yhd = v[1];
+  zhd = v[2];
+
+  /*  diurnal aberration */
+  diurab = aoprms[3];
+  f = (1.0-diurab*yhd);
+  xhdt = f*xhd;
+  yhdt = f*(yhd+diurab);
+  zhdt = f*zhd;
+
+  /*  cartesian -ha,dec to cartesian az,el (s=0,e=90) */
+  xaet = sphi*xhdt-cphi*zhdt;
+  yaet = yhdt;
+  zaet = cphi*xhdt+sphi*zhdt;
+
+  /*  azimuth (n=0,e=90) */
+  if (xaet == 0.0 && yaet == 0.0) {
+    azobs = 0.0;
+  } else {
+    azobs = atan2(yaet,-xaet);
+  }
+
+  /*  topocentric zenith distance */
+  zdt = atan2(sqrt(xaet*xaet+yaet*yaet),zaet);
+
+  /*
+   *  refraction
+   *  ---------- */
+
+  /*  fast algorithm using two constant model */
+  refa = aoprms[10];
+  refb = aoprms[11];
+  palRefz(zdt,refa,refb,&zdobs);
+
+  /*  large zenith distance? */
+  if (cos(zdobs) < zbreak) {
+
+    /*     yes: use rigorous algorithm */
+
+    /*     initialize loop (maximum of 10 iterations) */
+    i = 1;
+    dzd = 1.0e1;
+    while (fabs(dzd) > 1e-10 && i <= 10) {
+
+      /*        compute refraction using current estimate of observed zd */
+      palRefro(zdobs,aoprms[4],aoprms[5],aoprms[6],
+               aoprms[7],aoprms[8],aoprms[0],
+               aoprms[9],1e-8,&dref);
+
+      /*        remaining discrepancy */
+      dzd = zdobs+dref-zdt;
+
+      /*        update the estimate */
+      zdobs = zdobs-dzd;
+
+      /*        increment the iteration counter */
+      i++;
+    }
+  }
+
+  /*  to cartesian az/zd */
+  ce = sin(zdobs);
+  xaeo = -cos(azobs)*ce;
+  yaeo = sin(azobs)*ce;
+  zaeo = cos(zdobs);
+
+  /*  cartesian az/zd to cartesian -ha,dec */
+  v[0] = sphi*xaeo+cphi*zaeo;
+  v[1] = yaeo;
+  v[2] = -cphi*xaeo+sphi*zaeo;
+
+  /*  to spherical -ha,dec */
+  palDcc2s(v,&hmobs,&dcobs);
+
+  /*  right ascension */
+  raobs = palDranrm(st+hmobs);
+
+  /*  return the results */
+  *aob = azobs;
+  *zob = zdobs;
+  *hob = -hmobs;
+  *dob = dcobs;
+  *rob = raobs;
+
+}
Index: trunk/FACT++/pal/palAtmdsp.c
===================================================================
--- trunk/FACT++/pal/palAtmdsp.c	(revision 18347)
+++ trunk/FACT++/pal/palAtmdsp.c	(revision 18347)
@@ -0,0 +1,180 @@
+/*
+*+
+*  Name:
+*     palAtmdsp
+
+*  Purpose:
+*     Apply atmospheric-dispersion adjustments to refraction coefficients
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palAtmdsp( double tdk, double pmb, double rh, double wl1,
+*                     double a1, double b1, double wl2, double *a2, double *b2 );
+
+
+*  Arguments:
+*     tdk = double (Given)
+*        Ambient temperature, K
+*     pmb = double (Given)
+*        Ambient pressure, millibars
+*     rh = double (Given)
+*        Ambient relative humidity, 0-1
+*     wl1 = double (Given)
+*        Reference wavelength, micrometre (0.4 recommended)
+*     a1 = double (Given)
+*        Refraction coefficient A for wavelength wl1 (radians)
+*     b1 = double (Given)
+*        Refraction coefficient B for wavelength wl1 (radians)
+*     wl2 = double (Given)
+*        Wavelength for which adjusted A,B required
+*     a2 = double * (Returned)
+*        Refraction coefficient A for wavelength WL2 (radians)
+*     b2 = double * (Returned)
+*        Refraction coefficient B for wavelength WL2 (radians)
+
+*  Description:
+*     Apply atmospheric-dispersion adjustments to refraction coefficients.
+
+*  Authors:
+*     TIMJ: Tim Jenness
+*     PTW: Patrick Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - To use this routine, first call palRefco specifying WL1 as the
+*     wavelength.  This yields refraction coefficients A1,B1, correct
+*     for that wavelength.  Subsequently, calls to palAtmdsp specifying
+*     different wavelengths will produce new, slightly adjusted
+*     refraction coefficients which apply to the specified wavelength.
+*
+*     - Most of the atmospheric dispersion happens between 0.7 micrometre
+*     and the UV atmospheric cutoff, and the effect increases strongly
+*     towards the UV end.  For this reason a blue reference wavelength
+*     is recommended, for example 0.4 micrometres.
+*
+*     - The accuracy, for this set of conditions:
+*
+*        height above sea level    2000 m
+*                      latitude    29 deg
+*                      pressure    793 mb
+*                   temperature    17 degC
+*                      humidity    50%
+*                    lapse rate    0.0065 degC/m
+*          reference wavelength    0.4 micrometre
+*                star elevation    15 deg
+*
+*     is about 2.5 mas RMS between 0.3 and 1.0 micrometres, and stays
+*     within 4 mas for the whole range longward of 0.3 micrometres
+*     (compared with a total dispersion from 0.3 to 20.0 micrometres
+*     of about 11 arcsec).  These errors are typical for ordinary
+*     conditions and the given elevation;  in extreme conditions values
+*     a few times this size may occur, while at higher elevations the
+*     errors become much smaller.
+*
+*     - If either wavelength exceeds 100 micrometres, the radio case
+*     is assumed and the returned refraction coefficients are the
+*     same as the given ones.  Note that radio refraction coefficients
+*     cannot be turned into optical values using this routine, nor
+*     vice versa.
+*
+*     - The algorithm consists of calculation of the refractivity of the
+*     air at the observer for the two wavelengths, using the methods
+*     of the palRefro routine, and then scaling of the two refraction
+*     coefficients according to classical refraction theory.  This
+*     amounts to scaling the A coefficient in proportion to (n-1) and
+*     the B coefficient almost in the same ratio (see R.M.Green,
+*     "Spherical Astronomy", Cambridge University Press, 1985).
+
+*  History:
+*     2014-07-15 (TIMJ):
+*        Initial version. A direct copy of the Fortran SLA implementation.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2014 Tim Jenness
+*     Copyright (C) 2005 Patrick Wallace
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include <math.h>
+
+void palAtmdsp ( double tdk, double pmb, double rh, double wl1,
+                 double a1, double b1, double wl2, double *a2, double *b2 ) {
+
+  double f,tdkok,pmbok,rhok;
+  double psat,pwo,w1,wlok,wlsq,w2,dn1,dn2;
+
+  /*  Check for radio wavelengths */
+  if (wl1 > 100.0 || wl2 > 100.0) {
+
+    /*     Radio: no dispersion */
+    *a2 = a1;
+    *b2 = b1;
+
+  } else {
+
+    /*     Optical: keep arguments within safe bounds */
+    tdkok = DMIN(DMAX(tdk,100.0),500.0);
+    pmbok = DMIN(DMAX(pmb,0.0),10000.0);
+    rhok = DMIN(DMAX(rh,0.0),1.0);
+
+    /*     Atmosphere parameters at the observer */
+    psat = pow(10.0, -8.7115+0.03477*tdkok);
+    pwo = rhok*psat;
+    w1 = 11.2684e-6*pwo;
+
+    /*     Refractivity at the observer for first wavelength */
+    wlok = DMAX(wl1,0.1);
+    wlsq = wlok*wlok;
+    w2 = 77.5317e-6+(0.43909e-6+0.00367e-6/wlsq)/wlsq;
+    dn1 = (w2*pmbok-w1)/tdkok;
+
+    /*     Refractivity at the observer for second wavelength */
+    wlok = DMAX(wl2,0.1);
+    wlsq = wlok*wlok;
+    w2 = 77.5317e-6+(0.43909e-6+0.00367e-6/wlsq)/wlsq;
+    dn2 = (w2*pmbok-w1)/tdkok;
+
+    /*     Scale the refraction coefficients (see Green 4.31, p93) */
+    if (dn1 != 0.0) {
+      f = dn2/dn1;
+      *a2 = a1*f;
+      *b2 = b1*f;
+      if (dn1 != a1) {
+        *b2 *= (1.0+dn1*(dn1-dn2)/(2.0*(dn1-a1)));
+      }
+    }  else {
+      *a2 = a1;
+      *b2 = b1;
+    }
+  }
+
+}
Index: trunk/FACT++/pal/palCaldj.c
===================================================================
--- trunk/FACT++/pal/palCaldj.c	(revision 18347)
+++ trunk/FACT++/pal/palCaldj.c	(revision 18347)
@@ -0,0 +1,99 @@
+/*
+*+
+*  Name:
+*     palCaldj
+
+*  Purpose:
+*     Gregorian Calendar to Modified Julian Date
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palCaldj ( int iy, int im, int id, double *djm, int *j );
+
+*  Arguments:
+*     iy = int (Given)
+*        Year in the Gregorian calendar
+*     im = int (Given)
+*        Month in the Gergorian calendar
+*     id = int (Given)
+*        Day in the Gregorian calendar
+*     djm = double * (Returned)
+*        Modified Julian Date (JD-2400000.5) for 0 hrs
+*     j = status (Returned)
+*       0 = OK. See eraCal2jd for other values.
+
+*  Description:
+*     Modified Julian Date to Gregorian Calendar with special
+*     behaviour for 2-digit years relating to 1950 to 2049.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-11 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Notes:
+*     - Uses eraCal2jd
+*     - Unlike eraCal2jd this routine treats the years 0-100 as
+*       referring to the end of the 20th Century and beginning of
+*       the 21st Century. If this behaviour is not acceptable
+*       use the SOFA/ERFA routine directly or palCldj.
+*       Acceptable years are 00-49, interpreted as 2000-2049,
+*                            50-99,     "       "  1950-1999,
+*                            all others, interpreted literally.
+*     - Unlike SLA this routine will work with negative years.
+
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palCaldj ( int iy, int im, int id, double *djm, int *j ) {
+  int adj = 0;   /* Year adjustment */
+  double djm0;
+
+  if (iy >= 0 && iy <= 49) {
+    adj = 2000;
+  } else if (iy >= 50 && iy <= 99) {
+    adj = 1900;
+  }
+  iy += adj;
+
+  *j = eraCal2jd( iy, im, id, &djm0, djm );
+}
Index: trunk/FACT++/pal/palDafin.c
===================================================================
--- trunk/FACT++/pal/palDafin.c	(revision 18347)
+++ trunk/FACT++/pal/palDafin.c	(revision 18347)
@@ -0,0 +1,194 @@
+/*
+*+
+*  Name:
+*     palDafin
+
+*  Purpose:
+*     Sexagesimal character string to angle
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDafin ( const char *string, int *ipos, double *a, int *j );
+
+*  Arguments:
+*     string = const char * (Given)
+*        String containing deg, arcmin, arcsec fields
+*     ipos = int * (Given & Returned)
+*        Position to start decoding "string". First character
+*        is position 1 for compatibility with SLA. After
+*        calling this routine "iptr" will be positioned after
+*        the sexagesimal string.
+*     a = double * (Returned)
+*        Angle in radians.
+*     j = int * (Returned)
+*        status:  0 = OK
+*                +1 = default, A unchanged
+*                -1 = bad degrees      )
+*                -2 = bad arcminutes   )  (note 3)
+*                -3 = bad arcseconds   )
+
+*  Description:
+*     Extracts an angle from a sexagesimal string with degrees, arcmin,
+*     arcsec fields using space or comma delimiters.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Example:
+*     argument    before                           after
+*
+*     STRING      '-57 17 44.806  12 34 56.7'      unchanged
+*     IPTR        1                                16 (points to 12...)
+*     A           ?                                -1.00000D0
+*     J           ?                                0
+
+*  Notes:
+*     - The first three "fields" in STRING are degrees, arcminutes,
+*       arcseconds, separated by spaces or commas.  The degrees field
+*       may be signed, but not the others.  The decoding is carried
+*       out by the palDfltin routine and is free-format.
+*     - Successive fields may be absent, defaulting to zero.  For
+*       zero status, the only combinations allowed are degrees alone,
+*       degrees and arcminutes, and all three fields present.  If all
+*       three fields are omitted, a status of +1 is returned and A is
+*       unchanged.  In all other cases A is changed.
+*     - Range checking:
+*
+*           The degrees field is not range checked.  However, it is
+*           expected to be integral unless the other two fields are absent.
+*
+*           The arcminutes field is expected to be 0-59, and integral if
+*           the arcseconds field is present.  If the arcseconds field
+*           is absent, the arcminutes is expected to be 0-59.9999...
+*
+*           The arcseconds field is expected to be 0-59.9999...
+*
+*     - Decoding continues even when a check has failed.  Under these
+*       circumstances the field takes the supplied value, defaulting
+*       to zero, and the result A is computed and returned.
+*     - Further fields after the three expected ones are not treated
+*       as an error.  The pointer IPOS is left in the correct state
+*       for further decoding with the present routine or with palDfltin
+*       etc. See the example, above.
+*     - If STRING contains hours, minutes, seconds instead of degrees
+*       etc, or if the required units are turns (or days) instead of
+*       radians, the result A should be multiplied as follows:
+*
+*           for        to obtain    multiply
+*           STRING     A in         A by
+*
+*           d ' "      radians      1       =  1.0
+*           d ' "      turns        1/2pi   =  0.1591549430918953358
+*           h m s      radians      15      =  15.0
+*           h m s      days         15/2pi  =  2.3873241463784300365
+
+*  History:
+*     2012-03-08 (TIMJ):
+*        Initial version from SLA/F using Fortran documentation
+*        Adapted with permission from the Fortran SLALIB library.
+*     2012-10-17 (TIMJ):
+*        Fix range check on arcminute value.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+#include <math.h>
+
+void palDafin ( const char *string, int *ipos, double *a, int *j ) {
+
+  int jd = 0;    /* Status for degree parsing */
+  int jm = 0;    /* Status for arcmin parsing */
+  int js = 0;    /* Status for arcsec parsing */
+  int jf = 0;    /* Internal copy of status */
+  double deg = 0.0;
+  double arcmin = 0.0;
+  double arcsec = 0.0;
+
+  /* Decode degrees, arcminutes, arcseconds */
+  palDfltin( string, ipos, &deg, &jd );
+  if (jd > 1) {
+    jf = -1;
+  } else {
+
+    palDfltin( string, ipos, &arcmin, &jm );
+    if ( jm < 0 || jm > 1 ) {
+      jf = -2;
+    } else {
+
+      palDfltin( string, ipos, &arcsec, &js );
+      if (js < 0 || js > 1) {
+        jf = -3;
+
+      } else if (jd > 0) { /* See if combination of fields is credible */
+        /* No degrees: arcmin, arcsec ought also to be absent */
+        if (jm == 0) {
+          /* Suspect arcmin */
+          jf = -2;
+        } else if (js == 0) {
+          /* Suspect arcsec */
+          jf = -3;
+        } else {
+          /* All three fields absent */
+          jf = 1;
+        }
+
+      } else if (jm != 0 && js == 0) { /* Deg present: if arcsec present should have arcmin */
+        jf = -3;
+
+      /* Tests for range and integrality */
+      } else if (jm == 0 && DINT(deg) != deg) { /* Degrees */
+        jf = -1;
+
+      } else if ( (js == 0 && DINT(arcmin) != arcmin) || arcmin >= 60.0 ) { /* Arcmin */
+        jf = -2;
+
+      } else if (arcsec >= 60.0) { /* Arcsec */
+        jf = -3;
+      }
+    }
+  }
+
+  /* Unless all three fields absent, compute angle value */
+  if (jf <= 0) {
+    *a = PAL__DAS2R * ( 60.0 * ( 60.0 * fabs(deg) + arcmin) + arcsec );
+    if ( jd < 0 ) *a *= -1.;
+  }
+
+  *j = jf;
+
+}
Index: trunk/FACT++/pal/palDat.c
===================================================================
--- trunk/FACT++/pal/palDat.c	(revision 18347)
+++ trunk/FACT++/pal/palDat.c	(revision 18347)
@@ -0,0 +1,95 @@
+/*
+*+
+*  Name:
+*     palDat
+
+*  Purpose:
+*     Return offset between UTC and TAI
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     dat = palDat( double utc );
+
+*  Arguments:
+*     utc = double (Given)
+*        UTC date as a modified JD (JD-2400000.5)
+
+*  Returned Value:
+*     dat = double
+*        TAI-UTC in seconds
+
+*  Description:
+*     Increment to be applied to Coordinated Universal Time UTC to give
+*     International Atomic Time (TAI).
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - This routine converts the MJD argument to calendar date before calling
+*       the SOFA/ERFA eraDat function.
+*     - This routine matches the slaDat interface which differs from the eraDat
+*       interface. Consider coding directly to the SOFA/ERFA interface.
+*     - See eraDat for a description of error conditions when calling this function
+*       with a time outside of the UTC range.
+*     - The status argument from eraDat is ignored. This is reasonable since the
+*       error codes are mainly related to incorrect calendar dates when calculating
+*       the JD internally.
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library
+*        although the core algorithm is now from SOFA.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+
+#include "pal1sofa.h"
+
+double palDat ( double dju ) {
+  int iy;
+  int im;
+  int id;
+  int status;
+  double fd;
+  double deltat;
+
+  eraJd2cal( PAL__MJD0, dju,
+             &iy, &im, &id, &fd );
+
+  status = eraDat( iy, im, id, fd, &deltat );
+  return deltat;
+}
Index: trunk/FACT++/pal/palDe2h.c
===================================================================
--- trunk/FACT++/pal/palDe2h.c	(revision 18347)
+++ trunk/FACT++/pal/palDe2h.c	(revision 18347)
@@ -0,0 +1,142 @@
+/*
+*+
+*  Name:
+*     palDe2h
+
+*  Purpose:
+*     Equatorial to horizon coordinates: HA,Dec to Az,E
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDe2h( double ha, double dec, double phi, double * az, double * el );
+
+*  Arguments:
+*     ha = double * (Given)
+*        Hour angle (radians)
+*     dec = double * (Given)
+*        Declination (radians)
+*     phi = double (Given)
+*        Observatory latitude (radians)
+*     az = double * (Returned)
+*        Azimuth (radians)
+*     el = double * (Returned)
+*        Elevation (radians)
+
+*  Description:
+*     Convert equatorial to horizon coordinates.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - All the arguments are angles in radians.
+*     - Azimuth is returned in the range 0-2pi;  north is zero,
+*       and east is +pi/2.  Elevation is returned in the range
+*       +/-pi/2.
+*     - The latitude must be geodetic.  In critical applications,
+*       corrections for polar motion should be applied.
+*     - In some applications it will be important to specify the
+*       correct type of hour angle and declination in order to
+*       produce the required type of azimuth and elevation.  In
+*       particular, it may be important to distinguish between
+*       elevation as affected by refraction, which would
+*       require the "observed" HA,Dec, and the elevation
+*       in vacuo, which would require the "topocentric" HA,Dec.
+*       If the effects of diurnal aberration can be neglected, the
+*       "apparent" HA,Dec may be used instead of the topocentric
+*       HA,Dec.
+*     - No range checking of arguments is carried out.
+*     - In applications which involve many such calculations, rather
+*       than calling the present routine it will be more efficient to
+*       use inline code, having previously computed fixed terms such
+*       as sine and cosine of latitude, and (for tracking a star)
+*       sine and cosine of declination.
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include <math.h>
+
+void
+palDe2h ( double ha, double dec, double phi, double *az, double *el) {
+
+  double sh;
+  double ch;
+  double sd;
+  double cd;
+  double sp;
+  double cp;
+
+  double a;
+
+  double x;
+  double y;
+  double z;
+  double r;
+
+  /*  Useful trig functions */
+  sh = sin(ha);
+  ch = cos(ha);
+  sd = sin(dec);
+  cd = cos(dec);
+  sp = sin(phi);
+  cp = cos(phi);
+
+  /*  Az,El as x,y,z */
+  x = -ch * cd * sp + sd * cp;
+  y = -sh * cd;
+  z = ch * cd * cp + sd * sp;
+
+  /*  To spherical */
+  r = sqrt(x * x + y * y);
+  if (r == 0.) {
+    a = 0.;
+  } else {
+    a = atan2(y, x);
+  }
+  if (a < 0.) {
+    a += PAL__D2PI;
+  }
+  *az = a;
+  *el = atan2(z, r);
+
+  return;
+}
Index: trunk/FACT++/pal/palDeuler.c
===================================================================
--- trunk/FACT++/pal/palDeuler.c	(revision 18347)
+++ trunk/FACT++/pal/palDeuler.c	(revision 18347)
@@ -0,0 +1,141 @@
+/*
+*+
+*  Name:
+*     palDeuler
+
+*  Purpose:
+*     Form a rotation matrix from the Euler angles
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDeuler ( const char *order, double phi, double theta, double psi,
+*                      double rmat[3][3] );
+
+*  Arguments:
+*     order = const char[] (Given)
+*        Specifies about which axes the rotation occurs
+*     phi = double (Given)
+*        1st rotation (radians)
+*     theta = double (Given)
+*        2nd rotation (radians)
+*     psi = double (Given)
+*        3rd rotation (radians)
+*     rmat = double[3][3] (Given & Returned)
+*        Rotation matrix
+
+*  Description:
+*     A rotation is positive when the reference frame rotates
+*     anticlockwise as seen looking towards the origin from the
+*     positive region of the specified axis.
+*
+*     The characters of ORDER define which axes the three successive
+*     rotations are about.  A typical value is 'ZXZ', indicating that
+*     RMAT is to become the direction cosine matrix corresponding to
+*     rotations of the reference frame through PHI radians about the
+*     old Z-axis, followed by THETA radians about the resulting X-axis,
+*     then PSI radians about the resulting Z-axis.
+*
+*     The axis names can be any of the following, in any order or
+*     combination:  X, Y, Z, uppercase or lowercase, 1, 2, 3.  Normal
+*     axis labelling/numbering conventions apply;  the xyz (=123)
+*     triad is right-handed.  Thus, the 'ZXZ' example given above
+*     could be written 'zxz' or '313' (or even 'ZxZ' or '3xZ').  ORDER
+*     is terminated by length or by the first unrecognized character.
+*
+*     Fewer than three rotations are acceptable, in which case the later
+*     angle arguments are ignored.  If all rotations are zero, the
+*     identity matrix is produced.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1997 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void
+palDeuler( const char *order, double phi, double theta, double psi,
+                 double rmat[3][3] ) {
+  int i = 0;
+  double rotations[3];
+
+  /* Initialise rmat */
+  eraIr( rmat );
+
+  /* copy the rotations into an array */
+  rotations[0] = phi;
+  rotations[1] = theta;
+  rotations[2] = psi;
+
+  /* maximum three rotations */
+  while (i < 3 && order[i] != '\0') {
+
+    switch (order[i]) {
+    case 'X':
+    case 'x':
+    case '1':
+      eraRx( rotations[i], rmat );
+      break;
+
+    case 'Y':
+    case 'y':
+    case '2':
+      eraRy( rotations[i], rmat );
+      break;
+
+    case 'Z':
+    case 'z':
+    case '3':
+      eraRz( rotations[i], rmat );
+      break;
+
+    default:
+      /* break out the loop if we do not recognize something */
+      i = 3;
+
+    }
+
+    /* Go to the next position */
+    i++;
+  }
+
+  return;
+}
Index: trunk/FACT++/pal/palDfltin.c
===================================================================
--- trunk/FACT++/pal/palDfltin.c	(revision 18347)
+++ trunk/FACT++/pal/palDfltin.c	(revision 18347)
@@ -0,0 +1,258 @@
+/*
+*+
+*  Name:
+*     palDfltin
+
+*  Purpose:
+*     Convert free-format input into double precision floating point
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDfltin( const char * string, int *nstrt,
+*                     double *dreslt, int *jflag );
+
+*  Arguments:
+*     string = const char * (Given)
+*        String containing number to be decoded.
+*     nstrt = int * (Given and Returned)
+*        Character number indicating where decoding should start.
+*        On output its value is updated to be the location of the
+*        possible next value. For compatibility with SLA the first
+*        character is index 1.
+*     dreslt = double * (Returned)
+*        Result. Not updated when jflag=1.
+*     jflag = int * (Returned)
+*        status: -1 = -OK, 0 = +OK, 1 = null, 2 = error
+
+*  Description:
+*     Extracts a number from an input string starting at the specified
+*     index.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Uses the strtod() system call to do the parsing. This may lead to
+*       subtle differences when compared to the SLA/F parsing.
+*     - All "D" characters are converted to "E" to handle fortran exponents.
+*     - Commas are recognized as a special case and are skipped if one happens
+*       to be the next character when updating nstrt. Additionally the output
+*       nstrt position will skip past any trailing space.
+*     - If no number can be found flag will be set to 1.
+*     - If the number overflows or underflows jflag will be set to 2. For overflow
+*       the returned result will have the value HUGE_VAL, for underflow it
+*       will have the value 0.0.
+*     - For compatiblity with SLA/F -0 will be returned as "0" with jflag == -1.
+*     - Unlike slaDfltin a standalone "E" will return status 1 (could not find
+*       a number) rather than 2 (bad number).
+
+*  Implementation Status:
+*     - The code is more robust if the C99 copysign() function is available.
+*     This can recognize the -0.0 values returned by strtod. If copysign() is
+*     missing we try to scan the string looking for minus signs.
+
+*  History:
+*     2012-03-08 (TIMJ):
+*        Initial version based on strtod
+*        Adapted with permission from the Fortran SLALIB library
+*        although this is a completely distinct implementation of the SLA API.
+*     2012-06-21 (TIMJ):
+*        Provide a backup for missing copysign.
+*     2012-06-22 (TIMJ):
+*        Check __STDC_VERSION__
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+/* Use the config file if we have one, else look at
+   compiler defines to see if we have C99 */
+#if HAVE_CONFIG_H
+#include <config.h>
+#else
+#ifdef __STDC_VERSION__
+#  if (__STDC_VERSION__ >= 199901L)
+#    define HAVE_COPYSIGN 1
+#  endif
+#endif
+#endif
+
+/* isblank() is a C99 feature so we just reimplement it if it is missing */
+#if HAVE_ISBLANK
+#define _POSIX_C_SOURCE 200112L
+#define _ISOC99_SOURCE
+#include <ctype.h>
+# define ISBLANK isblank
+#else
+
+static int ISBLANK( int c ) {
+  return ( c == ' ' || c == '\t' );
+}
+
+#endif
+
+#ifdef HAVE_BSD_STRING_H
+#include <bsd/string.h>
+#endif
+
+/* System include files */
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "pal.h"
+
+#if HAVE_COPYSIGN
+# define SCAN_FOR_MINUS 0
+#else
+# define SCAN_FOR_MINUS 1
+#endif
+
+/* We prefer to use the starutil package */
+#if HAVE_STAR_UTIL_H
+# include "star/util.h"
+#else
+#endif
+
+void palDfltin( const char * string, int *nstrt,
+                double *dreslt, int *jflag ) {
+
+  char * ctemp = NULL; /* Pointer into string */
+  char * endptr = NULL;/* Pointer to string after number */
+  double retval;       /* Return value from strtod */
+
+  /* We have to copy the string in order to modify the exponents
+     from Fortran style. Rather than using malloc we have a static
+     buffer. Technically we only have to do the copy if we have a
+     D or d in the string. */
+  char tempbuf[256];
+
+#if SCAN_FOR_MINUS
+  int dreslt_sign = 1;
+  int ipos = *nstrt;
+  const char * cctemp = NULL;
+
+  /* Scan the string looking for a minus sign. Then update the
+     start position for the subsequent copy iff we find a '-'.
+     Note  that commas are a special delimiter so we stop looking for a
+     minus if we find one or if we find a digit. */
+  cctemp = &(string[ipos-1]);
+  while (!isdigit(*cctemp) && (*cctemp != ',') && (*cctemp != '\0')) {
+    if (*cctemp == '-') {
+      *nstrt = ipos;
+      dreslt_sign = -1;
+      break;
+    }
+    ipos++;
+    cctemp++;
+  }
+#endif
+
+  /* Correct for SLA use of fortran convention */
+#if HAVE_STAR_UTIL_H
+  star_strlcpy( tempbuf, &(string[*nstrt-1]), sizeof(tempbuf) );
+#else
+# if HAVE_STRLCPY
+  strlcpy( tempbuf, &(string[*nstrt-1]), sizeof(tempbuf) );
+# else
+  /* Use standard C interface */
+  strncpy( tempbuf, &(string[*nstrt-1]), sizeof(tempbuf));
+  tempbuf[sizeof(tempbuf)-1] = '\0';
+# endif
+#endif
+
+  /* Convert d or D to E */
+  ctemp = tempbuf;
+  while (*ctemp != '\0') {
+    if (*ctemp == 'd' || *ctemp == 'D') *ctemp = 'E';
+    ctemp++;
+  }
+
+  /* strtod man page indicates that we should reset errno before
+     calling strtod */
+  errno = 0;
+
+  /* We know we are starting at the beginning of the string now */
+  retval = strtod( tempbuf, &endptr );
+  if (retval == 0.0 && endptr == tempbuf) {
+    /* conversion did not find anything */
+    *jflag = 1;
+
+    /* but SLA compatibility requires that we step
+       through to remove leading spaces. We also step
+       through alphabetic characters since they can never
+       be numbers standalone (no number starts with an 'E') */
+    while (ISBLANK(*endptr) || isalpha(*endptr) ) {
+      endptr++;
+    }
+
+  } else if ( errno == ERANGE ) {
+    *jflag = 2;
+  } else {
+#if SCAN_FOR_MINUS
+    *jflag = (dreslt_sign < 0 ? -1 : 0);
+#else
+    if ( retval < 0.0 ) {
+      *jflag = -1;
+    } else if ( retval == 0.0 ) {
+      /* Need to distinguish -0 from +0 */
+      double test = copysign( 1.0, retval );
+      if ( test < 0.0 ) {
+        *jflag = -1;
+      } else {
+        *jflag = 0;
+      }
+    } else {
+      *jflag = 0;
+    }
+#endif
+  }
+
+  /* Sort out the position for the next index */
+  *nstrt += endptr - tempbuf;
+
+  /* Skip a comma */
+  if (*endptr == ',') {
+    (*nstrt)++;
+  } else {
+    /* jump past any leading spaces for the next part of the string */
+    ctemp = endptr;
+    while ( ISBLANK(*ctemp) ) {
+      (*nstrt)++;
+      ctemp++;
+    }
+  }
+
+  /* And the result unless we found nothing */
+  if (*jflag != 1) *dreslt = retval;
+
+}
Index: trunk/FACT++/pal/palDh2e.c
===================================================================
--- trunk/FACT++/pal/palDh2e.c	(revision 18347)
+++ trunk/FACT++/pal/palDh2e.c	(revision 18347)
@@ -0,0 +1,133 @@
+/*
+*+
+*  Name:
+*     palDh2e
+
+*  Purpose:
+*     Horizon to equatorial coordinates: Az,El to HA,Dec
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDh2e( double az, double el, double phi, double * ha, double * dec );
+
+*  Arguments:
+*     az = double (Given)
+*        Azimuth (radians)
+*     el = double (Given)
+*        Elevation (radians)
+*     phi = double (Given)
+*        Observatory latitude (radians)
+*     ha = double * (Returned)
+*        Hour angle (radians)
+*     dec = double * (Returned)
+*        Declination (radians)
+
+*  Description:
+*     Convert horizon to equatorial coordinates.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - All the arguments are angles in radians.
+*     - The sign convention for azimuth is north zero, east +pi/2.
+*     - HA is returned in the range +/-pi.  Declination is returned
+*       in the range +/-pi/2.
+*     - The latitude is (in principle) geodetic.  In critical
+*       applications, corrections for polar motion should be applied.
+*     - In some applications it will be important to specify the
+*       correct type of elevation in order to produce the required
+*       type of HA,Dec.  In particular, it may be important to
+*       distinguish between the elevation as affected by refraction,
+*       which will yield the "observed" HA,Dec, and the elevation
+*       in vacuo, which will yield the "topocentric" HA,Dec.  If the
+*       effects of diurnal aberration can be neglected, the
+*       topocentric HA,Dec may be used as an approximation to the
+*       "apparent" HA,Dec.
+*     - No range checking of arguments is done.
+*     - In applications which involve many such calculations, rather
+*       than calling the present routine it will be more efficient to
+*       use inline code, having previously computed fixed terms such
+*       as sine and cosine of latitude.
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include <math.h>
+
+void
+palDh2e ( double az, double el, double phi, double *ha, double *dec) {
+
+  double sa;
+  double ca;
+  double se;
+  double ce;
+  double sp;
+  double cp;
+
+  double x;
+  double y;
+  double z;
+  double r;
+
+  /*  Useful trig functions */
+  sa = sin(az);
+  ca = cos(az);
+  se = sin(el);
+  ce = cos(el);
+  sp = sin(phi);
+  cp = cos(phi);
+
+  /*  HA,Dec as x,y,z */
+  x = -ca * ce * sp + se * cp;
+  y = -sa * ce;
+  z = ca * ce * cp + se * sp;
+
+  /*  To HA,Dec */
+  r = sqrt(x * x + y * y);
+  if (r == 0.) {
+    *ha = 0.;
+  } else {
+    *ha = atan2(y, x);
+  }
+  *dec = atan2(z, r);
+
+  return;
+}
Index: trunk/FACT++/pal/palDjcal.c
===================================================================
--- trunk/FACT++/pal/palDjcal.c	(revision 18347)
+++ trunk/FACT++/pal/palDjcal.c	(revision 18347)
@@ -0,0 +1,97 @@
+/*
+*+
+*  Name:
+*     palDjcal
+
+*  Purpose:
+*     Modified Julian Date to Gregorian Calendar
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDjcal ( int ndp, double djm, int iymdf[4], int *j );
+
+*  Arguments:
+*     ndp = int (Given)
+*        Number of decimal places of days in fraction.
+*     djm = double (Given)
+*        Modified Julian Date (JD-2400000.5)
+*     iymdf[4] = int[] (Returned)
+*       Year, month, day, fraction in Gregorian calendar.
+*     j = status (Returned)
+*       0 = OK. See eraJd2cal for other values.
+
+*  Description:
+*     Modified Julian Date to Gregorian Calendar, expressed
+*     in a form convenient for formatting messages (namely
+*     rounded to a specified precision, and with the fields
+*     stored in a single array)
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-10 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Notes:
+*     - Uses eraJd2cal
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palDjcal ( int ndp, double djm, int iymdf[4], int *j ) {
+  double frac = 0.0;
+  double nfd;
+
+  *j = eraJd2cal( PAL__MJD0, djm, &(iymdf[0]),
+		  &(iymdf[1]), &(iymdf[2]),
+		  &frac);
+
+  /* Convert ndp to a power of 10 */
+  nfd = pow( 10., (double)ndp );
+
+  /* Multiply the fraction */
+  frac *= nfd;
+
+  /* and now we want to round to the nearest integer */
+  iymdf[3] = (int)DNINT(frac);
+
+}
Index: trunk/FACT++/pal/palDmat.c
===================================================================
--- trunk/FACT++/pal/palDmat.c	(revision 18347)
+++ trunk/FACT++/pal/palDmat.c	(revision 18347)
@@ -0,0 +1,182 @@
+/*
+*+
+*  Name:
+*     palDmat
+
+*  Purpose:
+*     Matrix inversion & solution of simultaneous equations
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDmat( int n, double *a, double *y, double *d, int *jf,
+*                    int *iw );
+
+*  Arguments:
+*     n = int (Given)
+*        Number of simultaneous equations and number of unknowns.
+*     a = double[] (Given & Returned)
+*        A non-singular NxN matrix (implemented as a contiguous block
+*        of memory). After calling this routine "a" contains the
+*        inverse of the matrix.
+*     y = double[] (Given & Returned)
+*        On input the vector of N knowns. On exit this vector contains the
+*        N solutions.
+*     d = double * (Returned)
+*        The determinant.
+*     jf = int * (Returned)
+*        The singularity flag.  If the matrix is non-singular, jf=0
+*        is returned.  If the matrix is singular, jf=-1 & d=0.0 are
+*        returned.  In the latter case, the contents of array "a" on
+*        return are undefined.
+*     iw = int[] (Given)
+*        Integer workspace of size N.
+
+*  Description:
+*     Matrix inversion & solution of simultaneous equations
+*     For the set of n simultaneous equations in n unknowns:
+*          A.Y = X
+*     this routine calculates the inverse of A, the determinant
+*     of matrix A and the vector of N unknowns.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-11 (TIMJ):
+*        Combination of a port of the Fortran and a comparison
+*        with the obfuscated GPL C routine.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Notes:
+*     - Implemented using Gaussian elimination with partial pivoting.
+*     - Optimized for speed rather than accuracy with errors 1 to 4
+*       times those of routines optimized for accuracy.
+
+*  Copyright:
+*     Copyright (C) 2001 Rutherford Appleton Laboratory.
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palDmat ( int n, double *a, double *y, double *d, int *jf, int *iw ) {
+
+  const double SFA = 1e-20;
+
+  int k;
+  double*aoff;
+
+  *jf=0;
+  *d=1.0;
+  for(k=0,aoff=a; k<n; k++, aoff+=n){
+    int imx;
+    double * aoff2 = aoff;
+    double amx=fabs(aoff[k]);
+    imx=k;
+    if(k!=n){
+      int i;
+      double *apos2;
+      for(i=k+1,apos2=aoff+n;i<n;i++,apos2+=n){
+	double t=fabs(apos2[k]);
+	if(t>amx){
+	  amx=t;
+	  imx=i;
+	  aoff2=apos2;
+	}
+      }
+    }
+    if(amx<SFA){
+      *jf=-1;
+    } else {
+      if(imx!=k){
+	double t;
+	int j;
+	for(j=0;j<n;j++){
+	  t=aoff[j];
+	  aoff[j]=aoff2[j];
+	  aoff2[j]=t;
+	}
+	t=y[k];
+	y[k]=y[imx];
+	y[imx]=t;*d=-*d;
+      }
+      iw[k]=imx;
+      *d*=aoff[k];
+      if(fabs(*d)<SFA){
+	*jf=-1;
+      } else {
+	double yk;
+	double * apos2;
+	int i, j;
+	aoff[k]=1.0/aoff[k];
+	for(j=0;j<n;j++){
+	  if(j!=k){
+	    aoff[j]*=aoff[k];
+	  }
+	}
+	yk=y[k]*aoff[k];
+	y[k]=yk;
+	for(i=0,apos2=a;i<n;i++,apos2+=n){
+	  if(i!=k){
+	    for(j=0;j<n;j++){
+	      if(j!=k){
+		apos2[j]-=apos2[k]*aoff[j];
+	      }
+	    }
+	    y[i]-=apos2[k]*yk;
+	  }
+	}
+	for(i=0,apos2=a;i<n;i++,apos2+=n){
+	  if(i!=k){
+	    apos2[k]*=-aoff[k];
+	  }
+	}
+      }
+    }
+  }
+  if(*jf!=0){
+    *d=0.0;
+  } else {
+    for(k=n;k-->0;){
+      int ki=iw[k];
+      if(k!=ki){
+	int i;
+	double *apos = a;
+	for(i=0;i<n;i++,apos+=n){
+	  double t=apos[k];
+	  apos[k]=apos[ki];
+	  apos[ki]=t;
+	}
+      }
+    }
+  }
+}
Index: trunk/FACT++/pal/palDmoon.c
===================================================================
--- trunk/FACT++/pal/palDmoon.c	(revision 18347)
+++ trunk/FACT++/pal/palDmoon.c	(revision 18347)
@@ -0,0 +1,573 @@
+/*
+*+
+*  Name:
+*     palDmoon
+
+*  Purpose:
+*     Approximate geocentric position and velocity of the Moon
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palDmoon( double date, double pv[6] );
+
+*  Arguments:
+*     date = double (Given)
+*        TDB as a Modified Julian Date (JD-2400000.5)
+*     pv = double [6] (Returned)
+*        Moon x,y,z,xdot,ydot,zdot, mean equator and
+*        equinox of date (AU, AU/s)
+
+*  Description:
+*      Calculate the approximate geocentric position of the Moon
+*      using a full implementation of the algorithm published by
+*      Meeus (l'Astronomie, June 1984, p348).
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Meeus quotes accuracies of 10 arcsec in longitude, 3 arcsec in
+*       latitude and 0.2 arcsec in HP (equivalent to about 20 km in
+*       distance).  Comparison with JPL DE200 over the interval
+*       1960-2025 gives RMS errors of 3.7 arcsec and 83 mas/hour in
+*       longitude, 2.3 arcsec and 48 mas/hour in latitude, 11 km
+*       and 81 mm/s in distance.  The maximum errors over the same
+*       interval are 18 arcsec and 0.50 arcsec/hour in longitude,
+*       11 arcsec and 0.24 arcsec/hour in latitude, 40 km and 0.29 m/s
+*       in distance.
+*     - The original algorithm is expressed in terms of the obsolete
+*       timescale Ephemeris Time.  Either TDB or TT can be used, but
+*       not UT without incurring significant errors (30 arcsec at
+*       the present time) due to the Moon's 0.5 arcsec/sec movement.
+*     - The algorithm is based on pre IAU 1976 standards.  However,
+*       the result has been moved onto the new (FK5) equinox, an
+*       adjustment which is in any case much smaller than the
+*       intrinsic accuracy of the procedure.
+*     - Velocity is obtained by a complete analytical differentiation
+*       of the Meeus model.
+
+*  History:
+*     2012-03-07 (TIMJ):
+*        Initial version based on a direct port of the SLA/F code.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1998 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+#include "palmac.h"
+
+/* Autoconf can give us -DPIC */
+#undef PIC
+
+void palDmoon( double date, double pv[6] ) {
+
+  /*  Seconds per Julian century (86400*36525) */
+  const double CJ = 3155760000.0;
+
+  /*  Julian epoch of B1950 */
+  const double B1950 = 1949.9997904423;
+
+  /*  Earth equatorial radius in AU ( = 6378.137 / 149597870 ) */
+  const double ERADAU=4.2635212653763e-5;
+
+  double T,THETA,SINOM,COSOM,DOMCOM,WA,DWA,WB,DWB,WOM,
+    DWOM,SINWOM,COSWOM,V,DV,COEFF,EMN,EMPN,DN,FN,EN,
+    DEN,DTHETA,FTHETA,EL,DEL,B,DB,BF,DBF,P,DP,SP,R,
+    DR,X,Y,Z,XD,YD,ZD,SEL,CEL,SB,CB,RCB,RBD,W,EPJ,
+    EQCOR,EPS,SINEPS,COSEPS,ES,EC;
+  double ELP, DELP;
+  double EM, DEM, EMP, DEMP, D, DD, F, DF, OM, DOM, E, DESQ, ESQ, DE;
+  int N,I;
+
+  /*
+   *  Coefficients for fundamental arguments
+   *
+   *   at J1900:  T**0, T**1, T**2, T**3
+   *   at epoch:  T**0, T**1
+   *
+   *  Units are degrees for position and Julian centuries for time
+   *
+   */
+
+  /*  Moon's mean longitude */
+  const double ELP0=270.434164;
+  const double ELP1=481267.8831;
+  const double ELP2=-0.001133;
+  const double ELP3=0.0000019;
+
+  /*  Sun's mean anomaly */
+  const double EM0=358.475833;
+  const double EM1=35999.0498;
+  const double EM2=-0.000150;
+  const double EM3=-0.0000033;
+
+  /*  Moon's mean anomaly */
+  const double EMP0=296.104608;
+  const double EMP1=477198.8491;
+  const double EMP2=0.009192;
+  const double EMP3=0.0000144;
+
+  /*  Moon's mean elongation */
+  const double D0=350.737486;
+  const double D1=445267.1142;
+  const double D2=-0.001436;
+  const double D3=0.0000019;
+
+  /*  Mean distance of the Moon from its ascending node */
+  const double F0=11.250889;
+  const double F1=483202.0251;
+  const double F2=-0.003211;
+  const double F3=-0.0000003;
+
+  /*  Longitude of the Moon's ascending node */
+  const double OM0=259.183275;
+  const double OM1=-1934.1420;
+  const double OM2=0.002078;
+  const double OM3=0.0000022;
+
+  /*  Coefficients for (dimensionless) E factor */
+  const double E1=-0.002495;
+  const double E2=-0.00000752;
+
+  /*  Coefficients for periodic variations etc */
+  const double PAC=0.000233;
+  const double PA0=51.2;
+  const double PA1=20.2;
+  const double PBC=-0.001778;
+  const double PCC=0.000817;
+  const double PDC=0.002011;
+  const double PEC=0.003964;
+  const double PE0=346.560;
+  const double PE1=132.870;
+  const double PE2=-0.0091731;
+  const double PFC=0.001964;
+  const double PGC=0.002541;
+  const double PHC=0.001964;
+  const double PIC=-0.024691;
+  const double PJC=-0.004328;
+  const double PJ0=275.05;
+  const double PJ1=-2.30;
+  const double CW1=0.0004664;
+  const double CW2=0.0000754;
+
+  /*
+   *  Coefficients for Moon position
+   *
+   *   Tx(N)       = coefficient of L, B or P term (deg)
+   *   ITx(N,1-5)  = coefficients of M, M', D, F, E**n in argument
+   */
+#define NL 50
+#define NB 45
+#define NP 31
+
+  /*
+   *  Longitude
+   */
+  const double TL[NL] = {
+    6.28875,1.274018,.658309,.213616,-.185596,
+    -.114336,.058793,.057212,.05332,.045874,.041024,-.034718,-.030465,
+    .015326,-.012528,-.01098,.010674,.010034,.008548,-.00791,-.006783,
+    .005162,.005,.004049,.003996,.003862,.003665,.002695,.002602,
+    .002396,-.002349,.002249,-.002125,-.002079,.002059,-.001773,
+    -.001595,.00122,-.00111,8.92e-4,-8.11e-4,7.61e-4,7.17e-4,7.04e-4,
+    6.93e-4,5.98e-4,5.5e-4,5.38e-4,5.21e-4,4.86e-4
+  };
+
+  const int ITL[NL][5] = {
+    /* M   M'  D   F   n */
+    { +0, +1, +0, +0, 0 },
+    { +0, -1, +2, +0, 0 },
+    { +0, +0, +2, +0, 0 },
+    { +0, +2, +0, +0, 0 },
+    { +1, +0, +0, +0, 1 },
+    { +0, +0, +0, +2, 0 },
+    { +0, -2, +2, +0, 0 },
+    { -1, -1, +2, +0, 1 },
+    { +0, +1, +2, +0, 0 },
+    { -1, +0, +2, +0, 1 },
+    { -1, +1, +0, +0, 1 },
+    { +0, +0, +1, +0, 0 },
+    { +1, +1, +0, +0, 1 },
+    { +0, +0, +2, -2, 0 },
+    { +0, +1, +0, +2, 0 },
+    { +0, -1, +0, +2, 0 },
+    { +0, -1, +4, +0, 0 },
+    { +0, +3, +0, +0, 0 },
+    { +0, -2, +4, +0, 0 },
+    { +1, -1, +2, +0, 1 },
+    { +1, +0, +2, +0, 1 },
+    { +0, +1, -1, +0, 0 },
+    { +1, +0, +1, +0, 1 },
+    { -1, +1, +2, +0, 1 },
+    { +0, +2, +2, +0, 0 },
+    { +0, +0, +4, +0, 0 },
+    { +0, -3, +2, +0, 0 },
+    { -1, +2, +0, +0, 1 },
+    { +0, +1, -2, -2, 0 },
+    { -1, -2, +2, +0, 1 },
+    { +0, +1, +1, +0, 0 },
+    { -2, +0, +2, +0, 2 },
+    { +1, +2, +0, +0, 1 },
+    { +2, +0, +0, +0, 2 },
+    { -2, -1, +2, +0, 2 },
+    { +0, +1, +2, -2, 0 },
+    { +0, +0, +2, +2, 0 },
+    { -1, -1, +4, +0, 1 },
+    { +0, +2, +0, +2, 0 },
+    { +0, +1, -3, +0, 0 },
+    { +1, +1, +2, +0, 1 },
+    { -1, -2, +4, +0, 1 },
+    { -2, +1, +0, +0, 2 },
+    { -2, +1, -2, +0, 2 },
+    { +1, -2, +2, +0, 1 },
+    { -1, +0, +2, -2, 1 },
+    { +0, +1, +4, +0, 0 },
+    { +0, +4, +0, +0, 0 },
+    { -1, +0, +4, +0, 1 },
+    { +0, +2, -1, +0, 0 }
+  };
+
+  /*
+   *  Latitude
+   */
+  const double TB[NB] = {
+    5.128189,.280606,.277693,.173238,.055413,
+    .046272,.032573,.017198,.009267,.008823,.008247,.004323,.0042,
+    .003372,.002472,.002222,.002072,.001877,.001828,-.001803,-.00175,
+    .00157,-.001487,-.001481,.001417,.00135,.00133,.001106,.00102,
+    8.33e-4,7.81e-4,6.7e-4,6.06e-4,5.97e-4,4.92e-4,4.5e-4,4.39e-4,
+    4.23e-4,4.22e-4,-3.67e-4,-3.53e-4,3.31e-4,3.17e-4,3.06e-4,
+    -2.83e-4
+  };
+
+  const int ITB[NB][5] = {
+    /* M   M'  D   F   n */
+    { +0, +0, +0, +1, 0 },
+    { +0, +1, +0, +1, 0 },
+    { +0, +1, +0, -1, 0 },
+    { +0, +0, +2, -1, 0 },
+    { +0, -1, +2, +1, 0 },
+    { +0, -1, +2, -1, 0 },
+    { +0, +0, +2, +1, 0 },
+    { +0, +2, +0, +1, 0 },
+    { +0, +1, +2, -1, 0 },
+    { +0, +2, +0, -1, 0 },
+    { -1, +0, +2, -1, 1 },
+    { +0, -2, +2, -1, 0 },
+    { +0, +1, +2, +1, 0 },
+    { -1, +0, -2, +1, 1 },
+    { -1, -1, +2, +1, 1 },
+    { -1, +0, +2, +1, 1 },
+    { -1, -1, +2, -1, 1 },
+    { -1, +1, +0, +1, 1 },
+    { +0, -1, +4, -1, 0 },
+    { +1, +0, +0, +1, 1 },
+    { +0, +0, +0, +3, 0 },
+    { -1, +1, +0, -1, 1 },
+    { +0, +0, +1, +1, 0 },
+    { +1, +1, +0, +1, 1 },
+    { -1, -1, +0, +1, 1 },
+    { -1, +0, +0, +1, 1 },
+    { +0, +0, -1, +1, 0 },
+    { +0, +3, +0, +1, 0 },
+    { +0, +0, +4, -1, 0 },
+    { +0, -1, +4, +1, 0 },
+    { +0, +1, +0, -3, 0 },
+    { +0, -2, +4, +1, 0 },
+    { +0, +0, +2, -3, 0 },
+    { +0, +2, +2, -1, 0 },
+    { -1, +1, +2, -1, 1 },
+    { +0, +2, -2, -1, 0 },
+    { +0, +3, +0, -1, 0 },
+    { +0, +2, +2, +1, 0 },
+    { +0, -3, +2, -1, 0 },
+    { +1, -1, +2, +1, 1 },
+    { +1, +0, +2, +1, 1 },
+    { +0, +0, +4, +1, 0 },
+    { -1, +1, +2, +1, 1 },
+    { -2, +0, +2, -1, 2 },
+    { +0, +1, +0, +3, 0 }
+  };
+
+  /*
+   *  Parallax
+   */
+  const double TP[NP] = {
+    .950724,.051818,.009531,.007843,.002824,
+    8.57e-4,5.33e-4,4.01e-4,3.2e-4,-2.71e-4,-2.64e-4,-1.98e-4,1.73e-4,
+    1.67e-4,-1.11e-4,1.03e-4,-8.4e-5,-8.3e-5,7.9e-5,7.2e-5,6.4e-5,
+    -6.3e-5,4.1e-5,3.5e-5,-3.3e-5,-3e-5,-2.9e-5,-2.9e-5,2.6e-5,
+    -2.3e-5,1.9e-5
+  };
+
+  const int ITP[NP][5] = {
+    /* M   M'  D   F   n */
+    { +0, +0, +0, +0, 0 },
+    { +0, +1, +0, +0, 0 },
+    { +0, -1, +2, +0, 0 },
+    { +0, +0, +2, +0, 0 },
+    { +0, +2, +0, +0, 0 },
+    { +0, +1, +2, +0, 0 },
+    { -1, +0, +2, +0, 1 },
+    { -1, -1, +2, +0, 1 },
+    { -1, +1, +0, +0, 1 },
+    { +0, +0, +1, +0, 0 },
+    { +1, +1, +0, +0, 1 },
+    { +0, -1, +0, +2, 0 },
+    { +0, +3, +0, +0, 0 },
+    { +0, -1, +4, +0, 0 },
+    { +1, +0, +0, +0, 1 },
+    { +0, -2, +4, +0, 0 },
+    { +0, +2, -2, +0, 0 },
+    { +1, +0, +2, +0, 1 },
+    { +0, +2, +2, +0, 0 },
+    { +0, +0, +4, +0, 0 },
+    { -1, +1, +2, +0, 1 },
+    { +1, -1, +2, +0, 1 },
+    { +1, +0, +1, +0, 1 },
+    { -1, +2, +0, +0, 1 },
+    { +0, +3, -2, +0, 0 },
+    { +0, +1, +1, +0, 0 },
+    { +0, +0, -2, +2, 0 },
+    { +1, +2, +0, +0, 1 },
+    { -2, +0, +2, +0, 2 },
+    { +0, +1, -2, +2, 0 },
+    { -1, -1, +4, +0, 1 }
+  };
+
+  /*  Centuries since J1900 */
+  T=(date-15019.5)/36525.;
+
+  /*
+   *  Fundamental arguments (radians) and derivatives (radians per
+   *  Julian century) for the current epoch
+   */
+
+  /*  Moon's mean longitude */
+  ELP=PAL__DD2R*fmod(ELP0+(ELP1+(ELP2+ELP3*T)*T)*T,360.);
+  DELP=PAL__DD2R*(ELP1+(2.*ELP2+3*ELP3*T)*T);
+
+  /*  Sun's mean anomaly */
+  EM=PAL__DD2R*fmod(EM0+(EM1+(EM2+EM3*T)*T)*T,360.);
+  DEM=PAL__DD2R*(EM1+(2.*EM2+3*EM3*T)*T);
+
+  /*  Moon's mean anomaly */
+  EMP=PAL__DD2R*fmod(EMP0+(EMP1+(EMP2+EMP3*T)*T)*T,360.);
+  DEMP=PAL__DD2R*(EMP1+(2.*EMP2+3*EMP3*T)*T);
+
+  /*  Moon's mean elongation */
+  D=PAL__DD2R*fmod(D0+(D1+(D2+D3*T)*T)*T,360.);
+  DD=PAL__DD2R*(D1+(2.*D2+3.*D3*T)*T);
+
+  /*  Mean distance of the Moon from its ascending node */
+  F=PAL__DD2R*fmod(F0+(F1+(F2+F3*T)*T)*T,360.);
+  DF=PAL__DD2R*(F1+(2.*F2+3.*F3*T)*T);
+
+  /*  Longitude of the Moon's ascending node */
+  OM=PAL__DD2R*fmod(OM0+(OM1+(OM2+OM3*T)*T)*T,360.);
+  DOM=PAL__DD2R*(OM1+(2.*OM2+3.*OM3*T)*T);
+  SINOM=sin(OM);
+  COSOM=cos(OM);
+  DOMCOM=DOM*COSOM;
+
+  /*  Add the periodic variations */
+  THETA=PAL__DD2R*(PA0+PA1*T);
+  WA=sin(THETA);
+  DWA=PAL__DD2R*PA1*cos(THETA);
+  THETA=PAL__DD2R*(PE0+(PE1+PE2*T)*T);
+  WB=PEC*sin(THETA);
+  DWB=PAL__DD2R*PEC*(PE1+2.*PE2*T)*cos(THETA);
+  ELP=ELP+PAL__DD2R*(PAC*WA+WB+PFC*SINOM);
+  DELP=DELP+PAL__DD2R*(PAC*DWA+DWB+PFC*DOMCOM);
+  EM=EM+PAL__DD2R*PBC*WA;
+  DEM=DEM+PAL__DD2R*PBC*DWA;
+  EMP=EMP+PAL__DD2R*(PCC*WA+WB+PGC*SINOM);
+  DEMP=DEMP+PAL__DD2R*(PCC*DWA+DWB+PGC*DOMCOM);
+  D=D+PAL__DD2R*(PDC*WA+WB+PHC*SINOM);
+  DD=DD+PAL__DD2R*(PDC*DWA+DWB+PHC*DOMCOM);
+  WOM=OM+PAL__DD2R*(PJ0+PJ1*T);
+  DWOM=DOM+PAL__DD2R*PJ1;
+  SINWOM=sin(WOM);
+  COSWOM=cos(WOM);
+  F=F+PAL__DD2R*(WB+PIC*SINOM+PJC*SINWOM);
+  DF=DF+PAL__DD2R*(DWB+PIC*DOMCOM+PJC*DWOM*COSWOM);
+
+  /*  E-factor, and square */
+  E=1.+(E1+E2*T)*T;
+  DE=E1+2.*E2*T;
+  ESQ=E*E;
+  DESQ=2.*E*DE;
+
+  /*
+   *  Series expansions
+   */
+
+  /*  Longitude */
+  V=0.;
+  DV=0.;
+  for (N=NL-1; N>=0; N--) { /* DO N=NL, 1, -1 */
+    COEFF=TL[N];
+    EMN=(double)(ITL[N][0]);
+    EMPN=(double)(ITL[N][1]);
+    DN=(double)(ITL[N][2]);
+    FN=(double)(ITL[N][3]);
+    I=ITL[N][4];
+    if (I == 0) {
+      EN=1.;
+      DEN=0.;
+    } else if (I == 1) {
+      EN=E;
+      DEN=DE;
+    } else {
+      EN=ESQ;
+      DEN=DESQ;
+    }
+    THETA=EMN*EM+EMPN*EMP+DN*D+FN*F;
+    DTHETA=EMN*DEM+EMPN*DEMP+DN*DD+FN*DF;
+    FTHETA=sin(THETA);
+    V=V+COEFF*FTHETA*EN;
+    DV=DV+COEFF*(cos(THETA)*DTHETA*EN+FTHETA*DEN);
+  }
+  EL=ELP+PAL__DD2R*V;
+  DEL=(DELP+PAL__DD2R*DV)/CJ;
+
+  /*  Latitude */
+  V=0.;
+  DV=0.;
+  for (N=NB-1; N>=0; N--) { /* DO N=NB,1,-1 */
+    COEFF=TB[N];
+    EMN=(double)(ITB[N][0]);
+    EMPN=(double)(ITB[N][1]);
+    DN=(double)(ITB[N][2]);
+    FN=(double)(ITB[N][3]);
+    I=ITB[N][4];
+    if (I == 0 ) {
+      EN=1.;
+      DEN=0.;
+    } else if (I == 1) {
+      EN=E;
+      DEN=DE;
+    } else {
+      EN=ESQ;
+      DEN=DESQ;
+    }
+    THETA=EMN*EM+EMPN*EMP+DN*D+FN*F;
+    DTHETA=EMN*DEM+EMPN*DEMP+DN*DD+FN*DF;
+    FTHETA=sin(THETA);
+    V=V+COEFF*FTHETA*EN;
+    DV=DV+COEFF*(cos(THETA)*DTHETA*EN+FTHETA*DEN);
+  }
+  BF=1.-CW1*COSOM-CW2*COSWOM;
+  DBF=CW1*DOM*SINOM+CW2*DWOM*SINWOM;
+  B=PAL__DD2R*V*BF;
+  DB=PAL__DD2R*(DV*BF+V*DBF)/CJ;
+
+  /*  Parallax */
+  V=0.;
+  DV=0.;
+  for (N=NP-1; N>=0; N--) { /* DO N=NP,1,-1 */
+    COEFF=TP[N];
+    EMN=(double)(ITP[N][0]);
+    EMPN=(double)(ITP[N][1]);
+    DN=(double)(ITP[N][2]);
+    FN=(double)(ITP[N][3]);
+    I=ITP[N][4];
+    if (I == 0) {
+      EN=1.;
+      DEN=0.;
+    } else if (I == 1) {
+      EN=E;
+      DEN=DE;
+    } else {
+      EN=ESQ;
+      DEN=DESQ;
+    }
+    THETA=EMN*EM+EMPN*EMP+DN*D+FN*F;
+    DTHETA=EMN*DEM+EMPN*DEMP+DN*DD+FN*DF;
+    FTHETA=cos(THETA);
+    V=V+COEFF*FTHETA*EN;
+    DV=DV+COEFF*(-sin(THETA)*DTHETA*EN+FTHETA*DEN);
+  }
+  P=PAL__DD2R*V;
+  DP=PAL__DD2R*DV/CJ;
+
+  /*
+   *  Transformation into final form
+   */
+
+  /*  Parallax to distance (AU, AU/sec) */
+  SP=sin(P);
+  R=ERADAU/SP;
+  DR=-R*DP*cos(P)/SP;
+
+  /*  Longitude, latitude to x,y,z (AU) */
+  SEL=sin(EL);
+  CEL=cos(EL);
+  SB=sin(B);
+  CB=cos(B);
+  RCB=R*CB;
+  RBD=R*DB;
+  W=RBD*SB-CB*DR;
+  X=RCB*CEL;
+  Y=RCB*SEL;
+  Z=R*SB;
+  XD=-Y*DEL-W*CEL;
+  YD=X*DEL-W*SEL;
+  ZD=RBD*CB+SB*DR;
+
+  /*  Julian centuries since J2000 */
+  T=(date-51544.5)/36525.;
+
+  /*  Fricke equinox correction */
+  EPJ=2000.+T*100.;
+  EQCOR=PAL__DS2R*(0.035+0.00085*(EPJ-B1950));
+
+  /*  Mean obliquity (IAU 1976) */
+  EPS=PAL__DAS2R*(84381.448+(-46.8150+(-0.00059+0.001813*T)*T)*T);
+
+  /*  To the equatorial system, mean of date, FK5 system */
+  SINEPS=sin(EPS);
+  COSEPS=cos(EPS);
+  ES=EQCOR*SINEPS;
+  EC=EQCOR*COSEPS;
+  pv[0]=X-EC*Y+ES*Z;
+  pv[1]=EQCOR*X+Y*COSEPS-Z*SINEPS;
+  pv[2]=Y*SINEPS+Z*COSEPS;
+  pv[3]=XD-EC*YD+ES*ZD;
+  pv[4]=EQCOR*XD+YD*COSEPS-ZD*SINEPS;
+  pv[5]=YD*SINEPS+ZD*COSEPS;
+
+}
Index: trunk/FACT++/pal/palDrange.c
===================================================================
--- trunk/FACT++/pal/palDrange.c	(revision 18347)
+++ trunk/FACT++/pal/palDrange.c	(revision 18347)
@@ -0,0 +1,77 @@
+/*
+*+
+*  Name:
+*     palDrange
+
+*  Purpose:
+*     Normalize angle into range +/- pi
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDrange( double angle )
+
+*  Arguments:
+*     angle = double (Given)
+*        The angle in radians.
+
+*  Description:
+*     The result is "angle" expressed in the range +/- pi. If the
+*     supplied value for "angle" is equal to +/- pi, it is returned
+*     unchanged.
+
+*  Authors:
+*     DSB: David S Berry (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-05-09 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include <math.h>
+
+double palDrange( double angle ){
+   double result = fmod( angle, PAL__D2PI );
+   if( result > PAL__DPI ) {
+      result -= PAL__D2PI;
+   } else if( result < -PAL__DPI ) {
+      result += PAL__D2PI;
+   }
+   return result;
+}
+
Index: trunk/FACT++/pal/palDs2tp.c
===================================================================
--- trunk/FACT++/pal/palDs2tp.c	(revision 18347)
+++ trunk/FACT++/pal/palDs2tp.c	(revision 18347)
@@ -0,0 +1,127 @@
+/*
+*+
+*  Name:
+*     palDs2tp
+
+*  Purpose:
+*     Spherical to tangent plane projection
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDs2tp( double ra, double dec, double raz, double decz,
+*               double *xi, double *eta, int *j );
+
+*  Arguments:
+*     ra = double (Given)
+*        RA spherical coordinate of point to be projected (radians)
+*     dec = double (Given)
+*        Dec spherical coordinate of point to be projected (radians)
+*     raz = double (Given)
+*        RA spherical coordinate of tangent point (radians)
+*     decz = double (Given)
+*        Dec spherical coordinate of tangent point (radians)
+*     xi = double * (Returned)
+*        First rectangular coordinate on tangent plane (radians)
+*     eta = double * (Returned)
+*        Second rectangular coordinate on tangent plane (radians)
+*     j = int * (Returned)
+*        status: 0 = OK, star on tangent plane
+*                1 = error, star too far from axis
+*                2 = error, antistar on tangent plane
+*                3 = error, antistar too far from axis
+
+*  Description:
+*     Projection of spherical coordinates onto tangent plane:
+*     "gnomonic" projection - "standard coordinates"
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include <math.h>
+
+void
+palDs2tp ( double ra, double dec, double raz, double decz,
+           double *xi, double *eta, int *j ) {
+
+  const double TINY = 1.0e-6;
+
+  double cdec;
+  double sdec;
+  double radif;
+  double cdecz;
+  double denom;
+  double sdecz;
+  double cradif;
+  double sradif;
+
+  /*  Trig functions */
+  sdecz = sin(decz);
+  sdec = sin(dec);
+  cdecz = cos(decz);
+  cdec = cos(dec);
+  radif = ra - raz;
+  sradif = sin(radif);
+  cradif = cos(radif);
+
+  /*  Reciprocal of star vector length to tangent plane */
+  denom = sdec * sdecz + cdec * cdecz * cradif;
+
+  /*  Handle vectors too far from axis */
+  if (denom > TINY) {
+    *j = 0;
+  } else if (denom >= 0.) {
+    *j = 1;
+    denom = TINY;
+  } else if (denom > -TINY) {
+    *j = 2;
+    denom = -TINY;
+  } else {
+    *j = 3;
+  }
+
+  /*  Compute tangent plane coordinates (even in dubious cases) */
+  *xi = cdec * sradif / denom;
+  *eta = (sdec * cdecz - cdec * sdecz * cradif) / denom;
+
+  return;
+}
Index: trunk/FACT++/pal/palDt.c
===================================================================
--- trunk/FACT++/pal/palDt.c	(revision 18347)
+++ trunk/FACT++/pal/palDt.c	(revision 18347)
@@ -0,0 +1,125 @@
+/*
+*+
+*  Name:
+*     palDt
+
+*  Purpose:
+*     Estimate the offset between dynamical time and UT
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palDt( double epoch );
+
+*  Arguments:
+*     epoch = double (Given)
+*        Julian epoch (e.g. 1850.0)
+
+*  Returned Value:
+*     palDt = double
+*        Rough estimate of ET-UT (after 1984, TT-UT) at the
+*        given epoch, in seconds.
+
+*  Description:
+*     Estimate the offset between dynamical time and Universal Time
+*     for a given historical epoch.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Depending on the epoch, one of three parabolic approximations
+*       is used:
+*
+*         before 979    Stephenson & Morrison's 390 BC to AD 948 model
+*         979 to 1708   Stephenson & Morrison's 948 to 1600 model
+*         after 1708    McCarthy & Babcock's post-1650 model
+*
+*       The breakpoints are chosen to ensure continuity:  they occur
+*       at places where the adjacent models give the same answer as
+*       each other.
+*     - The accuracy is modest, with errors of up to 20 sec during
+*       the interval since 1650, rising to perhaps 30 min by 1000 BC.
+*       Comparatively accurate values from AD 1600 are tabulated in
+*       the Astronomical Almanac (see section K8 of the 1995 AA).
+*     - The use of double-precision for both argument and result is
+*       purely for compatibility with other SLALIB time routines.
+*     - The models used are based on a lunar tidal acceleration value
+*       of -26.00 arcsec per century.
+*
+*  See Also:
+*     Explanatory Supplement to the Astronomical Almanac,
+*     ed P.K.Seidelmann, University Science Books (1992),
+*     section 2.553, p83.  This contains references to
+*     the Stephenson & Morrison and McCarthy & Babcock
+*     papers.
+
+*  History:
+*     2012-03-08 (TIMJ):
+*        Initial version with documentation from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+double palDt ( double epoch ) {
+
+  double t,w,s;
+
+  /* Centuries since 1800 */
+  t = (epoch - 1800.0) / 100.0;
+
+  /* Select model */
+  if ( epoch >= 1708.185161980887 ) {
+
+    /* Post-1708: use McCarthy & Babcock */
+    w = t - 0.19;
+    s = 5.156 + 13.3066 * w * w;
+
+  } else if ( epoch >= 979.0258204760233 ) {
+
+    /* 978-1708: use Stephenson & Morrison's 948-1600 model */
+    s = 25.5 * t * t;
+
+  } else {
+
+    /* Pre-979: use Stephenson & Morrison's 390 BC to AD 948 model */
+    s = 1360.0 + (320.0 + 44.3*t) * t;
+
+  }
+
+  return s;
+
+}
Index: trunk/FACT++/pal/palDtp2s.c
===================================================================
--- trunk/FACT++/pal/palDtp2s.c	(revision 18347)
+++ trunk/FACT++/pal/palDtp2s.c	(revision 18347)
@@ -0,0 +1,95 @@
+/*
+*+
+*  Name:
+*     palDtp2s
+
+*  Purpose:
+*     Tangent plane to spherical coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDtp2s( double xi, double eta, double raz, double decz,
+*               double *ra, double *dec);
+
+*  Arguments:
+*     xi = double (Given)
+*        First rectangular coordinate on tangent plane (radians)
+*     eta = double (Given)
+*        Second rectangular coordinate on tangent plane (radians)
+*     raz = double (Given)
+*        RA spherical coordinate of tangent point (radians)
+*     decz = double (Given)
+*        Dec spherical coordinate of tangent point (radians)
+*     ra = double * (Returned)
+*        RA spherical coordinate of point to be projected (radians)
+*     dec = double * (Returned)
+*        Dec spherical coordinate of point to be projected (radians)
+
+*  Description:
+*     Transform tangent plane coordinates into spherical.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+#include <math.h>
+
+void
+palDtp2s ( double xi, double eta, double raz, double decz,
+           double *ra, double *dec ) {
+
+  double cdecz;
+  double denom;
+  double sdecz;
+  double d;
+
+  sdecz = sin(decz);
+  cdecz = cos(decz);
+  denom = cdecz - eta * sdecz;
+  d = atan2(xi, denom) + raz;
+  *ra = eraAnp(d);
+  *dec = atan2(sdecz + eta * cdecz, sqrt(xi * xi + denom * denom));
+
+  return;
+}
Index: trunk/FACT++/pal/palDtps2c.c
===================================================================
--- trunk/FACT++/pal/palDtps2c.c	(revision 18347)
+++ trunk/FACT++/pal/palDtps2c.c	(revision 18347)
@@ -0,0 +1,151 @@
+/*
+*+
+*  Name:
+*     palDtps2c
+
+*  Purpose:
+*     Determine RA,Dec of tangent point from coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDtps2c( double xi, double eta, double ra, double dec,
+*                double * raz1, double decz1,
+*                double * raz2, double decz2, int *n);
+
+*  Arguments:
+*     xi = double (Given)
+*        First rectangular coordinate on tangent plane (radians)
+*     eta = double (Given)
+*        Second rectangular coordinate on tangent plane (radians)
+*     ra = double (Given)
+*        RA spherical coordinate of star (radians)
+*     dec = double (Given)
+*        Dec spherical coordinate of star (radians)
+*     raz1 = double * (Returned)
+*        RA spherical coordinate of tangent point, solution 1 (radians)
+*     decz1 = double * (Returned)
+*        Dec spherical coordinate of tangent point, solution 1 (radians)
+*     raz2 = double * (Returned)
+*        RA spherical coordinate of tangent point, solution 2 (radians)
+*     decz2 = double * (Returned)
+*        Dec spherical coordinate of tangent point, solution 2 (radians)
+*     n = int * (Returned)
+*        number of solutions: 0 = no solutions returned (note 2)
+*                             1 = only the first solution is useful (note 3)
+*                             2 = both solutions are useful (note 3)
+
+
+*  Description:
+*     From the tangent plane coordinates of a star of known RA,Dec,
+*     determine the RA,Dec of the tangent point.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The RAZ1 and RAZ2 values are returned in the range 0-2pi.
+*     - Cases where there is no solution can only arise near the poles.
+*       For example, it is clearly impossible for a star at the pole
+*       itself to have a non-zero XI value, and hence it is
+*       meaningless to ask where the tangent point would have to be
+*       to bring about this combination of XI and DEC.
+*     - Also near the poles, cases can arise where there are two useful
+*       solutions.  The argument N indicates whether the second of the
+*       two solutions returned is useful.  N=1 indicates only one useful
+*       solution, the usual case;  under these circumstances, the second
+*       solution corresponds to the "over-the-pole" case, and this is
+*       reflected in the values of RAZ2 and DECZ2 which are returned.
+*     - The DECZ1 and DECZ2 values are returned in the range +/-pi, but
+*       in the usual, non-pole-crossing, case, the range is +/-pi/2.
+*     - This routine is the spherical equivalent of the routine sla_DTPV2C.
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+#include <math.h>
+
+void
+palDtps2c( double xi, double eta, double ra, double dec,
+           double * raz1, double * decz1,
+           double * raz2, double * decz2, int *n) {
+
+  double x2;
+  double y2;
+  double sd;
+  double cd;
+  double sdf;
+  double r2;
+
+  x2 = xi * xi;
+  y2 = eta * eta;
+  sd = sin(dec);
+  cd = cos(dec);
+  sdf = sd * sqrt(x2 + 1. + y2);
+  r2 = cd * cd * (y2 + 1.) - sd * sd * x2;
+  if (r2 >= 0.) {
+    double r;
+    double s;
+    double c;
+
+    r = sqrt(r2);
+    s = sdf - eta * r;
+    c = sdf * eta + r;
+    if (xi == 0. && r == 0.) {
+      r = 1.;
+    }
+    *raz1 = eraAnp(ra - atan2(xi, r));
+    *decz1 = atan2(s, c);
+    r = -r;
+    s = sdf - eta * r;
+    c = sdf * eta + r;
+    *raz2 = eraAnp(ra - atan2(xi, r));
+    *decz2 = atan2(s, c);
+    if (fabs(sdf) < 1.) {
+      *n = 1;
+    } else {
+      *n = 2;
+    }
+  } else {
+    *n = 0;
+  }
+  return;
+}
Index: trunk/FACT++/pal/palDtt.c
===================================================================
--- trunk/FACT++/pal/palDtt.c	(revision 18347)
+++ trunk/FACT++/pal/palDtt.c	(revision 18347)
@@ -0,0 +1,77 @@
+/*
+*+
+*  Name:
+*     palDtt
+
+*  Purpose:
+*     Return offset between UTC and TT
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     dtt = palDtt( double utc );
+
+*  Arguments:
+*     utc = double (Given)
+*        UTC date as a modified JD (JD-2400000.5)
+
+*  Returned Value:
+*     dtt = double
+*        TT-UTC in seconds
+
+*  Description:
+*     Increment to be applied to Coordinated Universal Time UTC to give
+*     Terrestrial Time TT (formerly Ephemeris Time ET)
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     PTW: Patrick T. Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Consider a comprehensive upgrade to use the time transformations in SOFA's time
+*       cookbook:  http://www.iausofa.org/sofa_ts_c.pdf.
+*     - See eraDat for a description of error conditions when calling this function
+*       with a time outside of the UTC range. This behaviour differs from slaDtt.
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+double palDtt( double utc ) {
+  return 32.184 + palDat( utc );
+}
Index: trunk/FACT++/pal/palEcleq.c
===================================================================
--- trunk/FACT++/pal/palEcleq.c	(revision 18347)
+++ trunk/FACT++/pal/palEcleq.c	(revision 18347)
@@ -0,0 +1,97 @@
+/*
+*+
+*  Name:
+*     palEcleq
+
+*  Purpose:
+*     Transform from ecliptic coordinates to J2000.0 equatorial coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEcleq ( double dl, double db, double date,
+*                     double *dr, double *dd );
+
+*  Arguments:
+*     dl = double (Given)
+*        Ecliptic longitude (mean of date, IAU 1980 theory, radians)
+*     db = double (Given)
+*        Ecliptic latitude (mean of date, IAU 1980 theory, radians)
+*     date = double (Given)
+*        TT as Modified Julian Date (JD-2400000.5). The difference
+*        between TT and TDB is of the order of a millisecond or two
+*        (i.e. about 0.02 arc-seconds).
+*     dr = double * (Returned)
+*        J2000.0 mean RA (radians)
+*     dd = double * (Returned)
+*        J2000.0 mean Dec (Radians)
+
+*  Description:
+*     Transform from ecliptic coordinate to J2000.0 equatorial coordinates.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (Cornell University)
+*     {enter_new_authors_here}
+
+*  History:
+*     2014-11-18 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2014 Cornell University
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palEcleq ( double dl, double db, double date, double *dr, double *dd ) {
+  double v1[3], v2[3];
+  double rmat[3][3];
+
+  /* Spherical to Cartesian */
+  eraS2c( dl, db, v1 );
+
+  /* Ecliptic to equatorial */
+  palEcmat( date, rmat );
+  eraTrxp( rmat, v1, v2 );
+
+  /* Mean of date to J2000 */
+  palPrec( 2000.0, palEpj(date), rmat );
+  eraTrxp( rmat, v2, v1 );
+
+  /* Cartesian to spherical */
+  eraC2s( v1, dr, dd );
+
+  /* Express in conventional range */
+  *dr = eraAnp( *dr );
+  *dd = palDrange( *dd );
+}
Index: trunk/FACT++/pal/palEcmat.c
===================================================================
--- trunk/FACT++/pal/palEcmat.c	(revision 18347)
+++ trunk/FACT++/pal/palEcmat.c	(revision 18347)
@@ -0,0 +1,82 @@
+/*
+*+
+*  Name:
+*     palEcmat
+
+*  Purpose:
+*     Form the equatorial to ecliptic rotation matrix - IAU 2006
+*     precession model.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palEcmat( double date, double rmat[3][3] )
+
+*  Arguments:
+*     date = double (Given)
+*        TT as Modified Julian Date (JD-2400000.5). The difference
+*        between TT and TDB is of the order of a millisecond or two
+*        (i.e. about 0.02 arc-seconds).
+*     rmat = double[3][3] (Returned)
+*        Rotation matrix
+
+*  Description:
+*     The equatorial to ecliptic rotation matrix is found and returned.
+*     The matrix is in the sense   V(ecl)  =  RMAT * V(equ);  the
+*     equator, equinox and ecliptic are mean of date.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-10 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palEcmat( double date, double rmat[3][3] ) {
+
+/* Mean obliquity (the angle between the ecliptic and mean equator of
+   date). */
+   double eps0 = eraObl06( PAL__MJD0, date );
+
+/* Matrix */
+   palDeuler( "X", eps0, 0.0, 0.0, rmat );
+
+}
Index: trunk/FACT++/pal/palEl2ue.c
===================================================================
--- trunk/FACT++/pal/palEl2ue.c	(revision 18347)
+++ trunk/FACT++/pal/palEl2ue.c	(revision 18347)
@@ -0,0 +1,351 @@
+/*
+*+
+*  Name:
+*     palEl2ue
+
+*  Purpose:
+*     Transform conventional elements into "universal" form
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEl2ue ( double date, int jform, double epoch, double orbinc,
+*                     double anode, double perih, double aorq, double e,
+*                     double aorl, double dm, double u[13], int *jstat );
+
+*  Arguments:
+*     date = double (Given)
+*        Epoch (TT MJD) of osculation (Note 3)
+*     jform = int (Given)
+*        Element set actually returned (1-3; Note 6)
+*     epoch = double (Given)
+*        Epoch of elements (TT MJD)
+*     orbinc = double (Given)
+*        inclination (radians)
+*     anode = double (Given)
+*        longitude of the ascending node (radians)
+*     perih = double (Given)
+*        longitude or argument of perihelion (radians)
+*     aorq = double (Given)
+*        mean distance or perihelion distance (AU)
+*     e = double (Given)
+*        eccentricity
+*     aorl = double (Given)
+*        mean anomaly or longitude (radians, JFORM=1,2 only)
+*     dm = double (Given)
+*        daily motion (radians, JFORM=1 only)
+*     u = double [13] (Returned)
+*        Universal orbital elements (Note 1)
+*          -   (0)  combined mass (M+m)
+*          -   (1)  total energy of the orbit (alpha)
+*          -   (2)  reference (osculating) epoch (t0)
+*          - (3-5)  position at reference epoch (r0)
+*          - (6-8)  velocity at reference epoch (v0)
+*          -   (9)  heliocentric distance at reference epoch
+*          -  (10)  r0.v0
+*          -  (11)  date (t)
+*          -  (12)  universal eccentric anomaly (psi) of date, approx
+*     jstat = int * (Returned)
+*        status:  0 = OK
+*              - -1 = illegal JFORM
+*              - -2 = illegal E
+*              - -3 = illegal AORQ
+*              - -4 = illegal DM
+*              - -5 = numerical error
+
+*  Description:
+*      Transform conventional osculating elements into "universal" form.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - The companion routine is palUe2pv.  This takes the set of numbers
+*       that the present routine outputs and uses them to derive the
+*       object's position and velocity.  A single prediction requires one
+*       call to the present routine followed by one call to palUe2pv;
+*       for convenience, the two calls are packaged as the routine
+*       palPlanel.  Multiple predictions may be made by again calling the
+*       present routine once, but then calling palUe2pv multiple times,
+*       which is faster than multiple calls to palPlanel.
+*     - DATE is the epoch of osculation.  It is in the TT timescale
+*       (formerly Ephemeris Time, ET) and is a Modified Julian Date
+*       (JD-2400000.5).
+*     - The supplied orbital elements are with respect to the J2000
+*       ecliptic and equinox.  The position and velocity parameters
+*       returned in the array U are with respect to the mean equator and
+*       equinox of epoch J2000, and are for the perihelion prior to the
+*       specified epoch.
+*     - The universal elements returned in the array U are in canonical
+*       units (solar masses, AU and canonical days).
+*     - Three different element-format options are available:
+*
+*       Option JFORM=1, suitable for the major planets:
+*
+*       EPOCH  = epoch of elements (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = longitude of perihelion, curly pi (radians)
+*       AORQ   = mean distance, a (AU)
+*       E      = eccentricity, e (range 0 to <1)
+*       AORL   = mean longitude L (radians)
+*       DM     = daily motion (radians)
+*
+*       Option JFORM=2, suitable for minor planets:
+*
+*       EPOCH  = epoch of elements (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = argument of perihelion, little omega (radians)
+*       AORQ   = mean distance, a (AU)
+*       E      = eccentricity, e (range 0 to <1)
+*       AORL   = mean anomaly M (radians)
+*
+*       Option JFORM=3, suitable for comets:
+*
+*       EPOCH  = epoch of perihelion (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = argument of perihelion, little omega (radians)
+*       AORQ   = perihelion distance, q (AU)
+*       E      = eccentricity, e (range 0 to 10)
+*
+*     - Unused elements (DM for JFORM=2, AORL and DM for JFORM=3) are
+*       not accessed.
+*     - The algorithm was originally adapted from the EPHSLA program of
+*       D.H.P.Jones (private communication, 1996).  The method is based
+*       on Stumpff's Universal Variables.
+*
+*  See Also:
+*     Everhart & Pitkin, Am.J.Phys. 51, 712 (1983).
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version taken directly from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void palEl2ue ( double date, int jform, double epoch, double orbinc,
+                double anode, double perih, double aorq, double e,
+                double aorl, double dm, double u[13], int *jstat ) {
+
+  /*  Sin and cos of J2000 mean obliquity (IAU 1976) */
+  const double SE=0.3977771559319137;
+  const double CE=0.9174820620691818;
+
+  int J;
+
+  double PHT,ARGPH,Q,W,CM,ALPHA,PHS,SW,CW,SI,CI,SO,CO,
+    X,Y,Z,PX,PY,PZ,VX,VY,VZ,DT,FC,FP,PSI,
+    UL[13],PV[6];
+
+  /*  Validate arguments. */
+  if (jform < 1 || jform > 3) {
+    *jstat = -1;
+    return;
+  }
+  if (e < 0.0 || e > 10.0 || (e >= 1.0 && jform != 3)) {
+    *jstat = -2;
+    return;
+  }
+  if (aorq <= 0.0) {
+    *jstat = -3;
+    return;
+  }
+  if (jform == 1 && dm <= 0.0) {
+    *jstat = -4;
+    return;
+  }
+
+  /*
+   *  Transform elements into standard form:
+   *
+   *  PHT   = epoch of perihelion passage
+   *  ARGPH = argument of perihelion (little omega)
+   *  Q     = perihelion distance (q)
+   *  CM    = combined mass, M+m (mu)
+   */
+
+  if (jform == 1) {
+
+    /*     Major planet. */
+    PHT = epoch-(aorl-perih)/dm;
+    ARGPH = perih-anode;
+    Q = aorq*(1.0-e);
+    W = dm/PAL__GCON;
+    CM = W*W*aorq*aorq*aorq;
+
+  } else if (jform == 2) {
+
+    /*     Minor planet. */
+    PHT = epoch-aorl*sqrt(aorq*aorq*aorq)/PAL__GCON;
+    ARGPH = perih;
+    Q = aorq*(1.0-e);
+    CM = 1.0;
+
+  } else {
+
+    /*     Comet. */
+    PHT = epoch;
+    ARGPH = perih;
+    Q = aorq;
+    CM = 1.0;
+
+  }
+
+  /*  The universal variable alpha.  This is proportional to the total
+   *  energy of the orbit:  -ve for an ellipse, zero for a parabola,
+   *  +ve for a hyperbola. */
+
+  ALPHA = CM*(e-1.0)/Q;
+
+  /*  Speed at perihelion. */
+
+  PHS = sqrt(ALPHA+2.0*CM/Q);
+
+  /*  In a Cartesian coordinate system which has the x-axis pointing
+   *  to perihelion and the z-axis normal to the orbit (such that the
+   *  object orbits counter-clockwise as seen from +ve z), the
+   *  perihelion position and velocity vectors are:
+   *
+   *    position   [Q,0,0]
+   *    velocity   [0,PHS,0]
+   *
+   *  To express the results in J2000 equatorial coordinates we make a
+   *  series of four rotations of the Cartesian axes:
+   *
+   *           axis      Euler angle
+   *
+   *     1      z        argument of perihelion (little omega)
+   *     2      x        inclination (i)
+   *     3      z        longitude of the ascending node (big omega)
+   *     4      x        J2000 obliquity (epsilon)
+   *
+   *  In each case the rotation is clockwise as seen from the +ve end of
+   *  the axis concerned.
+   */
+
+  /*  Functions of the Euler angles. */
+  SW = sin(ARGPH);
+  CW = cos(ARGPH);
+  SI = sin(orbinc);
+  CI = cos(orbinc);
+  SO = sin(anode);
+  CO = cos(anode);
+
+  /*  Position at perihelion (AU). */
+  X = Q*CW;
+  Y = Q*SW;
+  Z = Y*SI;
+  Y = Y*CI;
+  PX = X*CO-Y*SO;
+  Y = X*SO+Y*CO;
+  PY = Y*CE-Z*SE;
+  PZ = Y*SE+Z*CE;
+
+  /*  Velocity at perihelion (AU per canonical day). */
+  X = -PHS*SW;
+  Y = PHS*CW;
+  Z = Y*SI;
+  Y = Y*CI;
+  VX = X*CO-Y*SO;
+  Y = X*SO+Y*CO;
+  VY = Y*CE-Z*SE;
+  VZ = Y*SE+Z*CE;
+
+  /*  Time from perihelion to date (in Canonical Days: a canonical day
+   *  is 58.1324409... days, defined as 1/PAL__GCON). */
+
+  DT = (date-PHT)*PAL__GCON;
+
+  /*  First approximation to the Universal Eccentric Anomaly, PSI,
+   *  based on the circle (FC) and parabola (FP) values. */
+
+  FC = DT/Q;
+  W = pow(3.0*DT+sqrt(9.0*DT*DT+8.0*Q*Q*Q), 1.0/3.0);
+  FP = W-2.0*Q/W;
+  PSI = (1.0-e)*FC+e*FP;
+
+  /*  Assemble local copy of element set. */
+  UL[0] = CM;
+  UL[1] = ALPHA;
+  UL[2] = PHT;
+  UL[3] = PX;
+  UL[4] = PY;
+  UL[5] = PZ;
+  UL[6] = VX;
+  UL[7] = VY;
+  UL[8] = VZ;
+  UL[9] = Q;
+  UL[10] = 0.0;
+  UL[11] = date;
+  UL[12] = PSI;
+
+  /*  Predict position+velocity at epoch of osculation. */
+  palUe2pv( date, UL, PV, &J );
+  if (J != 0) {
+    *jstat = -5;
+    return;
+  }
+
+  /*  Convert back to universal elements. */
+  palPv2ue( PV, date, CM-1.0, u, &J );
+  if (J != 0) {
+    *jstat = -5;
+    return;
+  }
+
+  /*  OK exit. */
+  *jstat = 0;
+
+}
Index: trunk/FACT++/pal/palEpco.c
===================================================================
--- trunk/FACT++/pal/palEpco.c	(revision 18347)
+++ trunk/FACT++/pal/palEpco.c	(revision 18347)
@@ -0,0 +1,102 @@
+/*
+*+
+*  Name:
+*     palEpco
+
+*  Purpose:
+*     Convert an epoch into the appropriate form - 'B' or 'J'
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palEpco( char k0, char k, double e );
+
+*  Arguments:
+*     k0 = char (Given)
+*       Form of result: 'B'=Besselian, 'J'=Julian
+*     k = char (Given)
+*       Form of given epoch: 'B' or 'J'.
+
+*  Description:
+*     Converts a Besselian or Julian epoch to a Julian or Besselian
+*     epoch.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The result is always either equal to or very close to
+*       the given epoch E.  The routine is required only in
+*       applications where punctilious treatment of heterogeneous
+*       mixtures of star positions is necessary.
+*     - k and k0 are case insensitive. This differes slightly from the
+*       Fortran SLA implementation.
+*     - k and k0 are not validated. They are interpreted as follows:
+*       o If k0 and k are the same the result is e
+*       o If k0 is 'b' or 'B' and k isn't the conversion is J to B.
+*       o In all other cases, the conversion is B to J.
+
+*  History:
+*     2012-03-01 (TIMJ):
+*        Initial version. Documentation from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+*     USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+#include <ctype.h>
+
+double palEpco( char k0, char k, double e ) {
+
+  double new_epoch = 0.0;
+  double djm;
+  double djm0;
+
+  /* Use upper case */
+  k0 = toupper( k0 );
+  k = toupper( k );
+
+  if (k == k0) {
+    new_epoch = e;
+  } else if (k0 == 'B') {
+    eraEpj2jd( e, &djm0, &djm );
+    new_epoch = eraEpb( djm0, djm );
+  } else {
+    eraEpb2jd( e, &djm0, &djm );
+    new_epoch = eraEpj( djm0, djm );
+  }
+  return new_epoch;
+}
Index: trunk/FACT++/pal/palEpv.c
===================================================================
--- trunk/FACT++/pal/palEpv.c	(revision 18347)
+++ trunk/FACT++/pal/palEpv.c	(revision 18347)
@@ -0,0 +1,96 @@
+/*
+*+
+*  Name:
+*     palEpv
+
+*  Purpose:
+*     Earth position and velocity with respect to the BCRS
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEpv( double date, double ph[3], double vh[3],
+*                  double pb[3], double vb[3] );
+
+*  Arguments:
+*     date = double (Given)
+*        Date, TDB Modified Julian Date (JD-2400000.5)
+*     ph = double [3] (Returned)
+*        Heliocentric Earth position (AU)
+*     vh = double [3] (Returned)
+*        Heliocentric Earth velocity (AU/day)
+*     pb = double [3] (Returned)
+*        Barycentric Earth position (AU)
+*     vb = double [3] (Returned)
+*        Barycentric Earth velocity (AU/day)
+
+*  Description:
+*     Earth position and velocity, heliocentric and barycentric, with
+*     respect to the Barycentric Celestial Reference System.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - See eraEpv00 for details on accuracy
+*     - Note that the status argument from eraEpv00 is ignored
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library
+*        but now mainly calls SOFA routines.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "palmac.h"
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palEpv( double date, double ph[3], double vh[3],
+             double pb[3], double vb[3] ) {
+
+  int i;
+  double pvh[2][3];
+  double pvb[2][3];
+
+  eraEpv00( PAL__MJD0, date, pvh, pvb );
+
+  /* Copy into output arrays */
+  for (i=0; i<3; i++) {
+    ph[i] = pvh[0][i];
+    vh[i] = pvh[1][i];
+    pb[i] = pvb[0][i];
+    vb[i] = pvb[1][i];
+  }
+
+}
Index: trunk/FACT++/pal/palEqecl.c
===================================================================
--- trunk/FACT++/pal/palEqecl.c	(revision 18347)
+++ trunk/FACT++/pal/palEqecl.c	(revision 18347)
@@ -0,0 +1,97 @@
+/*
+*+
+*  Name:
+*     palEqecl
+
+*  Purpose:
+*     Transform from J2000.0 equatorial coordinates to ecliptic coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEqecl( double dr, double dd, double date,
+*                    double *dl, double *db);
+
+*  Arguments:
+*     dr = double (Given)
+*        J2000.0 mean RA (radians)
+*     dd = double (Given)
+*        J2000.0 mean Dec (Radians)
+*     date = double (Given)
+*        TT as Modified Julian Date (JD-2400000.5). The difference
+*        between TT and TDB is of the order of a millisecond or two
+*        (i.e. about 0.02 arc-seconds).
+*     dl = double * (Returned)
+*        Ecliptic longitude (mean of date, IAU 1980 theory, radians)
+*     db = double * (Returned)
+*        Ecliptic latitude (mean of date, IAU 1980 theory, radians)
+
+*  Description:
+*     Transform from J2000.0 equatorial coordinates to ecliptic coordinates.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palEqecl ( double dr, double dd, double date, double *dl, double *db ) {
+  double v1[3], v2[3];
+  double rmat[3][3];
+
+  /* Spherical to Cartesian */
+  eraS2c( dr, dd, v1 );
+
+  /* Mean J2000 to mean of date */
+  palPrec( 2000.0, palEpj(date), rmat );
+  eraRxp( rmat, v1, v2 );
+
+  /* Equatorial to ecliptic */
+  palEcmat( date, rmat );
+  eraRxp( rmat, v2, v1 );
+
+  /* Cartesian to spherical */
+  eraC2s( v1, dl, db );
+
+  /* Express in conventional range */
+  *dl = eraAnp( *dl );
+  *db = palDrange( *db );
+}
Index: trunk/FACT++/pal/palEqgal.c
===================================================================
--- trunk/FACT++/pal/palEqgal.c	(revision 18347)
+++ trunk/FACT++/pal/palEqgal.c	(revision 18347)
@@ -0,0 +1,118 @@
+/*
+*+
+*  Name:
+*     palEqgal
+
+*  Purpose:
+*     Convert from J2000.0 equatorial coordinates to Galactic
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEqgal ( double dr, double dd, double *dl, double *db );
+
+*  Arguments:
+*     dr = double (Given)
+*       J2000.0 RA (radians)
+*     dd = double (Given)
+*       J2000.0 Dec (radians
+*     dl = double * (Returned)
+*       Galactic longitude (radians).
+*     db = double * (Returned)
+*       Galactic latitude (radians).
+
+*  Description:
+*     Transformation from J2000.0 equatorial coordinates
+*     to IAU 1958 galactic coordinates.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     The equatorial coordinates are J2000.0.  Use the routine
+*     palGe50 if conversion to B1950.0 'FK4' coordinates is
+*     required.
+
+*  See Also:
+*     Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1998 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palEqgal ( double dr, double dd, double *dl, double *db ) {
+
+  double v1[3];
+  double v2[3];
+
+/*
+*  L2,B2 system of galactic coordinates
+*
+*  P = 192.25       RA of galactic north pole (mean B1950.0)
+*  Q =  62.6        inclination of galactic to mean B1950.0 equator
+*  R =  33          longitude of ascending node
+*
+*  P,Q,R are degrees
+*
+*  Equatorial to galactic rotation matrix (J2000.0), obtained by
+*  applying the standard FK4 to FK5 transformation, for zero proper
+*  motion in FK5, to the columns of the B1950 equatorial to
+*  galactic rotation matrix:
+*/
+  double rmat[3][3] = {
+    { -0.054875539726,-0.873437108010,-0.483834985808 },
+    { +0.494109453312,-0.444829589425,+0.746982251810 },
+    { -0.867666135858,-0.198076386122,+0.455983795705 }
+  };
+
+  /* Spherical to Cartesian */
+  eraS2c( dr, dd, v1 );
+
+  /* Equatorial to Galactic */
+  eraRxp( rmat, v1, v2 );
+
+  /* Cartesian to spherical */
+  eraC2s( v2, dl, db );
+
+  /* Express in conventional ranges */
+  *dl = eraAnp( *dl );
+  *db = eraAnpm( *db );
+
+}
Index: trunk/FACT++/pal/palEtrms.c
===================================================================
--- trunk/FACT++/pal/palEtrms.c	(revision 18347)
+++ trunk/FACT++/pal/palEtrms.c	(revision 18347)
@@ -0,0 +1,106 @@
+/*
+*+
+*  Name:
+*     palEtrms
+
+*  Purpose:
+*     Compute the E-terms vector
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEtrms ( double ep, double ev[3] );
+
+*  Arguments:
+*     ep = double (Given)
+*        Besselian epoch
+*     ev = double [3] (Returned)
+*        E-terms as (dx,dy,dz)
+
+*  Description:
+*     Computes the E-terms (elliptic component of annual aberration)
+*     vector.
+*
+*     Note the use of the J2000 aberration constant (20.49552 arcsec).
+*     This is a reflection of the fact that the E-terms embodied in
+*     existing star catalogues were computed from a variety of
+*     aberration constants.  Rather than adopting one of the old
+*     constants the latest value is used here.
+*
+*  See also:
+*     - Smith, C.A. et al., 1989.  Astr.J. 97, 265.
+*     - Yallop, B.D. et al., 1989.  Astr.J. 97, 274.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-12 (TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+
+void palEtrms ( double ep, double ev[3] ) {
+
+  /* Use the J2000 aberration constant */
+  const double ABCONST = 20.49552;
+
+  double t, e, e0, p, ek, cp;
+
+  /*  Julian centuries since B1950 */
+  t = (ep - 1950.) * .0100002135903;
+
+  /*  Eccentricity */
+  e = .01673011 - (t * 1.26e-7 + 4.193e-5) * t;
+
+  /*  Mean obliquity */
+  e0 = (84404.836 - ((t * .00181 + .00319) * t + 46.8495) * t) *
+    PAL__DAS2R;
+
+  /*  Mean longitude of perihelion */
+  p = (((t * .012 + 1.65) * t + 6190.67) * t + 1015489.951) *
+    PAL__DAS2R;
+
+  /*  E-terms */
+  ek = e * ABCONST * PAL__DAS2R;
+  cp = cos(p);
+  ev[0] = ek * sin(p);
+  ev[1] = -ek * cp * cos(e0);
+  ev[2] = -ek * cp * sin(e0);
+
+}
Index: trunk/FACT++/pal/palEvp.c
===================================================================
--- trunk/FACT++/pal/palEvp.c	(revision 18347)
+++ trunk/FACT++/pal/palEvp.c	(revision 18347)
@@ -0,0 +1,110 @@
+/*
+*+
+*  Name:
+*     palEvp
+
+*  Purpose:
+*     Returns the barycentric and heliocentric velocity and position of the
+*     Earth.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palEvp( double date, double deqx, double dvb[3], double dpb[3],
+*                  double dvh[3], double dph[3] )
+
+*  Arguments:
+*     date = double (Given)
+*        TDB (loosely ET) as a Modified Julian Date (JD-2400000.5)
+*     deqx = double (Given)
+*        Julian epoch (e.g. 2000.0) of mean equator and equinox of the
+*        vectors returned.  If deqx <= 0.0, all vectors are referred to the
+*        mean equator and equinox (FK5) of epoch date.
+*     dvb = double[3] (Returned)
+*        Barycentric velocity (AU/s, AU)
+*     dpb = double[3] (Returned)
+*        Barycentric position (AU/s, AU)
+*     dvh = double[3] (Returned)
+*        heliocentric velocity (AU/s, AU)
+*     dph = double[3] (Returned)
+*        Heliocentric position (AU/s, AU)
+
+*  Description:
+*     Returns the barycentric and heliocentric velocity and position of the
+*     Earth at a given epoch, given with respect to a specified equinox.
+*     For information about accuracy, see the function eraEpv00.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (PTW):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palEvp( double date, double deqx, double dvb[3], double dpb[3],
+             double dvh[3], double dph[3] ){
+
+/* Local Variables; */
+   int i;
+   double pvh[2][3], pvb[2][3], d1, d2, r[3][3];
+
+/* BCRS PV-vectors. */
+   eraEpv00 ( 2400000.5, date, pvh, pvb );
+
+/* Was precession to another equinox requested? */
+   if ( deqx > 0.0 ) {
+
+/* Yes: compute precession matrix from J2000.0 to deqx. */
+      eraEpj2jd ( deqx, &d1, &d2 );
+      eraPmat06 ( d1, d2, r );
+
+/* Rotate the PV-vectors. */
+      eraRxpv ( r, pvh, pvh );
+      eraRxpv ( r, pvb, pvb );
+   }
+
+/* Return the required vectors. */
+   for ( i = 0; i < 3; i++ ) {
+      dvh[i] = pvh[1][i] / PAL__SPD;
+      dvb[i] = pvb[1][i] / PAL__SPD;
+      dph[i] = pvh[0][i];
+      dpb[i] = pvb[0][i];
+   }
+}
Index: trunk/FACT++/pal/palFk45z.c
===================================================================
--- trunk/FACT++/pal/palFk45z.c	(revision 18347)
+++ trunk/FACT++/pal/palFk45z.c	(revision 18347)
@@ -0,0 +1,186 @@
+/*
+*+
+*  Name:
+*     palFk45z
+
+*  Purpose:
+*     Convert B1950.0 FK4 star data to J2000.0 FK5 assuming zero
+*     proper motion in the FK5 frame
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palFk45z( double r1950, double d1950, double bepoch, double *r2000,
+*               double *d2000 )
+
+*  Arguments:
+*     r1950 = double (Given)
+*        B1950.0 FK4 RA at epoch (radians).
+*     d1950 = double (Given)
+*        B1950.0 FK4 Dec at epoch (radians).
+*     bepoch = double (Given)
+*        Besselian epoch (e.g. 1979.3)
+*     r2000 = double (Returned)
+*        J2000.0 FK5 RA (Radians).
+*     d2000 = double (Returned)
+*        J2000.0 FK5 Dec(Radians).
+
+*  Description:
+*     Convert B1950.0 FK4 star data to J2000.0 FK5 assuming zero
+*     proper motion in the FK5 frame (double precision)
+*
+*     This function converts stars from the Bessel-Newcomb, FK4
+*     system to the IAU 1976, FK5, Fricke system, in such a
+*     way that the FK5 proper motion is zero.  Because such a star
+*     has, in general, a non-zero proper motion in the FK4 system,
+*     the routine requires the epoch at which the position in the
+*     FK4 system was determined.
+*
+*     The method is from Appendix 2 of Ref 1, but using the constants
+*     of Ref 4.
+
+*  Notes:
+*     - The epoch BEPOCH is strictly speaking Besselian, but if a
+*     Julian epoch is supplied the result will be affected only to
+*     a negligible extent.
+*
+*     - Conversion from Besselian epoch 1950.0 to Julian epoch 2000.0
+*     only is provided for.  Conversions involving other epochs will
+*     require use of the appropriate precession, proper motion, and
+*     E-terms routines before and/or after palFk45z is called.
+*
+*     - In the FK4 catalogue the proper motions of stars within 10
+*     degrees of the poles do not embody the differential E-term effect
+*     and should, strictly speaking, be handled in a different manner
+*     from stars outside these regions. However, given the general lack
+*     of homogeneity of the star data available for routine astrometry,
+*     the difficulties of handling positions that may have been
+*     determined from astrometric fields spanning the polar and non-polar
+*     regions, the likelihood that the differential E-terms effect was not
+*     taken into account when allowing for proper motion in past
+*     astrometry, and the undesirability of a discontinuity in the
+*     algorithm, the decision has been made in this routine to include the
+*     effect of differential E-terms on the proper motions for all stars,
+*     whether polar or not.  At epoch 2000, and measuring on the sky rather
+*     than in terms of dRA, the errors resulting from this simplification
+*     are less than 1 milliarcsecond in position and 1 milliarcsecond per
+*     century in proper motion.
+*
+*  References:
+*     - Aoki,S., et al, 1983.  Astron.Astrophys., 128, 263.
+*     - Smith, C.A. et al, 1989.  "The transformation of astrometric
+*       catalog systems to the equinox J2000.0".  Astron.J. 97, 265.
+*     - Yallop, B.D. et al, 1989.  "Transformation of mean star places
+*       from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space".
+*       Astron.J. 97, 274.
+*     - Seidelmann, P.K. (ed), 1992.  "Explanatory Supplement to
+*       the Astronomical Almanac", ISBN 0-935702-68-7.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-10 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1998 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palFk45z( double r1950, double d1950, double bepoch, double *r2000,
+               double *d2000 ){
+
+/* Local Variables: */
+   double w;
+   int i;
+   int j;
+   double r0[3], a1[3], v1[3], v2[6]; /* Position and position+velocity vectors */
+
+
+/* CANONICAL CONSTANTS  (see references) */
+
+/* Vector A. */
+   double a[3] = { -1.62557E-6, -0.31919E-6, -0.13843E-6 };
+
+/* Vectors Adot. */
+   double ad[3] = { 1.245E-3, -1.580E-3, -0.659E-3 };
+
+/* Matrix M (only half of which is needed here). */
+   double em[6][3] = { {0.9999256782, -0.0111820611, -0.0048579477},
+                       {0.0111820610, 0.9999374784, -0.0000271765},
+                       {0.0048579479, -0.0000271474, 0.9999881997},
+                       {-0.000551, -0.238565, 0.435739},
+                       {0.238514, -0.002667, -0.008541},
+                       {-0.435623, 0.012254, 0.002117} };
+
+
+/* Spherical to Cartesian. */
+   eraS2c( r1950, d1950, r0 );
+
+/* Adjust vector A to give zero proper motion in FK5. */
+   w = ( bepoch - 1950.0 )/PAL__PMF;
+   for( i = 0; i < 3; i++ ) {
+      a1[ i ] = a[ i ] + w*ad[ i ];
+   }
+
+/* Remove e-terms. */
+   w = r0[ 0 ]*a1[ 0 ] + r0[ 1 ]*a1[ 1 ] + r0[ 2 ]*a1[ 2 ];
+   for( i = 0; i < 3; i++ ) {
+      v1[ i ] = r0[ i ] - a1[ i ] + w*r0[ i ];
+   }
+
+/* Convert position vector to Fricke system. */
+   for( i = 0; i < 6; i++ ) {
+      w = 0.0;
+      for( j = 0; j < 3; j++ ) {
+         w += em[ i ][ j ]*v1[ j ];
+      }
+      v2[ i ] = w;
+   }
+
+/* Allow for fictitious proper motion in FK4. */
+   w = ( palEpj( palEpb2d( bepoch ) ) - 2000.0 )/PAL__PMF;
+   for( i = 0; i < 3; i++ ) {
+      v2[ i ] += w*v2[ i + 3 ];
+   }
+
+/* Revert to spherical coordinates. */
+   eraC2s( v2, &w, d2000 );
+   *r2000 = eraAnp( w );
+}
+
+
Index: trunk/FACT++/pal/palFk524.c
===================================================================
--- trunk/FACT++/pal/palFk524.c	(revision 18347)
+++ trunk/FACT++/pal/palFk524.c	(revision 18347)
@@ -0,0 +1,259 @@
+/*
+*+
+*  Name:
+*     palFk524
+
+*  Purpose:
+*     Convert J2000.0 FK5 star data to B1950.0 FK4.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palFk524( double r2000, double d2000, double dr2000, double dd2000,
+*               double p2000, double v2000, double *r1950, double *d1950,
+*               double *dr1950, double *dd1950, double *p1950, double *v1950 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 FK5 RA (radians).
+*     d2000 = double (Given)
+*        J2000.0 FK5 Dec (radians).
+*     dr2000 = double (Given)
+*        J2000.0 FK5 RA proper motion (rad/Jul.yr)
+*     dd2000 = double (Given)
+*        J2000.0 FK5 Dec proper motion (rad/Jul.yr)
+*     p2000 = double (Given)
+*        J2000.0 FK5 parallax (arcsec)
+*     v2000 = double (Given)
+*         J2000.0 FK5 radial velocity (km/s, +ve = moving away)
+*     r1950 = double * (Returned)
+*        B1950.0 FK4 RA (radians).
+*     d1950 = double * (Returned)
+*        B1950.0 FK4 Dec (radians).
+*     dr1950 = double * (Returned)
+*        B1950.0 FK4 RA proper motion (rad/Jul.yr)
+*     dd1950 = double * (Returned)
+*        B1950.0 FK4 Dec proper motion (rad/Jul.yr)
+*     p1950 = double * (Returned)
+*        B1950.0 FK4 parallax (arcsec)
+*     v1950 = double * (Returned)
+*         B1950.0 FK4 radial velocity (km/s, +ve = moving away)
+
+*  Description:
+*     This function converts stars from the IAU 1976, FK5, Fricke
+*     system, to the Bessel-Newcomb, FK4 system.  The precepts
+*     of Smith et al (Ref 1) are followed, using the implementation
+*     by Yallop et al (Ref 2) of a matrix method due to Standish.
+*     Kinoshita's development of Andoyer's post-Newcomb precession is
+*     used.  The numerical constants from Seidelmann et al (Ref 3) are
+*     used canonically.
+
+*  Notes:
+*     - The proper motions in RA are dRA/dt rather than
+*     cos(Dec)*dRA/dt, and are per year rather than per century.
+*     - Note that conversion from Julian epoch 2000.0 to Besselian
+*     epoch 1950.0 only is provided for.  Conversions involving
+*     other epochs will require use of the appropriate precession,
+*     proper motion, and E-terms routines before and/or after
+*     FK524 is called.
+*     - In the FK4 catalogue the proper motions of stars within
+*     10 degrees of the poles do not embody the differential
+*     E-term effect and should, strictly speaking, be handled
+*     in a different manner from stars outside these regions.
+*     However, given the general lack of homogeneity of the star
+*     data available for routine astrometry, the difficulties of
+*     handling positions that may have been determined from
+*     astrometric fields spanning the polar and non-polar regions,
+*     the likelihood that the differential E-terms effect was not
+*     taken into account when allowing for proper motion in past
+*     astrometry, and the undesirability of a discontinuity in
+*     the algorithm, the decision has been made in this routine to
+*     include the effect of differential E-terms on the proper
+*     motions for all stars, whether polar or not.  At epoch 2000,
+*     and measuring on the sky rather than in terms of dRA, the
+*     errors resulting from this simplification are less than
+*     1 milliarcsecond in position and 1 milliarcsecond per
+*     century in proper motion.
+*
+*  References:
+*     - Smith, C.A. et al, 1989.  "The transformation of astrometric
+*       catalog systems to the equinox J2000.0".  Astron.J. 97, 265.
+*     - Yallop, B.D. et al, 1989.  "Transformation of mean star places
+*       from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space".
+*       Astron.J. 97, 274.
+*     - Seidelmann, P.K. (ed), 1992.  "Explanatory Supplement to
+*       the Astronomical Almanac", ISBN 0-935702-68-7.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "math.h"
+
+void palFk524( double r2000, double d2000, double dr2000, double dd2000,
+               double p2000, double v2000, double *r1950, double *d1950,
+               double *dr1950, double *dd1950, double *p1950, double *v1950 ){
+
+/* Local Variables; */
+   double r, d, ur, ud, px, rv;
+   double sr, cr, sd, cd, x, y, z, w;
+   double v1[ 6 ], v2[ 6 ];
+   double xd, yd, zd;
+   double rxyz, wd, rxysq, rxy;
+   int i, j;
+
+/* Small number to avoid arithmetic problems. */
+   static const double tiny = 1.0E-30;
+
+/* Canonical constants (see references). Constant vector and matrix. */
+   double a[ 6 ] = { -1.62557E-6,  -0.31919E-6, -0.13843E-6,
+                     +1.245E-3,    -1.580E-3,   -0.659E-3 };
+   double emi[ 6 ][ 6 ] = {
+                 { 0.9999256795,      0.0111814828,      0.0048590039,
+                  -0.00000242389840, -0.00000002710544, -0.00000001177742},
+                 {-0.0111814828,      0.9999374849,     -0.0000271771,
+                   0.00000002710544, -0.00000242392702,  0.00000000006585 },
+                 {-0.0048590040,     -0.0000271557,      0.9999881946,
+                   0.00000001177742,  0.00000000006585, -0.00000242404995 },
+                 {-0.000551,          0.238509,         -0.435614,
+                   0.99990432,        0.01118145,        0.00485852 },
+                 {-0.238560,         -0.002667,          0.012254,
+                  -0.01118145,        0.99991613,       -0.00002717},
+                 { 0.435730,         -0.008541,          0.002117,
+                  -0.00485852,       -0.00002716,        0.99996684 } };
+
+/* Pick up J2000 data (units radians and arcsec/JC). */
+   r = r2000;
+   d = d2000;
+   ur = dr2000*PAL__PMF;
+   ud = dd2000*PAL__PMF;
+   px = p2000;
+   rv = v2000;
+
+/* Spherical to Cartesian. */
+   sr = sin( r );
+   cr = cos( r );
+   sd = sin( d );
+   cd = cos( d );
+
+   x = cr*cd;
+   y = sr*cd;
+   z =    sd;
+
+   w = PAL__VF*rv*px;
+
+   v1[ 0 ] = x;
+   v1[ 1 ] = y;
+   v1[ 2 ] = z;
+
+   v1[ 3 ] = -ur*y - cr*sd*ud + w*x;
+   v1[ 4 ] =  ur*x - sr*sd*ud + w*y;
+   v1[ 5 ] =            cd*ud + w*z;
+
+/* Convert position+velocity vector to BN system. */
+   for( i = 0; i < 6; i++ ) {
+      w = 0.0;
+      for( j = 0; j < 6; j++ ) {
+         w += emi[ i ][ j ]*v1[ j ];
+      }
+      v2[ i ] = w;
+   }
+
+/* Position vector components and magnitude. */
+   x = v2[ 0 ];
+   y = v2[ 1 ];
+   z = v2[ 2 ];
+   rxyz = sqrt( x*x + y*y + z*z );
+
+/* Apply E-terms to position. */
+   w = x*a[ 0 ] + y*a[ 1 ] + z*a[ 2 ];
+   x += a[ 0 ]*rxyz - w*x;
+   y += a[ 1 ]*rxyz - w*y;
+   z += a[ 2 ]*rxyz - w*z;
+
+/* Recompute magnitude. */
+   rxyz = sqrt( x*x + y*y + z*z );
+
+/* Apply E-terms to both position and velocity. */
+   x = v2[ 0 ];
+   y = v2[ 1 ];
+   z = v2[ 2 ];
+   w = x*a[ 0 ] + y*a[ 1 ] + z*a[ 2 ];
+   wd = x*a[ 3 ] + y*a[ 4 ] + z*a[ 5 ];
+   x += a[ 0 ]*rxyz - w*x;
+   y += a[ 1 ]*rxyz - w*y;
+   z += a[ 2 ]*rxyz - w*z;
+   xd = v2[ 3 ] + a[ 3 ]*rxyz - wd*x;
+   yd = v2[ 4 ] + a[ 4 ]*rxyz - wd*y;
+   zd = v2[ 5 ] + a[ 5 ]*rxyz - wd*z;
+
+/* Convert to spherical. */
+   rxysq = x*x + y*y;
+   rxy = sqrt( rxysq );
+
+   if( x == 0.0 && y == 0.0 ) {
+      r = 0.0;
+   } else {
+      r = atan2( y, x );
+      if( r <  0.0 ) r += PAL__D2PI;
+   }
+   d = atan2( z, rxy );
+
+   if( rxy > tiny ) {
+      ur = ( x*yd - y*xd )/rxysq;
+      ud = ( zd*rxysq - z*( x*xd + y*yd ) )/( ( rxysq + z*z )*rxy );
+   }
+
+/* Radial velocity and parallax. */
+   if( px > tiny ) {
+      rv = ( x*xd + y*yd + z*zd )/( px*PAL__VF*rxyz );
+      px /= rxyz;
+   }
+
+/* Return results. */
+   *r1950 = r;
+   *d1950 = d;
+   *dr1950 = ur/PAL__PMF;
+   *dd1950 = ud/PAL__PMF;
+   *p1950 = px;
+   *v1950 = rv;
+}
Index: trunk/FACT++/pal/palFk54z.c
===================================================================
--- trunk/FACT++/pal/palFk54z.c	(revision 18347)
+++ trunk/FACT++/pal/palFk54z.c	(revision 18347)
@@ -0,0 +1,113 @@
+/*
+*+
+*  Name:
+*     palFk54z
+
+*  Purpose:
+*     Convert a J2000.0 FK5 star position to B1950.0 FK4 assuming
+*     zero proper motion and parallax.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palFk54z( double r2000, double d2000, double bepoch, double *r1950,
+*               double *d1950, double *dr1950, double *dd1950 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 FK5 RA (radians).
+*     d2000 = double (Given)
+*        J2000.0 FK5 Dec (radians).
+*     bepoch = double (Given)
+*         Besselian epoch (e.g. 1950.0).
+*     r1950 = double * (Returned)
+*        B1950 FK4 RA (radians) at epoch "bepoch".
+*     d1950 = double * (Returned)
+*        B1950 FK4 Dec (radians) at epoch "bepoch".
+*     dr1950 = double * (Returned)
+*        B1950 FK4 proper motion (RA) (radians/trop.yr)).
+*     dr1950 = double * (Returned)
+*        B1950 FK4 proper motion (Dec) (radians/trop.yr)).
+
+*  Description:
+*     This function converts star positions from the IAU 1976,
+*     FK5, Fricke system to the Bessel-Newcomb, FK4 system.
+
+*  Notes:
+*     - The proper motion in RA is dRA/dt rather than cos(Dec)*dRA/dt.
+*     - Conversion from Julian epoch 2000.0 to Besselian epoch 1950.0
+*     only is provided for.  Conversions involving other epochs will
+*     require use of the appropriate precession functions before and
+*     after this function is called.
+*     - The FK5 proper motions, the parallax and the radial velocity
+*      are presumed zero.
+*     - It is the intention that FK5 should be a close approximation
+*     to an inertial frame, so that distant objects have zero proper
+*     motion;  such objects have (in general) non-zero proper motion
+*     in FK4, and this function returns those fictitious proper
+*     motions.
+*     - The position returned by this function is in the B1950
+*     reference frame but at Besselian epoch BEPOCH.  For comparison
+*     with catalogues the "bepoch" argument will frequently be 1950.0.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palFk54z( double r2000, double d2000, double bepoch, double *r1950,
+               double *d1950, double *dr1950, double *dd1950 ){
+
+/* Local Variables: */
+   double r, d, px, rv, y;
+
+/* FK5 equinox J2000 (any epoch) to FK4 equinox B1950 epoch B1950. */
+   palFk524( r2000, d2000, 0.0, 0.0, 0.0, 0.0, &r, &d, dr1950, dd1950,
+             &px, &rv );
+
+/* Fictitious proper motion to epoch "bepoch". */
+   y = bepoch - 1950.0;
+   *r1950 = r + *dr1950*y;
+   *d1950 = d + *dd1950*y;
+
+}
+
Index: trunk/FACT++/pal/palGaleq.c
===================================================================
--- trunk/FACT++/pal/palGaleq.c	(revision 18347)
+++ trunk/FACT++/pal/palGaleq.c	(revision 18347)
@@ -0,0 +1,118 @@
+/*
+*+
+*  Name:
+*     palGaleq
+
+*  Purpose:
+*     Convert from galactic to J2000.0 equatorial coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palGaleq ( double dl, double db, double *dr, double *dd );
+
+*  Arguments:
+*     dl = double (Given)
+*       Galactic longitude (radians).
+*     db = double (Given)
+*       Galactic latitude (radians).
+*     dr = double * (Returned)
+*       J2000.0 RA (radians)
+*     dd = double * (Returned)
+*       J2000.0 Dec (radians)
+
+*  Description:
+*     Transformation from IAU 1958 galactic coordinates to
+*     J2000.0 equatorial coordinates.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     The equatorial coordinates are J2000.0.  Use the routine
+*     palGe50 if conversion to B1950.0 'FK4' coordinates is
+*     required.
+
+*  See Also:
+*     Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1998 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palGaleq ( double dl, double db, double *dr, double *dd ) {
+
+  double v1[3];
+  double v2[3];
+
+/*
+*  L2,B2 system of galactic coordinates
+*
+*  P = 192.25       RA of galactic north pole (mean B1950.0)
+*  Q =  62.6        inclination of galactic to mean B1950.0 equator
+*  R =  33          longitude of ascending node
+*
+*  P,Q,R are degrees
+*
+*  Equatorial to galactic rotation matrix (J2000.0), obtained by
+*  applying the standard FK4 to FK5 transformation, for zero proper
+*  motion in FK5, to the columns of the B1950 equatorial to
+*  galactic rotation matrix:
+*/
+  double rmat[3][3] = {
+    { -0.054875539726,-0.873437108010,-0.483834985808 },
+    { +0.494109453312,-0.444829589425,+0.746982251810 },
+    { -0.867666135858,-0.198076386122,+0.455983795705 }
+  };
+
+  /* Spherical to Cartesian */
+  eraS2c( dl, db, v1 );
+
+  /* Galactic to equatorial */
+  eraTrxp( rmat, v1, v2 );
+
+  /* Cartesian to spherical */
+  eraC2s( v2, dr, dd );
+
+  /* Express in conventional ranges */
+  *dr = eraAnp( *dr );
+  *dd = eraAnpm( *dd );
+
+}
Index: trunk/FACT++/pal/palGalsup.c
===================================================================
--- trunk/FACT++/pal/palGalsup.c	(revision 18347)
+++ trunk/FACT++/pal/palGalsup.c	(revision 18347)
@@ -0,0 +1,116 @@
+/*
+*+
+*  Name:
+*     palGalsup
+
+*  Purpose:
+*     Convert from galactic to supergalactic coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palGalsup ( double dl, double db, double *dsl, double *dsb );
+
+*  Arguments:
+*     dl = double (Given)
+*       Galactic longitude.
+*     db = double (Given)
+*       Galactic latitude.
+*     dsl = double * (Returned)
+*       Supergalactic longitude.
+*     dsb = double * (Returned)
+*       Supergalactic latitude.
+
+*  Description:
+*     Transformation from IAU 1958 galactic coordinates to
+*     de Vaucouleurs supergalactic coordinates.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  See Also:
+*     - de Vaucouleurs, de Vaucouleurs, & Corwin, Second Reference
+*       Catalogue of Bright Galaxies, U. Texas, page 8.
+*     - Systems & Applied Sciences Corp., Documentation for the
+*       machine-readable version of the above catalogue,
+*       Contract NAS 5-26490.
+*
+*     (These two references give different values for the galactic
+*     longitude of the supergalactic origin.  Both are wrong;  the
+*     correct value is L2=137.37.)
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palGalsup ( double dl, double db, double *dsl, double *dsb ) {
+
+  double v1[3];
+  double v2[3];
+
+/*
+*  System of supergalactic coordinates:
+*
+*    SGL   SGB        L2     B2      (deg)
+*     -    +90      47.37  +6.32
+*     0     0         -      0
+*
+*  Galactic to supergalactic rotation matrix:
+*/
+  double rmat[3][3] = {
+    { -0.735742574804,+0.677261296414,+0.000000000000 },
+    { -0.074553778365,-0.080991471307,+0.993922590400 },
+    { +0.673145302109,+0.731271165817,+0.110081262225 }
+  };
+
+  /* Spherical to Cartesian */
+  eraS2c( dl, db, v1 );
+
+  /* Galactic to Supergalactic */
+  eraRxp( rmat, v1, v2 );
+
+  /* Cartesian to spherical */
+  eraC2s( v2, dsl, dsb );
+
+  /* Express in conventional ranges */
+  *dsl = eraAnp( *dsl );
+  *dsb = eraAnpm( *dsb );
+
+}
Index: trunk/FACT++/pal/palGe50.c
===================================================================
--- trunk/FACT++/pal/palGe50.c	(revision 18347)
+++ trunk/FACT++/pal/palGe50.c	(revision 18347)
@@ -0,0 +1,128 @@
+/*
+*+
+*  Name:
+*     palGe50
+
+*  Purpose:
+*     Transform Galactic Coordinate to B1950 FK4
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palGe50( double dl, double db, double *dr, double *dd );
+
+*  Arguments:
+*     dl = double (Given)
+*        Galactic longitude (radians)
+*     db = double (Given)
+*        Galactic latitude (radians)
+*     dr = double * (Returned)
+*        B9150.0 FK4 RA.
+*     dd = double * (Returned)
+*        B1950.0 FK4 Dec.
+
+*  Description:
+*     Transformation from IAU 1958 galactic coordinates to
+*     B1950.0 'FK4' equatorial coordinates.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The equatorial coordinates are B1950.0 'FK4'. Use the routine
+*     palGaleq if conversion to J2000.0 coordinates is required.
+
+*  See Also:
+*     - Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+
+*  History:
+*     2012-03-23 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palGe50 ( double dl, double db, double * dr, double * dd ) {
+
+/*
+ *  L2,B2 system of galactic coordinates
+ *
+ *  P = 192.25       RA of galactic north pole (mean B1950.0)
+ *  Q =  62.6        inclination of galactic to mean B1950.0 equator
+ *  R =  33          longitude of ascending node
+ *
+ *  P,Q,R are degrees
+ *
+ *
+ *  Equatorial to galactic rotation matrix
+ *
+ *  The Euler angles are P, Q, 90-R, about the z then y then
+ *  z axes.
+ *
+ *         +CP.CQ.SR-SP.CR     +SP.CQ.SR+CP.CR     -SQ.SR
+ *
+ *         -CP.CQ.CR-SP.SR     -SP.CQ.CR+CP.SR     +SQ.CR
+ *
+ *         +CP.SQ              +SP.SQ              +CQ
+ *
+ */
+
+  double rmat[3][3] = {
+    { -0.066988739415,-0.872755765852,-0.483538914632 },
+    { +0.492728466075,-0.450346958020,+0.744584633283 },
+    { -0.867600811151,-0.188374601723,+0.460199784784 }
+  };
+
+  double v1[3], v2[3], r, d, re, de;
+
+  /* Spherical to cartesian */
+  eraS2c( dl, db, v1 );
+
+  /* Rotate to mean B1950.0 */
+  eraTrxp( rmat, v1, v2 );
+
+  /* Cartesian to spherical */
+  eraC2s( v2, &r, &d );
+
+  /* Introduce E-terms */
+  palAddet( r, d, 1950.0, &re, &de );
+
+  /* Express in conventional ranges */
+  *dr = eraAnp( re );
+  *dd = eraAnpm( de );
+
+}
Index: trunk/FACT++/pal/palGeoc.c
===================================================================
--- trunk/FACT++/pal/palGeoc.c	(revision 18347)
+++ trunk/FACT++/pal/palGeoc.c	(revision 18347)
@@ -0,0 +1,83 @@
+/*
+*+
+*  Name:
+*     palGeoc
+
+*  Purpose:
+*     Convert geodetic position to geocentric
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palGeoc( double p, double h, double * r, double *z );
+
+*  Arguments:
+*     p = double (Given)
+*       latitude (radians)
+*     h = double (Given)
+*       height above reference spheroid (geodetic, metres)
+*     r = double * (Returned)
+*       distance from Earth axis (AU)
+*     z = double * (Returned)
+*       distance from plane of Earth equator (AU)
+
+*  Description:
+*     Convert geodetic position to geocentric.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Geocentric latitude can be obtained by evaluating atan2(z,r)
+*     - Uses WGS84 reference ellipsoid and calls eraGd2gc
+
+*  History:
+*     2012-03-01 (TIMJ):
+*        Initial version moved from palOne2One
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palGeoc ( double p, double h, double *r, double *z ) {
+  double xyz[3];
+  const double elong = 0.0;   /* Use zero longitude */
+  const double AU = 1.49597870E11;
+  /* WGS84 looks to be the closest match */
+  eraGd2gc( ERFA_WGS84, elong, p, h, xyz );
+  *r = xyz[0] / (AU * cos(elong) );
+  *z = xyz[2] / AU;
+}
Index: trunk/FACT++/pal/palIntin.c
===================================================================
--- trunk/FACT++/pal/palIntin.c	(revision 18347)
+++ trunk/FACT++/pal/palIntin.c	(revision 18347)
@@ -0,0 +1,185 @@
+/*
+*+
+*  Name:
+*     palIntin
+
+*  Purpose:
+*     Convert free-format input into an integer
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palIntin( const char * string, int *nstrt,
+*                     long *ireslt, int *jflag );
+
+*  Arguments:
+*     string = const char * (Given)
+*        String containing number to be decoded.
+*     nstrt = int * (Given and Returned)
+*        Character number indicating where decoding should start.
+*        On output its value is updated to be the location of the
+*        possible next value. For compatibility with SLA the first
+*        character is index 1.
+*     ireslt = long * (Returned)
+*        Result. Not updated when jflag=1.
+*     jflag = int * (Returned)
+*        status: -1 = -OK, 0 = +OK, 1 = null, 2 = error
+
+*  Description:
+*     Extracts a number from an input string starting at the specified
+*     index.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Uses the strtol() system call to do the parsing. This may lead to
+*       subtle differences when compared to the SLA/F parsing.
+*     - Commas are recognized as a special case and are skipped if one happens
+*       to be the next character when updating nstrt. Additionally the output
+*       nstrt position will skip past any trailing space.
+*     - If no number can be found flag will be set to 1.
+*     - If the number overflows or underflows jflag will be set to 2. For overflow
+*       the returned result will have the value LONG_MAX, for underflow it
+*       will have the value LONG_MIN.
+
+*  History:
+*     2012-03-15 (TIMJ):
+*        Initial version
+*        Matches the SLALIB interface but brand new implementation using
+*        C library calls and not a direct port of the Fortran.
+*     2014-08-07 (TIMJ):
+*        Check for isblank availability.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012,2014 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+
+/* isblank() is a C99 feature so we just reimplement it if it is missing */
+#if HAVE_ISBLANK
+#ifndef _ISOC99_SOURCE
+#define _ISOC99_SOURCE
+#endif
+#include <ctype.h>
+# define ISBLANK isblank
+#else
+
+static int ISBLANK( int c ) {
+  return ( c == ' ' || c == '\t' );
+}
+
+#endif
+
+/* Still need ctype for isalpha and isdigit */
+#include <ctype.h>
+
+#include "pal.h"
+
+void palIntin( const char * string, int *nstrt,
+               long *ireslt, int *jflag ) {
+
+  const char *strstart = NULL; /* Pointer to start of search */
+  const char * ctemp = NULL; /* Pointer into string */
+  char * endptr = NULL;/* Pointer to string after number */
+  int retval;       /* Return value from strtol */
+  int hasminus;     /* is this a -0 */
+
+  /* strtol man page indicates that we should reset errno before
+     calling strtod */
+  errno = 0;
+
+  /* Locate the start postion */
+  strstart = &(string[*nstrt-1]);
+
+  /* We have to be able to deal with -0 so we have to search the
+     string first and look for the negative */
+  hasminus = 0;
+  ctemp = strstart;
+  while ( ctemp != '\0' ) {
+    if (isdigit(*ctemp)) break;
+    /* Reset so that - 12345 is not a negative number */
+    hasminus = 0;
+    /* Flag that we have found a minus */
+    if (*ctemp == '-') hasminus = 1;
+    ctemp++;
+  }
+
+  /* Look for the number using the system call, offsetting using
+     1-based counter. */
+  retval = strtol( strstart, &endptr, 10 );
+  if (retval == 0.0 && endptr == strstart) {
+    /* conversion did not find anything */
+    *jflag = 1;
+
+    /* but SLA compatibility requires that we step
+       through to remove leading spaces. We also step
+       through alphabetic characters since they can never
+       be numbers. Skip past a "+" since it doesn't gain
+       us anything and matches slalib. */
+    while (ISBLANK(*endptr) || isalpha(*endptr) || *endptr == '+' ) {
+      endptr++;
+    }
+
+  } else if ( errno == ERANGE ) {
+    *jflag = 2;
+  } else {
+    if ( retval < 0 || hasminus ) {
+      *jflag = -1;
+    } else {
+      *jflag = 0;
+    }
+  }
+
+  /* Sort out the position for the next index */
+  *nstrt = endptr - string + 1;
+
+  /* Skip a comma */
+  if (*endptr == ',') {
+    (*nstrt)++;
+  } else {
+    /* jump past any leading spaces for the next part of the string */
+    ctemp = endptr;
+    while ( ISBLANK(*ctemp) ) {
+      (*nstrt)++;
+      ctemp++;
+    }
+  }
+
+  /* And the result unless we found nothing */
+  if (*jflag != 1) *ireslt = retval;
+
+}
Index: trunk/FACT++/pal/palMap.c
===================================================================
--- trunk/FACT++/pal/palMap.c	(revision 18347)
+++ trunk/FACT++/pal/palMap.c	(revision 18347)
@@ -0,0 +1,128 @@
+/*
+*+
+*  Name:
+*     palMap
+
+*  Purpose:
+*     Convert star RA,Dec from mean place to geocentric apparent
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palMap( double rm, double dm, double pr, double pd,
+*                  double px, double rv, double eq, double date,
+*                  double *ra, double *da );
+
+*  Arguments:
+*     rm = double (Given)
+*        Mean RA (radians)
+*     dm = double (Given)
+*        Mean declination (radians)
+*     pr = double (Given)
+*        RA proper motion, changes per Julian year (radians)
+*     pd = double (Given)
+*        Dec proper motion, changes per Julian year (radians)
+*     px = double (Given)
+*        Parallax (arcsec)
+*     rv = double (Given)
+*        Radial velocity (km/s, +ve if receding)
+*     eq = double (Given)
+*        Epoch and equinox of star data (Julian)
+*     date = double (Given)
+*        TDB for apparent place (JD-2400000.5)
+*     ra = double * (Returned)
+*        Apparent RA (radians)
+*     dec = double * (Returned)
+*        Apparent dec (radians)
+
+*  Description:
+*     Convert star RA,Dec from mean place to geocentric apparent.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Calls palMappa and palMapqk
+
+*     - The reference systems and timescales used are IAU 2006.
+
+*     - EQ is the Julian epoch specifying both the reference frame and
+*       the epoch of the position - usually 2000.  For positions where
+*       the epoch and equinox are different, use the routine palPm to
+*       apply proper motion corrections before using this routine.
+*
+*     - The distinction between the required TDB and TT is always
+*       negligible.  Moreover, for all but the most critical
+*       applications UTC is adequate.
+*
+*     - The proper motions in RA are dRA/dt rather than cos(Dec)*dRA/dt.
+*
+*     - This routine may be wasteful for some applications because it
+*       recomputes the Earth position/velocity and the precession-
+*       nutation matrix each time, and because it allows for parallax
+*       and proper motion.  Where multiple transformations are to be
+*       carried out for one epoch, a faster method is to call the
+*       palMappa routine once and then either the palMapqk routine
+*       (which includes parallax and proper motion) or palMapqkz (which
+*       assumes zero parallax and proper motion).
+*
+*     - The accuracy is sub-milliarcsecond, limited by the
+*       precession-nutation model (see palPrenut for details).
+*
+*     - The accuracy is further limited by the routine palEvp, called
+*       by palMappa, which computes the Earth position and velocity.
+*       See eraEpv00 for details on that calculation.
+
+*  History:
+*     2012-03-01 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2001 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+*     USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palMap( double rm, double dm, double pr, double pd,
+             double px, double rv, double eq, double date,
+             double *ra, double *da ) {
+
+  double amprms[21];
+
+  /* Star independent parameters */
+  palMappa( eq, date, amprms );
+
+  /* Mean to apparent */
+  palMapqk( rm, dm, pr, pd, px, rv, amprms, ra, da );
+
+}
Index: trunk/FACT++/pal/palMappa.c
===================================================================
--- trunk/FACT++/pal/palMappa.c	(revision 18347)
+++ trunk/FACT++/pal/palMappa.c	(revision 18347)
@@ -0,0 +1,129 @@
+/*
+*+
+*  Name:
+*     palMappa
+
+*  Purpose:
+*     Compute parameters needed by palAmpqk and palMapqk.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palMappa( double eq, double date, double amprms[21] )
+
+*  Arguments:
+*     eq = double (Given)
+*        epoch of mean equinox to be used (Julian)
+*     date = double (Given)
+*        TDB (JD-2400000.5)
+*     amprms =   double[21]  (Returned)
+*        star-independent mean-to-apparent parameters:
+*        - (0)      time interval for proper motion (Julian years)
+*        - (1-3)    barycentric position of the Earth (AU)
+*        - (4-6)    heliocentric direction of the Earth (unit vector)
+*        - (7)      (grav rad Sun)*2/(Sun-Earth distance)
+*        - (8-10)   abv: barycentric Earth velocity in units of c
+*        - (11)     sqrt(1-v**2) where v=modulus(abv)
+*        - (12-20)  precession/nutation (3,3) matrix
+
+*  Description:
+*     Compute star-independent parameters in preparation for
+*     transformations between mean place and geocentric apparent place.
+*
+*     The parameters produced by this function are required in the
+*     parallax, aberration, and nutation/bias/precession parts of the
+*     mean/apparent transformations.
+*
+*     The reference systems and timescales used are IAU 2006.
+
+*  Notes:
+*     - For date, the distinction between the required TDB and TT
+*     is always negligible.  Moreover, for all but the most
+*     critical applications UTC is adequate.
+*     - The vector amprms(1-3) is referred to the mean equinox and
+*     equator of epoch eq.
+*     - The parameters amprms produced by this function are used by
+*     palAmpqk, palMapqk and palMapqkz.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (PTW):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2003 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+#include <string.h>
+
+void palMappa( double eq, double date, double amprms[21] ){
+
+/* Local constants */
+
+/*  Gravitational radius of the Sun x 2 (2*mu/c**2, AU) */
+  const double GR2 = 2.0 * 9.87063e-9;
+
+/* Local Variables; */
+   int i;
+   double ebd[ 3 ], ehd[ 3 ], eh[ 3 ], e, vn[ 3 ], vm;
+
+/* Initialise so that unsused values are returned holding zero */
+   memset( amprms, 0, 21*sizeof( *amprms ) );
+
+/* Time interval for proper motion correction. */
+   amprms[ 0 ] = eraEpj( PAL__MJD0, date ) - eq;
+
+/* Get Earth barycentric and heliocentric position and velocity. */
+   palEvp( date, eq, ebd, &amprms[ 1 ], ehd, eh );
+
+/* Heliocentric direction of Earth (normalized) and modulus. */
+   eraPn( eh, &e, &amprms[ 4 ] );
+
+/* Light deflection parameter */
+   amprms[7] = GR2 / e;
+
+/* Aberration parameters. */
+   for( i = 0; i < 3; i++ ) {
+      amprms[ i + 8 ] = ebd[ i ]*PAL__CR;
+   }
+   eraPn( &amprms[8], &vm, vn );
+   amprms[ 11 ] = sqrt( 1.0 - vm*vm );
+
+/* NPB matrix. */
+   palPrenut( eq, date, (double(*)[ 3 ]) &amprms[ 12 ] );
+}
Index: trunk/FACT++/pal/palMapqk.c
===================================================================
--- trunk/FACT++/pal/palMapqk.c	(revision 18347)
+++ trunk/FACT++/pal/palMapqk.c	(revision 18347)
@@ -0,0 +1,159 @@
+/*
+*+
+*  Name:
+*     palMapqk
+
+*  Purpose:
+*     Quick mean to apparent place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palMapqk ( double rm, double dm, double pr, double pd,
+*                     double px, double rv, double amprms[21],
+*                     double *ra, double *da );
+
+*  Arguments:
+*     rm = double (Given)
+*        Mean RA (radians)
+*     dm = double (Given)
+*        Mean declination (radians)
+*     pr = double (Given)
+*        RA proper motion, changes per Julian year (radians)
+*     pd = double (Given)
+*        Dec proper motion, changes per Julian year (radians)
+*     px = double (Given)
+*        Parallax (arcsec)
+*     rv = double (Given)
+*        Radial velocity (km/s, +ve if receding)
+*     amprms = double [21] (Given)
+*        Star-independent mean-to-apparent parameters (see palMappa).
+*     ra = double * (Returned)
+*        Apparent RA (radians)
+*     dec = double * (Returned)
+*        Apparent dec (radians)
+
+*  Description:
+*     Quick mean to apparent place:  transform a star RA,Dec from
+*     mean place to geocentric apparent place, given the
+*     star-independent parameters.
+*
+*     Use of this routine is appropriate when efficiency is important
+*     and where many star positions, all referred to the same equator
+*     and equinox, are to be transformed for one epoch.  The
+*     star-independent parameters can be obtained by calling the
+*     palMappa routine.
+*
+*     If the parallax and proper motions are zero the palMapqkz
+*     routine can be used instead.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The reference frames and timescales used are post IAU 2006.
+
+*  History:
+*     2012-03-01 (TIMJ):
+*        Initial version with documentation from SLA/F
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2000 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palMapqk ( double rm, double dm, double pr, double pd,
+                double px, double rv, double amprms[21],
+                double *ra, double *da ) {
+
+/* local constants */
+   const double VF = 0.21094502; /* Km/s to AU/year */
+
+/* Local Variables: */
+   int i;
+   double ab1, abv[3], p[3], w, p1dv, p2[3], p3[3];
+   double pmt, gr2e, eb[3], q[3], pxr, em[3];
+   double pde, pdep1, p1[3], ehn[3], pn[3];
+
+/* Unpack scalar and vector parameters. */
+   pmt = amprms[0];
+   gr2e = amprms[7];
+   ab1 = amprms[11];
+   for( i = 0; i < 3; i++ ) {
+      eb[i] = amprms[i+1];
+      ehn[i] = amprms[i+4];
+      abv[i] = amprms[i+8];
+   }
+
+/* Spherical to x,y,z. */
+   eraS2c( rm, dm, q);
+
+ /* Space motion (radians per year) */
+   pxr = px * PAL__DAS2R;
+   w = VF * rv * pxr;
+   em[0] = -pr * q[1] - pd * cos(rm) * sin(dm) + w * q[0];
+   em[1] =  pr * q[0] - pd * sin(rm) * sin(dm) + w * q[1];
+   em[2] =              pd * cos(dm)           + w * q[2];
+
+/* Geocentric direction of star (normalised) */
+   for( i = 0; i < 3; i++ ) {
+      p[i] = q[i] + pmt * em[i] - pxr * eb[i];
+   }
+   eraPn( p, &w, pn );
+
+/* Light deflection (restrained within the Sun's disc) */
+   pde = eraPdp( pn, ehn );
+   pdep1 = pde + 1.0;
+   w = gr2e / ( pdep1 > 1.0e-5 ? pdep1 : 1.0e-5 );
+   for( i = 0; i < 3; i++) {
+      p1[i] = pn[i] + w * ( ehn[i] - pde * pn[i] );
+   }
+
+/* Aberration (normalisation omitted). */
+   p1dv = eraPdp( p, abv );
+   w = 1.0 + p1dv / ( ab1 + 1.0 );
+   for( i = 0; i < 3; i++ ) {
+      p2[i] = ( ab1 * p1[i] ) + ( w * abv[i] );
+   }
+
+/* Precession and nutation. */
+   eraRxp( (double(*)[3]) &amprms[12], p2, p3 );
+
+/* Geocentric apparent RA,dec. */
+   eraC2s( p3, ra, da );
+   *ra = eraAnp( *ra );
+
+}
Index: trunk/FACT++/pal/palMapqkz.c
===================================================================
--- trunk/FACT++/pal/palMapqkz.c	(revision 18347)
+++ trunk/FACT++/pal/palMapqkz.c	(revision 18347)
@@ -0,0 +1,127 @@
+/*
+*+
+*  Name:
+*     palMapqkz
+
+*  Purpose:
+*     Quick mean to apparent place (no proper motion or parallax).
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palMapqkz( double rm, double dm, double amprms[21],
+*                     double *ra, double *da )
+
+*  Arguments:
+*     rm = double (Given)
+*        Mean RA (radians).
+*     dm = double (Given)
+*        Mean Dec (radians).
+*     amprms = double[21] (Given)
+*        Star-independent mean-to-apparent parameters (see palMappa):
+*        (0-3)    not used
+*        (4-6)    not used
+*        (7)      not used
+*        (8-10)   abv: barycentric Earth velocity in units of c
+*        (11)     sqrt(1-v**2) where v=modulus(abv)
+*        (12-20)  precession/nutation (3,3) matrix
+*     ra = double * (Returned)
+*        Apparent RA (radians).
+*     da = double * (Returned)
+*        Apparent Dec (radians).
+
+*  Description:
+*     Quick mean to apparent place:  transform a star RA,dec from
+*     mean place to geocentric apparent place, given the
+*     star-independent parameters, and assuming zero parallax
+*     and proper motion.
+*
+*     Use of this function is appropriate when efficiency is important
+*     and where many star positions, all with parallax and proper
+*     motion either zero or already allowed for, and all referred to
+*     the same equator and equinox, are to be transformed for one
+*     epoch.  The star-independent parameters can be obtained by
+*     calling the palMappa function.
+*
+*     The corresponding function for the case of non-zero parallax
+*     and proper motion is palMapqk.
+*
+*     The reference systems and timescales used are IAU 2006.
+*
+*     Strictly speaking, the function is not valid for solar-system
+*     sources, though the error will usually be extremely small.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-13 (PTW):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palMapqkz ( double rm, double dm, double amprms[21], double *ra,
+                 double *da ){
+
+/* Local Variables: */
+   int i;
+   double ab1, abv[3], p[3], w, p1dv, p1dvp1, p2[3], p3[3];
+
+/* Unpack scalar and vector parameters. */
+   ab1 = amprms[11];
+   for( i = 0; i < 3; i++ ) {
+      abv[i] = amprms[i+8];
+   }
+
+/* Spherical to x,y,z. */
+   eraS2c( rm, dm, p );
+
+/* Aberration. */
+   p1dv = eraPdp( p, abv );
+   p1dvp1 = p1dv + 1.0;
+   w = 1.0 + p1dv / ( ab1 + 1.0 );
+   for( i = 0; i < 3; i++ ) {
+      p2[i] = ( ( ab1 * p[i] ) + ( w * abv[i] ) ) / p1dvp1;
+   }
+
+/* Precession and nutation. */
+   eraRxp( (double(*)[3]) &amprms[12], p2, p3 );
+
+/* Geocentric apparent RA,dec. */
+   eraC2s( p3, ra, da );
+   *ra = eraAnp( *ra );
+}
Index: trunk/FACT++/pal/palNut.c
===================================================================
--- trunk/FACT++/pal/palNut.c	(revision 18347)
+++ trunk/FACT++/pal/palNut.c	(revision 18347)
@@ -0,0 +1,85 @@
+/*
+*+
+*  Name:
+*     palNut
+
+*  Purpose:
+*     Form the matrix of nutation
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palNut( double date, double rmatn[3][3] );
+
+*  Arguments:
+*     date = double (Given)
+*        TT as modified Julian date (JD-2400000.5)
+*     rmatn = double [3][3] (Returned)
+*        Nutation matrix in the sense v(true)=rmatn * v(mean)
+*        where v(true) is the star vector relative to the
+*        true equator and equinox of date and v(mean) is the
+*        star vector relative to the mean equator and equinox
+*        of date.
+
+*  Description:
+*     Form the matrix of nutation for a given date using
+*     the IAU 2006 nutation model and palDeuler.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Uses eraNut06a via palNutc
+*     - The distinction between TDB and TT is negligible. For all but
+*       the most critical applications UTC is adequate.
+
+*  History:
+*     2012-03-07 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palNut( double date, double rmatn[3][3]) {
+  double dpsi, deps, eps0;
+
+  /* Nutation component and mean obliquity */
+  palNutc( date, &dpsi, &deps, &eps0 );
+
+  /* Rotation matrix */
+  palDeuler( "XZX", eps0, -dpsi, -(eps0+deps), rmatn );
+
+}
Index: trunk/FACT++/pal/palNutc.c
===================================================================
--- trunk/FACT++/pal/palNutc.c	(revision 18347)
+++ trunk/FACT++/pal/palNutc.c	(revision 18347)
@@ -0,0 +1,80 @@
+/*
+*+
+*  Name:
+*     palNutc
+
+*  Purpose:
+*     Calculate nutation longitude & obliquoty components
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palNutc( double date, double * dpsi, double *deps, double *eps0 );
+
+*  Arguments:
+*     date = double (Given)
+*        TT as modified Julian date (JD-2400000.5)
+*     dpsi = double * (Returned)
+*        Nutation in longitude
+*     deps = double * (Returned)
+*        Nutation in obliquity
+*     eps0 = double * (Returned)
+*        Mean obliquity.
+
+*  Description:
+*     Calculates the longitude * obliquity components and mean obliquity
+*     using the SOFA/ERFA library.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Calls eraObl06 and eraNut06a and therefore uses the IAU 206
+*       precession/nutation model.
+*     - Note the change from SLA/F regarding the date. TT is used
+*       rather than TDB.
+
+*  History:
+*     2012-03-05 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palNutc( double date, double * dpsi, double *deps, double *eps0 ) {
+  eraNut06a( PAL__MJD0, date, dpsi, deps );
+  *eps0 = eraObl06( PAL__MJD0, date );
+}
Index: trunk/FACT++/pal/palOap.c
===================================================================
--- trunk/FACT++/pal/palOap.c	(revision 18347)
+++ trunk/FACT++/pal/palOap.c	(revision 18347)
@@ -0,0 +1,234 @@
+/*
+*+
+*  Name:
+*     palOap
+
+*  Purpose:
+*     Observed to apparent place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palOap ( const char *type, double ob1, double ob2, double date,
+*                   double dut, double elongm, double phim, double hm,
+*                   double xp, double yp, double tdk, double pmb,
+*                   double rh, double wl, double tlr,
+*                   double *rap, double *dap );
+
+*  Arguments:
+*     type = const char * (Given)
+*        Type of coordinates - 'R', 'H' or 'A' (see below)
+*     ob1 = double (Given)
+*        Observed Az, HA or RA (radians; Az is N=0;E=90)
+*     ob2 = double (Given)
+*        Observed ZD or Dec (radians)
+*     date = double (Given)
+*        UTC date/time (Modified Julian Date, JD-2400000.5)
+*     dut = double (Given)
+*        delta UT: UT1-UTC (UTC seconds)
+*     elongm = double (Given)
+*        Mean longitude of the observer (radians, east +ve)
+*     phim = double (Given)
+*        Mean geodetic latitude of the observer (radians)
+*     hm = double (Given)
+*        Observer's height above sea level (metres)
+*     xp = double (Given)
+*        Polar motion x-coordinates (radians)
+*     yp = double (Given)
+*        Polar motion y-coordinates (radians)
+*     tdk = double (Given)
+*        Local ambient temperature (K; std=273.15)
+*     pmb = double (Given)
+*        Local atmospheric pressure (mb; std=1013.25)
+*     rh = double (Given)
+*        Local relative humidity (in the range 0.0-1.0)
+*     wl = double (Given)
+*        Effective wavelength (micron, e.g. 0.55)
+*     tlr = double (Given)
+*        Tropospheric laps rate (K/metre, e.g. 0.0065)
+*     rap = double * (Given)
+*        Geocentric apparent right ascension
+*     dap = double * (Given)
+*        Geocentric apparent declination
+
+*  Description:
+*     Observed to apparent place.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Only the first character of the TYPE argument is significant.
+*     'R' or 'r' indicates that OBS1 and OBS2 are the observed right
+*     ascension and declination;  'H' or 'h' indicates that they are
+*     hour angle (west +ve) and declination;  anything else ('A' or
+*     'a' is recommended) indicates that OBS1 and OBS2 are azimuth
+*     (north zero, east 90 deg) and zenith distance.  (Zenith
+*     distance is used rather than elevation in order to reflect the
+*     fact that no allowance is made for depression of the horizon.)
+*
+*     - The accuracy of the result is limited by the corrections for
+*     refraction.  Providing the meteorological parameters are
+*     known accurately and there are no gross local effects, the
+*     predicted apparent RA,Dec should be within about 0.1 arcsec
+*     for a zenith distance of less than 70 degrees.  Even at a
+*     topocentric zenith distance of 90 degrees, the accuracy in
+*     elevation should be better than 1 arcmin;  useful results
+*     are available for a further 3 degrees, beyond which the
+*     palRefro routine returns a fixed value of the refraction.
+*     The complementary routines palAop (or palAopqk) and palOap
+*     (or palOapqk) are self-consistent to better than 1 micro-
+*     arcsecond all over the celestial sphere.
+*
+*     - It is advisable to take great care with units, as even
+*     unlikely values of the input parameters are accepted and
+*     processed in accordance with the models used.
+*
+*     - "Observed" Az,El means the position that would be seen by a
+*     perfect theodolite located at the observer.  This is
+*     related to the observed HA,Dec via the standard rotation, using
+*     the geodetic latitude (corrected for polar motion), while the
+*     observed HA and RA are related simply through the local
+*     apparent ST.  "Observed" RA,Dec or HA,Dec thus means the
+*     position that would be seen by a perfect equatorial located
+*     at the observer and with its polar axis aligned to the
+*     Earth's axis of rotation (n.b. not to the refracted pole).
+*     By removing from the observed place the effects of
+*     atmospheric refraction and diurnal aberration, the
+*     geocentric apparent RA,Dec is obtained.
+*
+*     - Frequently, mean rather than apparent RA,Dec will be required,
+*     in which case further transformations will be necessary.  The
+*     palAmp etc routines will convert the apparent RA,Dec produced
+*     by the present routine into an "FK5" (J2000) mean place, by
+*     allowing for the Sun's gravitational lens effect, annual
+*     aberration, nutation and precession.  Should "FK4" (1950)
+*     coordinates be needed, the routines palFk524 etc will also
+*     need to be applied.
+*
+*     - To convert to apparent RA,Dec the coordinates read from a
+*     real telescope, corrections would have to be applied for
+*     encoder zero points, gear and encoder errors, tube flexure,
+*     the position of the rotator axis and the pointing axis
+*     relative to it, non-perpendicularity between the mounting
+*     axes, and finally for the tilt of the azimuth or polar axis
+*     of the mounting (with appropriate corrections for mount
+*     flexures).  Some telescopes would, of course, exhibit other
+*     properties which would need to be accounted for at the
+*     appropriate point in the sequence.
+*
+*     - This routine takes time to execute, due mainly to the rigorous
+*     integration used to evaluate the refraction.  For processing
+*     multiple stars for one location and time, call palAoppa once
+*     followed by one call per star to palOapqk.  Where a range of
+*     times within a limited period of a few hours is involved, and the
+*     highest precision is not required, call palAoppa once, followed
+*     by a call to palAoppat each time the time changes, followed by
+*     one call per star to palOapqk.
+*
+*     - The DATE argument is UTC expressed as an MJD.  This is, strictly
+*     speaking, wrong, because of leap seconds.  However, as long as
+*     the delta UT and the UTC are consistent there are no
+*     difficulties, except during a leap second.  In this case, the
+*     start of the 61st second of the final minute should begin a new
+*     MJD day and the old pre-leap delta UT should continue to be used.
+*     As the 61st second completes, the MJD should revert to the start
+*     of the day as, simultaneously, the delta UTC changes by one
+*     second to its post-leap new value.
+*
+*     - The delta UT (UT1-UTC) is tabulated in IERS circulars and
+*     elsewhere.  It increases by exactly one second at the end of
+*     each UTC leap second, introduced in order to keep delta UT
+*     within +/- 0.9 seconds.
+*
+*     - IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+*     The longitude required by the present routine is east-positive,
+*     in accordance with geographical convention (and right-handed).
+*     In particular, note that the longitudes returned by the
+*     palOBS routine are west-positive, following astronomical
+*     usage, and must be reversed in sign before use in the present
+*     routine.
+*
+*     - The polar coordinates XP,YP can be obtained from IERS
+*     circulars and equivalent publications.  The maximum amplitude
+*     is about 0.3 arcseconds.  If XP,YP values are unavailable,
+*     use XP=YP=0D0.  See page B60 of the 1988 Astronomical Almanac
+*     for a definition of the two angles.
+*
+*     - The height above sea level of the observing station, HM,
+*     can be obtained from the Astronomical Almanac (Section J
+*     in the 1988 edition), or via the routine palOBS.  If P,
+*     the pressure in millibars, is available, an adequate
+*     estimate of HM can be obtained from the expression
+*
+*            HM ~ -29.3*TSL*LOG(P/1013.25).
+*
+*     where TSL is the approximate sea-level air temperature in K
+*     (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+*     section 52).  Similarly, if the pressure P is not known,
+*     it can be estimated from the height of the observing
+*     station, HM, as follows:
+*
+*            P ~ 1013.25*EXP(-HM/(29.3*TSL)).
+*
+*     Note, however, that the refraction is nearly proportional to the
+*     pressure and that an accurate P value is important for precise
+*     work.
+*
+*     - The azimuths etc. used by the present routine are with respect
+*     to the celestial pole.  Corrections from the terrestrial pole
+*     can be computed using palPolmo.
+
+*  History:
+*     2012-08-27 (TIMJ):
+*        Initial version, copied from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palOap ( const char *type, double ob1, double ob2, double date,
+              double dut, double elongm, double phim, double hm,
+              double xp, double yp, double tdk, double pmb,
+              double rh, double wl, double tlr,
+              double *rap, double *dap ) {
+
+  double aoprms[14];
+
+  palAoppa(date,dut,elongm,phim,hm,xp,yp,tdk,pmb,rh,wl,tlr,
+           aoprms);
+  palOapqk(type,ob1,ob2,aoprms,rap,dap);
+
+}
Index: trunk/FACT++/pal/palOapqk.c
===================================================================
--- trunk/FACT++/pal/palOapqk.c	(revision 18347)
+++ trunk/FACT++/pal/palOapqk.c	(revision 18347)
@@ -0,0 +1,266 @@
+/*
+*+
+*  Name:
+*     palOapqk
+
+*  Purpose:
+*     Quick observed to apparent place
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palOapqk ( const char *type, double ob1, double ob2,
+*                     const  double aoprms[14], double *rap, double *dap );
+
+*  Arguments:
+*     Quick observed to apparent place.
+
+*  Description:
+*     type = const char * (Given)
+*        Type of coordinates - 'R', 'H' or 'A' (see below)
+*     ob1 = double (Given)
+*        Observed Az, HA or RA (radians; Az is N=0;E=90)
+*     ob2 = double (Given)
+*        Observed ZD or Dec (radians)
+*     aoprms = const double [14] (Given)
+*        Star-independent apparent-to-observed parameters.
+*        See palAopqk for details.
+*     rap = double * (Given)
+*        Geocentric apparent right ascension
+*     dap = double * (Given)
+*        Geocentric apparent declination
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Only the first character of the TYPE argument is significant.
+*     'R' or 'r' indicates that OBS1 and OBS2 are the observed right
+*     ascension and declination;  'H' or 'h' indicates that they are
+*     hour angle (west +ve) and declination;  anything else ('A' or
+*     'a' is recommended) indicates that OBS1 and OBS2 are azimuth
+*     (north zero, east 90 deg) and zenith distance.  (Zenith distance
+*     is used rather than elevation in order to reflect the fact that
+*     no allowance is made for depression of the horizon.)
+*
+*     - The accuracy of the result is limited by the corrections for
+*     refraction.  Providing the meteorological parameters are
+*     known accurately and there are no gross local effects, the
+*     predicted apparent RA,Dec should be within about 0.1 arcsec
+*     for a zenith distance of less than 70 degrees.  Even at a
+*     topocentric zenith distance of 90 degrees, the accuracy in
+*     elevation should be better than 1 arcmin;  useful results
+*     are available for a further 3 degrees, beyond which the
+*     palREFRO routine returns a fixed value of the refraction.
+*     The complementary routines palAop (or palAopqk) and palOap
+*     (or palOapqk) are self-consistent to better than 1 micro-
+*     arcsecond all over the celestial sphere.
+*
+*     - It is advisable to take great care with units, as even
+*     unlikely values of the input parameters are accepted and
+*     processed in accordance with the models used.
+*
+*     - "Observed" Az,El means the position that would be seen by a
+*     perfect theodolite located at the observer.  This is
+*     related to the observed HA,Dec via the standard rotation, using
+*     the geodetic latitude (corrected for polar motion), while the
+*     observed HA and RA are related simply through the local
+*     apparent ST.  "Observed" RA,Dec or HA,Dec thus means the
+*     position that would be seen by a perfect equatorial located
+*     at the observer and with its polar axis aligned to the
+*     Earth's axis of rotation (n.b. not to the refracted pole).
+*     By removing from the observed place the effects of
+*     atmospheric refraction and diurnal aberration, the
+*     geocentric apparent RA,Dec is obtained.
+*
+*     - Frequently, mean rather than apparent RA,Dec will be required,
+*     in which case further transformations will be necessary.  The
+*     palAmp etc routines will convert the apparent RA,Dec produced
+*     by the present routine into an "FK5" (J2000) mean place, by
+*     allowing for the Sun's gravitational lens effect, annual
+*     aberration, nutation and precession.  Should "FK4" (1950)
+*     coordinates be needed, the routines palFk524 etc will also
+*     need to be applied.
+*
+*     - To convert to apparent RA,Dec the coordinates read from a
+*     real telescope, corrections would have to be applied for
+*     encoder zero points, gear and encoder errors, tube flexure,
+*     the position of the rotator axis and the pointing axis
+*     relative to it, non-perpendicularity between the mounting
+*     axes, and finally for the tilt of the azimuth or polar axis
+*     of the mounting (with appropriate corrections for mount
+*     flexures).  Some telescopes would, of course, exhibit other
+*     properties which would need to be accounted for at the
+*     appropriate point in the sequence.
+*
+*     - The star-independent apparent-to-observed-place parameters
+*     in AOPRMS may be computed by means of the palAoppa routine.
+*     If nothing has changed significantly except the time, the
+*     palAoppat routine may be used to perform the requisite
+*     partial recomputation of AOPRMS.
+*
+*     - The azimuths etc used by the present routine are with respect
+*     to the celestial pole.  Corrections from the terrestrial pole
+*     can be computed using palPolmo.
+
+
+*  History:
+*     2012-08-27 (TIMJ):
+*        Initial version, direct copy of Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void palOapqk ( const char *type, double ob1, double ob2, const double aoprms[14],
+                double *rap, double *dap ) {
+
+  /*  breakpoint for fast/slow refraction algorithm:
+   *  zd greater than arctan(4), (see palRefco routine)
+   *  or vector z less than cosine(arctan(z)) = 1/sqrt(17) */
+  const double zbreak = 0.242535625;
+
+  char c;
+  double c1,c2,sphi,cphi,st,ce,xaeo,yaeo,zaeo,v[3],
+    xmhdo,ymhdo,zmhdo,az,sz,zdo,tz,dref,zdt,
+    xaet,yaet,zaet,xmhda,ymhda,zmhda,diurab,f,hma;
+
+  /*  coordinate type */
+  c = type[0];
+
+  /*  coordinates */
+  c1 = ob1;
+  c2 = ob2;
+
+  /*  sin, cos of latitude */
+  sphi = aoprms[1];
+  cphi = aoprms[2];
+
+  /*  local apparent sidereal time */
+  st = aoprms[13];
+
+  /*  standardise coordinate type */
+  if (c == 'r' || c == 'R') {
+    c = 'r';
+  } else if (c == 'h' || c == 'H') {
+    c = 'h';
+  } else {
+    c = 'a';
+  }
+
+  /*  if az,zd convert to cartesian (s=0,e=90) */
+  if (c == 'a') {
+    ce = sin(c2);
+    xaeo = -cos(c1)*ce;
+    yaeo = sin(c1)*ce;
+    zaeo = cos(c2);
+  } else {
+
+    /*     if ra,dec convert to ha,dec */
+    if (c == 'r') {
+      c1 = st-c1;
+    }
+
+    /*     to cartesian -ha,dec */
+    palDcs2c( -c1, c2, v );
+    xmhdo = v[0];
+    ymhdo = v[1];
+    zmhdo = v[2];
+
+    /*     to cartesian az,el (s=0,e=90) */
+    xaeo = sphi*xmhdo-cphi*zmhdo;
+    yaeo = ymhdo;
+    zaeo = cphi*xmhdo+sphi*zmhdo;
+  }
+
+  /*  azimuth (s=0,e=90) */
+  if (xaeo != 0.0 || yaeo != 0.0) {
+    az = atan2(yaeo,xaeo);
+  } else {
+    az = 0.0;
+  }
+
+  /*  sine of observed zd, and observed zd */
+  sz = sqrt(xaeo*xaeo+yaeo*yaeo);
+  zdo = atan2(sz,zaeo);
+
+  /*
+   *  refraction
+   *  ---------- */
+
+  /*  large zenith distance? */
+  if (zaeo >= zbreak) {
+
+    /*     fast algorithm using two constant model */
+    tz = sz/zaeo;
+    dref = (aoprms[10]+aoprms[11]*tz*tz)*tz;
+
+  } else {
+
+    /*     rigorous algorithm for large zd */
+    palRefro(zdo,aoprms[4],aoprms[5],aoprms[6],aoprms[7],
+             aoprms[8],aoprms[0],aoprms[9],1e-8,&dref);
+  }
+
+  zdt = zdo+dref;
+
+  /*  to cartesian az,zd */
+  ce = sin(zdt);
+  xaet = cos(az)*ce;
+  yaet = sin(az)*ce;
+  zaet = cos(zdt);
+
+  /*  cartesian az,zd to cartesian -ha,dec */
+  xmhda = sphi*xaet+cphi*zaet;
+  ymhda = yaet;
+  zmhda = -cphi*xaet+sphi*zaet;
+
+  /*  diurnal aberration */
+  diurab = -aoprms[3];
+  f = (1.0-diurab*ymhda);
+  v[0] = f*xmhda;
+  v[1] = f*(ymhda+diurab);
+  v[2] = f*zmhda;
+
+  /*  to spherical -ha,dec */
+  palDcc2s(v,&hma,dap);
+
+  /*  Right Ascension */
+  *rap = palDranrm(st+hma);
+
+}
Index: trunk/FACT++/pal/palObs.c
===================================================================
--- trunk/FACT++/pal/palObs.c	(revision 18347)
+++ trunk/FACT++/pal/palObs.c	(revision 18347)
@@ -0,0 +1,928 @@
+/*
+*+
+*  Name:
+*     palObs
+
+*  Purpose:
+*     Parameters of selected ground-based observing stations
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     int palObs( size_t n, const char * c,
+*                 char * ident, size_t identlen,
+*                 char * name, size_t namelen,
+*                 double * w, double * p, double * h );
+
+*  Arguments:
+*     n = size_t (Given)
+*         Number specifying the observing station. If 0
+*         the identifier in "c" is used to determine the
+*         observing station to use.
+*     c = const char * (Given)
+*         Identifier specifying the observing station for
+*         which the parameters should be returned. Only used
+*         if n is 0. Can be NULL for n>0. Case insensitive.
+*     ident = char * (Returned)
+*         Identifier of the observing station selected. Will be
+*         identical to "c" if n==0. Unchanged if "n" or "c"
+*         do not match an observing station. Should be at least
+*         11 characters (including the trailing nul).
+*     identlen = size_t (Given)
+*         Size of the buffer "ident" including trailing nul.
+*     name = char * (Returned)
+*         Full name of the specified observing station. Contains "?"
+*         if "n" or "c" did not correspond to a valid station. Should
+*         be at least 41 characters (including the trailing nul).
+*     w = double * (Returned)
+*         Longitude (radians, West +ve). Unchanged if observing
+*         station could not be identified.
+*     p = double * (Returned)
+*         Geodetic latitude (radians, North +ve). Unchanged if observing
+*         station could not be identified.
+*     h = double * (Returned)
+*         Height above sea level (metres). Unchanged if observing
+*         station could not be identified.
+
+*  Returned Value:
+*     palObs = int
+*         0 if an observing station was returned. -1 if no match was
+*         found.
+
+*  Description:
+*     Station numbers, identifiers, names and other details are
+*     subject to change and should not be hardwired into
+*     application programs.
+*
+*     All characters in "c" up to the first space are
+*     checked;  thus an abbreviated ID will return the parameters
+*     for the first station in the list which matches the
+*     abbreviation supplied, and no station in the list will ever
+*     contain embedded spaces. "c" must not have leading spaces.
+*
+*     IMPORTANT -- BEWARE OF THE LONGITUDE SIGN CONVENTION.  The
+*     longitude returned by palOBS (and SLA_OBS) is west-positive in accordance
+*     with astronomical usage.  However, this sign convention is
+*     left-handed and is the opposite of the one used by geographers;
+*     elsewhere in PAL the preferable east-positive convention is
+*     used.  In particular, note that for use in palAop, palAoppa
+*     and palOap the sign of the longitude must be reversed.
+*
+*     Users are urged to inform the author of any improvements
+*     they would like to see made.  For example:
+*
+*         typographical corrections
+*         more accurate parameters
+*         better station identifiers or names
+*         additional stations
+
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Differs from the SLA interface in that the output short name
+*       is not the same variable as the input short name. This simplifies
+*       consting. Additionally the size of the output buffers are now
+*       specified in the API and a status integer is returned.
+
+*  History:
+*     2012-03-06 (TIMJ):
+*        Initial version containing entries from SLA/F as of 15 March 2002
+*        with a 2008 tweak to the JCMT GPS position.
+*        Adapted with permission from the Fortran SLALIB library.
+*     2014-04-08 (TIMJ):
+*        Add APEX and NANTEN2
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2002 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     Copyright (C) 2014 Cornell University.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#if HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#ifdef HAVE_BSD_STRING_H
+#include <bsd/string.h>
+#endif
+
+#include <string.h>
+
+/* We prefer to use the starutil package. */
+#if HAVE_STAR_UTIL_H
+#include "star/util.h"
+#else
+/* This version is just a straight copy without putting ellipsis on the end. */
+static void star__strellcpy( char * dest, const char * src, size_t size ) {
+# if HAVE_STRLCPY
+  strlcpy( dest, src, size );
+# else
+  strncpy( dest, src, size );
+  dest[size-1] = '\0';
+# endif
+}
+
+#define star_strellcpy(dest, src, size) star__strellcpy(dest, src, size)
+#endif
+
+#include "pal.h"
+#include "palmac.h"
+
+/* Helper macros to convert degrees to radians in longitude and latitude */
+#define WEST(ID,IAM,AS) PAL__DAS2R*((60.0*(60.0*(double)ID+(double)IAM))+(double)AS)
+#define NORTH(ID,IAM,AS) WEST(ID,IAM,AS)
+#define EAST(ID,IAM,AS) -1.0*WEST(ID,IAM,AS)
+#define SOUTH(ID,IAM,AS) -1.0*WEST(ID,IAM,AS)
+
+struct telData {
+  double w;
+  double p;
+  double h;
+  char shortname[11];
+  char longname[41];
+};
+
+
+int palObs( size_t n, const char * c,
+            char * ident, size_t identlen,
+            char * name, size_t namelen,
+            double * w, double * p, double * h ) {
+  const struct telData telData[] = {
+    /* AAT (Observer's Guide)                                            AAT */
+    {
+      EAST(149,3,57.91),
+      SOUTH(31,16,37.34),
+      1164E0,
+      "AAT",
+      "Anglo-Australian 3.9m Telescope"
+    },
+    /* WHT (Gemini, April 1987)                                       LPO4.2 */
+    {
+      WEST(17,52,53.9),
+      NORTH(28,45,38.1),
+      2332E0,
+      "LPO4.2",
+      "William Herschel 4.2m Telescope"
+    },
+    /* INT (Gemini, April 1987)                                       LPO2.5 */
+    {
+      WEST(17,52,39.5),
+      NORTH(28,45,43.2),
+      2336E0,
+      "LPO2.5",
+      "Isaac Newton 2.5m Telescope"
+    },
+    /* JKT (Gemini, April 1987)                                         LPO1 */
+    {
+      WEST(17,52,41.2),
+      NORTH(28,45,39.9),
+      2364E0,
+      "LPO1",
+      "Jacobus Kapteyn 1m Telescope"
+    },
+    /* Lick 120" (S.L.Allen, private communication, 2002)            LICK120 */
+    {
+      WEST(121,38,13.689),
+      NORTH(37,20,34.931),
+      1286E0,
+      "LICK120",
+      "Lick 120 inch"
+    },
+    /* MMT 6.5m conversion (MMT Observatory website)                     MMT */
+    {
+      WEST(110,53,4.4),
+      NORTH(31,41,19.6),
+      2608E0,
+      "MMT",
+      "MMT 6.5m, Mt Hopkins"
+    },
+    /* Victoria B.C. 1.85m (1984 Almanac)                              DAO72 */
+    {
+      WEST(123,25,1.18),
+      NORTH(48,31,11.9),
+      238E0,
+      "DAO72",
+      "DAO Victoria BC 1.85 metre"
+    },
+    /* Las Campanas (1983 Almanac)                                    DUPONT */
+    {
+      WEST(70,42,9.),
+      SOUTH(29,0,11.),
+      2280E0,
+      "DUPONT",
+      "Du Pont 2.5m Telescope, Las Campanas"
+    },
+    /* Mt Hopkins 1.5m (1983 Almanac)                               MTHOP1.5 */
+    {
+      WEST(110,52,39.00),
+      NORTH(31,40,51.4),
+      2344E0,
+      "MTHOP1.5",
+      "Mt Hopkins 1.5 metre"
+    },
+    /* Mt Stromlo 74" (1983 Almanac)                               STROMLO74 */
+    {
+      EAST(149,0,27.59),
+      SOUTH(35,19,14.3),
+      767E0,
+      "STROMLO74",
+      "Mount Stromlo 74 inch"
+    },
+    /* ANU 2.3m, SSO (Gary Hovey)                                     ANU2.3 */
+    {
+      EAST(149,3,40.3),
+      SOUTH(31,16,24.1),
+      1149E0,
+      "ANU2.3",
+      "Siding Spring 2.3 metre"
+    },
+    /* Greenbank 140' (1983 Almanac)                                 GBVA140 */
+    {
+      WEST(79,50,9.61),
+      NORTH(38,26,15.4),
+      881E0,
+      "GBVA140",
+      "Greenbank 140 foot"
+    },
+    /* Cerro Tololo 4m (1982 Almanac)                               TOLOLO4M */
+    {
+      WEST(70,48,53.6),
+      SOUTH(30,9,57.8),
+      2235E0,
+      "TOLOLO4M",
+      "Cerro Tololo 4 metre"
+    },
+    /* Cerro Tololo 1.5m (1982 Almanac)                           TOLOLO1.5M */
+    {
+      WEST(70,48,54.5),
+      SOUTH(30,9,56.3),
+      2225E0,
+      "TOLOLO1.5M",
+      "Cerro Tololo 1.5 metre"
+    },
+    /* Tidbinbilla 64m (1982 Almanac)                              TIDBINBLA */
+    {
+      EAST(148,58,48.20),
+      SOUTH(35,24,14.3),
+      670E0,
+      "TIDBINBLA",
+      "Tidbinbilla 64 metre"
+    },
+    /* Bloemfontein 1.52m (1981 Almanac)                              BLOEMF */
+    {
+      EAST(26,24,18.),
+      SOUTH(29,2,18.),
+      1387E0,
+      "BLOEMF",
+      "Bloemfontein 1.52 metre"
+    },
+    /* Bosque Alegre 1.54m (1981 Almanac)                         BOSQALEGRE */
+    {
+      WEST(64,32,48.0),
+      SOUTH(31,35,53.),
+      1250E0,
+      "BOSQALEGRE",
+      "Bosque Alegre 1.54 metre"
+    },
+    /* USNO 61" astrographic reflector, Flagstaff (1981 Almanac)   FLAGSTF61 */
+    {
+      WEST(111,44,23.6),
+      NORTH(35,11,2.5),
+      2316E0,
+      "FLAGSTF61",
+      "USNO 61 inch astrograph, Flagstaff"
+    },
+    /* Lowell 72" (1981 Almanac)                                    LOWELL72 */
+    {
+      WEST(111,32,9.3),
+      NORTH(35,5,48.6),
+      2198E0,
+      "LOWELL72",
+      "Perkins 72 inch, Lowell"
+    },
+    /* Harvard 1.55m (1981 Almanac)                                  HARVARD */
+    {
+      WEST(71,33,29.32),
+      NORTH(42,30,19.0),
+      185E0,
+      "HARVARD",
+      "Harvard College Observatory 1.55m"
+    },
+    /* Okayama 1.88m (1981 Almanac)                                  OKAYAMA */
+    {
+      EAST(133,35,47.29),
+      NORTH(34,34,26.1),
+      372E0,
+      "OKAYAMA",
+      "Okayama 1.88 metre"
+    },
+    /* Kitt Peak Mayall 4m (1981 Almanac)                            KPNO158 */
+    {
+      WEST(111,35,57.61),
+      NORTH(31,57,50.3),
+      2120E0,
+      "KPNO158",
+      "Kitt Peak 158 inch"
+    },
+    /* Kitt Peak 90 inch (1981 Almanac)                               KPNO90 */
+    {
+      WEST(111,35,58.24),
+      NORTH(31,57,46.9),
+      2071E0,
+      "KPNO90",
+      "Kitt Peak 90 inch"
+    },
+    /* Kitt Peak 84 inch (1981 Almanac)                               KPNO84 */
+    {
+      WEST(111,35,51.56),
+      NORTH(31,57,29.2),
+      2096E0,
+      "KPNO84",
+      "Kitt Peak 84 inch"
+    },
+    /* Kitt Peak 36 foot (1981 Almanac)                             KPNO36FT */
+    {
+      WEST(111,36,51.12),
+      NORTH(31,57,12.1),
+      1939E0,
+      "KPNO36FT",
+      "Kitt Peak 36 foot"
+    },
+    /* Kottamia 74" (1981 Almanac)                                  KOTTAMIA */
+    {
+      EAST(31,49,30.),
+      NORTH(29,55,54.),
+      476E0,
+      "KOTTAMIA",
+      "Kottamia 74 inch"
+    },
+    /* La Silla 3.6m (1981 Almanac)                                   ESO3.6 */
+    {
+      WEST(70,43,36.),
+      SOUTH(29,15,36.),
+      2428E0,
+      "ESO3.6",
+      "ESO 3.6 metre"
+    },
+    /* Mauna Kea 88 inch                                            MAUNAK88 */
+    /* (IfA website, Richard Wainscoat) */
+    {
+      WEST(155,28,9.96),
+      NORTH(19,49,22.77),
+      4213.6E0,
+      "MAUNAK88",
+      "Mauna Kea 88 inch"
+    },
+    /* UKIRT (IfA website, Richard Wainscoat)                          UKIRT */
+    {
+      WEST(155,28,13.18),
+      NORTH(19,49,20.75),
+      4198.5E0,
+      "UKIRT",
+      "UK Infra Red Telescope"
+    },
+    /* Quebec 1.6m (1981 Almanac)                                  QUEBEC1.6 */
+    {
+      WEST(71,9,9.7),
+      NORTH(45,27,20.6),
+      1114E0,
+      "QUEBEC1.6",
+      "Quebec 1.6 metre"
+    },
+    /* Mt Ekar 1.82m (1981 Almanac)                                   MTEKAR */
+    {
+      EAST(11,34,15.),
+      NORTH(45,50,48.),
+      1365E0,
+      "MTEKAR",
+      "Mt Ekar 1.82 metre"
+    },
+    /* Mt Lemmon 60" (1981 Almanac)                               MTLEMMON60 */
+    {
+      WEST(110,42,16.9),
+      NORTH(32,26,33.9),
+      2790E0,
+      "MTLEMMON60",
+      "Mt Lemmon 60 inch"
+    },
+    /* Mt Locke 2.7m (1981 Almanac)                               MCDONLD2.7 */
+    {
+      WEST(104,1,17.60),
+      NORTH(30,40,17.7),
+      2075E0,
+      "MCDONLD2.7",
+      "McDonald 2.7 metre"
+    },
+    /* Mt Locke 2.1m (1981 Almanac)                               MCDONLD2.1 */
+    {
+      WEST(104,1,20.10),
+      NORTH(30,40,17.7),
+      2075E0,
+      "MCDONLD2.1",
+      "McDonald 2.1 metre"
+    },
+    /* Palomar 200" (1981 Almanac)                                PALOMAR200 */
+    {
+      WEST(116,51,50.),
+      NORTH(33,21,22.),
+      1706E0,
+      "PALOMAR200",
+      "Palomar 200 inch"
+    },
+    /* Palomar 60" (1981 Almanac)                                  PALOMAR60 */
+    {
+      WEST(116,51,31.),
+      NORTH(33,20,56.),
+      1706E0,
+      "PALOMAR60",
+      "Palomar 60 inch"
+    },
+    /* David Dunlap 74" (1981 Almanac)                              DUNLAP74 */
+    {
+      WEST(79,25,20.),
+      NORTH(43,51,46.),
+      244E0,
+      "DUNLAP74",
+      "David Dunlap 74 inch"
+    },
+    /* Haute Provence 1.93m (1981 Almanac)                         HPROV1.93 */
+    {
+      EAST(5,42,46.75),
+      NORTH(43,55,53.3),
+      665E0,
+      "HPROV1.93",
+      "Haute Provence 1.93 metre"
+    },
+    /* Haute Provence 1.52m (1981 Almanac)                         HPROV1.52 */
+    {
+      EAST(5,42,43.82),
+      NORTH(43,56,0.2),
+      667E0,
+      "HPROV1.52",
+      "Haute Provence 1.52 metre"
+    },
+    /* San Pedro Martir 83" (1981 Almanac)                           SANPM83 */
+    {
+      WEST(115,27,47.),
+      NORTH(31,2,38.),
+      2830E0,
+      "SANPM83",
+      "San Pedro Martir 83 inch"
+    },
+    /* Sutherland 74" (1981 Almanac)                                  SAAO74 */
+    {
+      EAST(20,48,44.3),
+      SOUTH(32,22,43.4),
+      1771E0,
+      "SAAO74",
+      "Sutherland 74 inch"
+    },
+    /* Tautenburg 2m (1981 Almanac)                                  TAUTNBG */
+    {
+      EAST(11,42,45.),
+      NORTH(50,58,51.),
+      331E0,
+      "TAUTNBG",
+      "Tautenburg 2 metre"
+    },
+    /* Catalina 61" (1981 Almanac)                                CATALINA61 */
+    {
+      WEST(110,43,55.1),
+      NORTH(32,25,0.7),
+      2510E0,
+      "CATALINA61",
+      "Catalina 61 inch"
+    },
+    /* Steward 90" (1981 Almanac)                                  STEWARD90 */
+    {
+      WEST(111,35,58.24),
+      NORTH(31,57,46.9),
+      2071E0,
+      "STEWARD90",
+      "Steward 90 inch"
+    },
+    /* Russian 6m (1981 Almanac)                                       USSR6 */
+    {
+      EAST(41,26,30.0),
+      NORTH(43,39,12.),
+      2100E0,
+      "USSR6",
+      "USSR 6 metre"
+    },
+    /* Arecibo 1000' (1981 Almanac)                                  ARECIBO */
+    {
+      WEST(66,45,11.1),
+      NORTH(18,20,36.6),
+      496E0,
+      "ARECIBO",
+      "Arecibo 1000 foot"
+    },
+    /* Cambridge 5km (1981 Almanac)                                  CAMB5KM */
+    {
+      EAST(0,2,37.23),
+      NORTH(52,10,12.2),
+      17E0,
+      "CAMB5KM",
+      "Cambridge 5km"
+    },
+    /* Cambridge 1 mile (1981 Almanac)                             CAMB1MILE */
+    {
+      EAST(0,2,21.64),
+      NORTH(52,9,47.3),
+      17E0,
+      "CAMB1MILE",
+      "Cambridge 1 mile"
+    },
+    /* Bonn 100m (1981 Almanac)                                   EFFELSBERG */
+    {
+      EAST(6,53,1.5),
+      NORTH(50,31,28.6),
+      366E0,
+      "EFFELSBERG",
+      "Effelsberg 100 metre"
+    },
+    /* Greenbank 300' (1981 Almanac)                        GBVA300 (R.I.P.) */
+    {
+      WEST(79,50,56.36),
+      NORTH(38,25,46.3),
+      894E0,
+      "(R.I.P.)",
+      "Greenbank 300 foot"
+    },
+    /* Jodrell Bank Mk 1 (1981 Almanac)                             JODRELL1 */
+    {
+      WEST(2,18,25.),
+      NORTH(53,14,10.5),
+      78E0,
+      "JODRELL1",
+      "Jodrell Bank 250 foot"
+    },
+    /* Australia Telescope Parkes Observatory                         PARKES */
+    /* (Peter te Lintel Hekkert) */
+    {
+      EAST(148,15,44.3591),
+      SOUTH(32,59,59.8657),
+      391.79E0,
+      "PARKES",
+      "Parkes 64 metre"
+    },
+    /* VLA (1981 Almanac)                                                VLA */
+    {
+      WEST(107,37,3.82),
+      NORTH(34,4,43.5),
+      2124E0,
+      "VLA",
+      "Very Large Array"
+    },
+    /* Sugar Grove 150' (1981 Almanac)                            SUGARGROVE */
+    {
+      WEST(79,16,23.),
+      NORTH(38,31,14.),
+      705E0,
+      "SUGARGROVE",
+      "Sugar Grove 150 foot"
+    },
+    /* Russian 600' (1981 Almanac)                                   USSR600 */
+    {
+      EAST(41,35,25.5),
+      NORTH(43,49,32.),
+      973E0,
+      "USSR600",
+      "USSR 600 foot"
+    },
+    /* Nobeyama 45 metre mm dish (based on 1981 Almanac entry)      NOBEYAMA */
+    {
+      EAST(138,29,12.),
+      NORTH(35,56,19.),
+      1350E0,
+      "NOBEYAMA",
+      "Nobeyama 45 metre"
+    },
+    /* James Clerk Maxwell 15 metre mm telescope, Mauna Kea             JCMT */
+    /* From GPS measurements on 11Apr2007 for eSMA setup (R. Tilanus) */
+    {
+      WEST(155,28,37.30),
+      NORTH(19,49,22.22),
+      4124.75E0,
+      "JCMT",
+      "JCMT 15 metre"
+    },
+    /* ESO 3.5 metre NTT, La Silla (K.Wirenstrand)                    ESONTT */
+    {
+      WEST(70,43,7.),
+      SOUTH(29,15,30.),
+      2377E0,
+      "ESONTT",
+      "ESO 3.5 metre NTT"
+    },
+    /* St Andrews University Observatory (1982 Almanac)           ST.ANDREWS */
+    {
+      WEST(2,48,52.5),
+      NORTH(56,20,12.),
+      30E0,
+      "ST.ANDREWS",
+      "St Andrews"
+    },
+    /* Apache Point 3.5 metre (R.Owen)                                APO3.5 */
+    {
+      WEST(105,49,11.56),
+      NORTH(32,46,48.96),
+      2809E0,
+      "APO3.5",
+      "Apache Point 3.5m"
+    },
+    /* W.M.Keck Observatory, Telescope 1                               KECK1 */
+    /* (William Lupton) */
+    {
+      WEST(155,28,28.99),
+      NORTH(19,49,33.41),
+      4160E0,
+      "KECK1",
+      "Keck 10m Telescope #1"
+    },
+    /* Tautenberg Schmidt (1983 Almanac)                            TAUTSCHM */
+    {
+      EAST(11,42,45.0),
+      NORTH(50,58,51.0),
+      331E0,
+      "TAUTSCHM",
+      "Tautenberg 1.34 metre Schmidt"
+    },
+    /* Palomar Schmidt (1981 Almanac)                              PALOMAR48 */
+    {
+      WEST(116,51,32.0),
+      NORTH(33,21,26.0),
+      1706E0,
+      "PALOMAR48",
+      "Palomar 48-inch Schmidt"
+    },
+    /* UK Schmidt, Siding Spring (1983 Almanac)                         UKST */
+    {
+      EAST(149,4,12.8),
+      SOUTH(31,16,27.8),
+      1145E0,
+      "UKST",
+      "UK 1.2 metre Schmidt, Siding Spring"
+    },
+    /* Kiso Schmidt, Japan (1981 Almanac)                               KISO */
+    {
+      EAST(137,37,42.2),
+      NORTH(35,47,38.7),
+      1130E0,
+      "KISO",
+      "Kiso 1.05 metre Schmidt, Japan"
+    },
+    /* ESO Schmidt, La Silla (1981 Almanac)                          ESOSCHM */
+    {
+      WEST(70,43,46.5),
+      SOUTH(29,15,25.8),
+      2347E0,
+      "ESOSCHM",
+      "ESO 1 metre Schmidt, La Silla"
+    },
+    /* Australia Telescope Compact Array                                ATCA */
+    /* (WGS84 coordinates of Station 35, Mark Calabretta) */
+    {
+      EAST(149,33,0.500),
+      SOUTH(30,18,46.385),
+      236.9E0,
+      "ATCA",
+      "Australia Telescope Compact Array"
+    },
+    /* Australia Telescope Mopra Observatory                           MOPRA */
+    /* (Peter te Lintel Hekkert) */
+    {
+      EAST(149,5,58.732),
+      SOUTH(31,16,4.451),
+      850E0,
+      "MOPRA",
+      "ATNF Mopra Observatory"
+    },
+    /* Subaru telescope, Mauna Kea                                     SUBARU */
+    /* (IfA website, Richard Wainscoat) */
+    {
+      WEST(155,28,33.67),
+      NORTH(19,49,31.81),
+      4163E0,
+      "SUBARU",
+      "Subaru 8m telescope"
+    },
+    /* Canada-France-Hawaii Telescope, Mauna Kea                         CFHT */
+    /* (IfA website, Richard Wainscoat) */
+    {
+      WEST(155,28,7.95),
+      NORTH(19,49,30.91),
+      4204.1E0,
+      "CFHT",
+      "Canada-France-Hawaii 3.6m Telescope"
+    },
+    /* W.M.Keck Observatory, Telescope 2                                KECK2 */
+    /* (William Lupton) */
+    {
+      WEST(155,28,27.24),
+      NORTH(19,49,35.62),
+      4159.6E0,
+      "KECK2",
+      "Keck 10m Telescope #2"
+    },
+    /* Gemini North, Mauna Kea                                        GEMININ */
+    /* (IfA website, Richard Wainscoat) */
+    {
+      WEST(155,28,8.57),
+      NORTH(19,49,25.69),
+      4213.4E0,
+      "GEMININ",
+      "Gemini North 8-m telescope"
+    },
+    /* Five College Radio Astronomy Observatory                        FCRAO */
+    /* (Tim Jenness) */
+    {
+      WEST(72,20,42.0),
+      NORTH(42,23,30.0),
+      314E0,
+      "FCRAO",
+      "Five College Radio Astronomy Obs"
+    },
+    /* NASA Infra Red Telescope Facility                                IRTF */
+    /* (IfA website, Richard Wainscoat) */
+    {
+      WEST(155,28,19.20),
+      NORTH(19,49,34.39),
+      4168.1E0,
+      "IRTF",
+      "NASA IR Telescope Facility, Mauna Kea"
+    },
+    /* Caltech Submillimeter Observatory                                 CSO */
+    /* (IfA website, Richard Wainscoat; height estimated) */
+    {
+      WEST(155,28,31.79),
+      NORTH(19,49,20.78),
+      4080E0,
+      "CSO",
+      "Caltech Sub-mm Observatory, Mauna Kea"
+    },
+    /* ESO VLT, UT1                                                       VLT1 */
+    /* (ESO website, VLT Whitebook Chapter 2) */
+    {
+      WEST(70,24,11.642),
+      SOUTH(24,37,33.117),
+      2635.43,
+      "VLT1",
+      "ESO VLT, Paranal, Chile: UT1"
+    },
+    /* ESO VLT, UT2                                                       VLT2 */
+    /* (ESO website, VLT Whitebook Chapter 2) */
+    {
+      WEST(70,24,10.855),
+      SOUTH(24,37,31.465),
+      2635.43,
+      "VLT2",
+      "ESO VLT, Paranal, Chile: UT2"
+    },
+    /* ESO VLT, UT3                                                       VLT3 */
+    /* (ESO website, VLT Whitebook Chapter 2) */
+    {
+      WEST(70,24,9.896),
+      SOUTH(24,37,30.300),
+      2635.43,
+      "VLT3",
+      "ESO VLT, Paranal, Chile: UT3"
+    },
+    /* ESO VLT, UT4                                                       VLT4 */
+    /* (ESO website, VLT Whitebook Chapter 2) */
+    {
+      WEST(70,24,8.000),
+      SOUTH(24,37,31.000),
+      2635.43,
+      "VLT4",
+      "ESO VLT, Paranal, Chile: UT4"
+    },
+    /* Gemini South, Cerro Pachon                                     GEMINIS */
+    /* (GPS readings by Patrick Wallace) */
+    {
+      WEST(70,44,11.5),
+      SOUTH(30,14,26.7),
+      2738E0,
+      "GEMINIS",
+      "Gemini South 8-m telescope"
+    },
+    /* Cologne Observatory for Submillimeter Astronomy (KOSMA)        KOSMA3M */
+    /* (Holger Jakob) */
+    {
+      EAST(7,47,3.48),
+      NORTH(45,58,59.772),
+      3141E0,
+      "KOSMA3M",
+      "KOSMA 3m telescope, Gornergrat"
+    },
+    /* Magellan 1, 6.5m telescope at Las Campanas, Chile            MAGELLAN1 */
+    /* (Skip Schaller) */
+    {
+      WEST(70,41,31.9),
+      SOUTH(29,0,51.7),
+      2408E0,
+      "MAGELLAN1",
+      "Magellan 1, 6.5m, Las Campanas"
+    },
+    /* Magellan 2, 6.5m telescope at Las Campanas, Chile            MAGELLAN2 */
+    /* (Skip Schaller) */
+    {
+      WEST(70,41,33.5),
+      SOUTH(29,0,50.3),
+      2408E0,
+      "MAGELLAN2",
+      "Magellan 2, 6.5m, Las Campanas"
+    },
+    /* APEX - Atacama Pathfinder EXperiment, Llano de Chajnantor    APEX */
+    /* (APEX web site) */
+    {
+      WEST(67,45,33.0),
+      SOUTH(23,0,20.8),
+      5105E0,
+      "APEX",
+      "APEX 12m telescope, Llano de Chajnantor"
+    },
+    /* NANTEN2 Submillimeter Observatory, 4m telescope Atacame desert NANTEN2 */
+    /* (NANTEN2 web site) */
+    {
+      WEST(67,42,8.0),
+      SOUTH(22,57,47.0),
+      4865E0,
+      "NANTEN2",
+      "NANTEN2 4m telescope, Pampa la Bola"
+    }
+  };
+
+  int retval = -1;    /* Return status. 0 if found. -1 if no match */
+
+  /* Work out the number of telescopes */
+  const size_t NTEL = sizeof(telData) / sizeof(struct telData);
+
+  /* Prefill the return buffer in a pessimistic manner */
+  star_strellcpy( name, "?", namelen );
+
+  if (n > 0) {
+    if (n <= NTEL) {
+      /* Index into telData with correction for zero-based indexing */
+      struct telData thistel;
+      thistel = telData[n-1];
+      *w = thistel.w;
+      *p = thistel.p;
+      *h = thistel.h;
+      star_strellcpy( ident, thistel.shortname, identlen );
+      star_strellcpy( name, thistel.longname, namelen );
+      retval = 0;
+    }
+
+  } else {
+    /* Searching */
+    size_t i;
+    for (i=0; i<NTEL; i++) {
+      struct telData thistel = telData[i];
+      if (strcasecmp( c, thistel.shortname) == 0) {
+        /* a match */
+        *w = thistel.w;
+        *p = thistel.p;
+        *h = thistel.h;
+        star_strellcpy( ident, thistel.shortname, identlen );
+        star_strellcpy( name, thistel.longname, namelen );
+        retval = 0;
+        break;
+      }
+    }
+
+  }
+
+  return retval;
+
+}
Index: trunk/FACT++/pal/palOne2One.c
===================================================================
--- trunk/FACT++/pal/palOne2One.c	(revision 18347)
+++ trunk/FACT++/pal/palOne2One.c	(revision 18347)
@@ -0,0 +1,1482 @@
+/*
+*+
+*  Name:
+*     palOne2One
+
+*  Purpose:
+*     File containing simple PAL wrappers for SLA routines that are identical in SOFA
+
+*  Invocation:
+*     Matches SLA API
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Description:
+*     Some SOFA/ERFA routines are identical to their SLA counterparts. PAL provides
+*     direct counterparts to these although it is generally a better idea to
+*     use the SOFA/ERFA routine directly in new code.
+*
+*     The PAL routines with direct equivalents in SOFA/ERFA are:
+*     - palCldj
+*     - palDbear
+*     - palDaf2r
+*     - palDav2m
+*     - palDcc2s
+*     - palDcs2c
+*     - palDd2tf
+*     - palDimxv
+*     - palDm2av
+*     - palDjcl
+*     - palDmxm
+*     - palDmxv
+*     - palDpav
+*     - palDr2af
+*     - palDr2tf
+*     - palDranrm
+*     - palDsep
+*     - palDsepv
+*     - palDtf2d
+*     - palDtf2r
+*     - palDvdv
+*     - palDvn
+*     - palDvxv
+*     - palEpb
+*     - palEpb2d
+*     - palEpj
+*     - palEpj2d
+*     - palEqeqx
+*     - palFk5hz
+*     - palGmst
+*     - palGmsta
+*     - palHfk5z
+*     - palRefcoq
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     DSB: David S Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Do not call these functions from other PAL functions. Always use
+*       the SOFA/ERFA routines directly in new code.
+*     - These are implemented as real functions rather than C preprocessor
+*       macros so there may be a performance penalty in using the PAL
+*       version instead of the SOFA/ERFA version.
+*     - Routines that take MJDs have SOFA/ERFA equivalents that have an explicit
+*       MJD offset included.
+*     - palEqeqx, palGmst and palGmsta use the IAU 2006 precession model.
+
+*  History:
+*     2012-02-10 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     2012-03-23 (TIMJ):
+*        Update prologue.
+*     2012-05-09 (DSBJ):
+*        Move palDrange into a separate file.
+*     2014-07-15 (TIMJ):
+*        SOFA now has palRefcoq equivalent.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2014 Tim Jenness
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+/*
+*+
+*  Name:
+*     palCldj
+
+*  Purpose:
+*     Gregorian Calendar to Modified Julian Date
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palCldj( int iy, int im, int id, double *djm, int *j );
+
+*  Arguments:
+*     iy = int (Given)
+*        Year in Gregorian calendar
+*     im = int (Given)
+*        Month in Gregorian calendar
+*     id = int (Given)
+*        Day in Gregorian calendar
+*     djm = double * (Returned)
+*        Modified Julian Date (JD-2400000.5) for 0 hrs
+*     j = int * (Returned)
+*        status: 0 = OK, 1 = bad year (MJD not computed),
+*        2 = bad month (MJD not computed), 3 = bad day (MJD computed).
+
+*  Description:
+*     Gregorian calendar to Modified Julian Date.
+
+*  Notes:
+*     - Uses eraCal2jd(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palCldj ( int iy, int im, int id, double *djm, int *j ) {
+  double djm0;
+  *j = eraCal2jd( iy, im, id, &djm0, djm );
+}
+
+/*
+*+
+*  Name:
+*     palDbear
+
+*  Purpose:
+*     Bearing (position angle) of one point on a sphere relative to another
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     pa = palDbear( double a1, double b1, double a2, double b2 );
+
+*  Arguments:
+*     a1 = double (Given)
+*        Longitude of point A (e.g. RA) in radians.
+*     a2 = double (Given)
+*        Latitude of point A (e.g. Dec) in radians.
+*     b1 = double (Given)
+*        Longitude of point B in radians.
+*     b2 = double (Given)
+*        Latitude of point B in radians.
+
+*  Returned Value:
+*     The result is the bearing (position angle), in radians, of point
+*     A2,B2 as seen from point A1,B1.  It is in the range +/- pi.  If
+*     A2,B2 is due east of A1,B1 the bearing is +pi/2.  Zero is returned
+*     if the two points are coincident.
+
+*  Description:
+*     Bearing (position angle) of one point in a sphere relative to another.
+
+*  Notes:
+*     - Uses eraPas(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDbear ( double a1, double b1, double a2, double b2 ) {
+  return eraPas( a1, b1, a2, b2 );
+}
+
+/*
+*+
+*  Name:
+*     palDaf2r
+
+*  Purpose:
+*     Convert degrees, arcminutes, arcseconds to radians
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDaf2r( int ideg, int iamin, double asec, double *rad, int *j );
+
+*  Arguments:
+*     ideg = int (Given)
+*        Degrees.
+*     iamin = int (Given)
+*        Arcminutes.
+*     iasec = double (Given)
+*        Arcseconds.
+*     rad = double * (Returned)
+*        Angle in radians.
+*     j = int * (Returned)
+*        Status: 0 = OK, 1 = "ideg" out of range 0-359,
+*                2 = "iamin" outside of range 0-59,
+*                2 = "asec" outside range 0-59.99999
+
+*  Description:
+*     Convert degrees, arcminutes, arcseconds to radians.
+
+*  Notes:
+*     - Uses eraAf2a(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Arguments differ slightly. Assumes that the sign is always positive
+   and dealt with externally. */
+void palDaf2r ( int ideg, int iamin, double asec, double *rad, int *j ) {
+  *j = eraAf2a( ' ', ideg, iamin, asec, rad );
+}
+
+/*
+*+
+*  Name:
+*     palDav2m
+
+*  Purpose:
+*     Form the rotation matrix corresponding to a given axial vector.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDav2m( double axvec[3], double rmat[3][3] );
+
+*  Arguments:
+*     axvec = double [3] (Given)
+*       Axial vector (radians)
+*     rmat = double [3][3] (Returned)
+*       Rotation matrix.
+
+*  Description:
+*     A rotation matrix describes a rotation about some arbitrary axis,
+*     called the Euler axis.  The "axial vector" supplied to this routine
+*     has the same direction as the Euler axis, and its magnitude is the
+*     amount of rotation in radians.
+
+*  Notes:
+*     - Uses eraRv2m(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDav2m ( double axvec[3], double rmat[3][3] ) {
+  eraRv2m( axvec, rmat );
+}
+
+/*
+*+
+*  Name:
+*     palDcc2s
+
+*  Purpose:
+*     Cartesian to spherical coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDcc2s( double v[3], double *a, double *b );
+
+*  Arguments:
+*     v = double [3] (Given)
+*        x, y, z vector.
+*     a = double * (Returned)
+*        Spherical coordinate (radians)
+*     b = double * (Returned)
+*        Spherical coordinate (radians)
+
+*  Description:
+*     The spherical coordinates are longitude (+ve anticlockwise looking
+*     from the +ve latitude pole) and latitude.  The Cartesian coordinates
+*     are right handed, with the x axis at zero longitude and latitude, and
+*     the z axis at the +ve latitude pole.
+
+*  Notes:
+*     - Uses eraC2s(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDcc2s ( double v[3], double *a, double *b ) {
+  eraC2s( v, a, b );
+}
+
+/*
+*+
+*  Name:
+*     palDcs2c
+
+*  Purpose:
+*     Spherical coordinates to direction cosines
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDcs2c( double a, double b, double v[3] );
+
+*  Arguments:
+*     a = double (Given)
+*        Spherical coordinate in radians (ra, long etc).
+*     b = double (Given)
+*        Spherical coordinate in radians (dec, lat etc).
+*     v = double [3] (Returned)
+*        x, y, z vector
+
+*  Description:
+*     The spherical coordinates are longitude (+ve anticlockwise looking
+*     from the +ve latitude pole) and latitude.  The Cartesian coordinates
+*     are right handed, with the x axis at zero longitude and latitude, and
+*     the z axis at the +ve latitude pole.
+
+*  Notes:
+*     - Uses eraS2c(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDcs2c ( double a, double b, double v[3] ) {
+  eraS2c( a, b, v );
+}
+
+/*
+*+
+*  Name:
+*     palDd2tf
+
+*  Purpose:
+*     Convert an interval in days into hours, minutes, seconds
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDd2tf( int ndp, double days, char *sign, int ihmsf[4] );
+
+*  Arguments:
+*     ndp = int (Given)
+*        Number of decimal places of seconds
+*     days = double (Given)
+*        Interval in days
+*     sign = char * (Returned)
+*        '+' or '-' (single character, not string)
+*     ihmsf = int [4] (Returned)
+*        Hours, minutes, seconds, fraction
+
+*  Description:
+*     Convert and interval in days into hours, minutes, seconds.
+
+*  Notes:
+*     - Uses eraD2tf(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDd2tf ( int ndp, double days, char *sign, int ihmsf[4] ) {
+  eraD2tf( ndp, days, sign, ihmsf );
+}
+
+/*
+*+
+*  Name:
+*     palDimxv
+
+*  Purpose:
+*     Perform the 3-D backward unitary transformation
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDimxv( double dm[3][3], double va[3], double vb[3] );
+
+*  Arguments:
+*     dm = double [3][3] (Given)
+*        Matrix
+*     va = double [3] (Given)
+*        vector
+*     vb = double [3] (Returned)
+*        Result vector
+
+*  Description:
+*     Perform the 3-D backward unitary transformation.
+
+*  Notes:
+*     - Uses eraTrxp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDimxv ( double dm[3][3], double va[3], double vb[3] ) {
+  eraTrxp( dm, va, vb );
+}
+
+/*
+*+
+*  Name:
+*     palDm2av
+
+*  Purpose:
+*     From a rotation matrix, determine the corresponding axial vector
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDm2av( double rmat[3][3], double axvec[3] );
+
+*  Arguments:
+*     rmat = double [3][3] (Given)
+*        Rotation matrix
+*     axvec = double [3] (Returned)
+*        Axial vector (radians)
+
+*  Description:
+*     A rotation matrix describes a rotation about some arbitrary axis,
+*     called the Euler axis.  The "axial vector" returned by this routine
+*     has the same direction as the Euler axis, and its magnitude is the
+*     amount of rotation in radians.  (The magnitude and direction can be
+*     separated by means of the routine palDvn.)
+
+*  Notes:
+*     - Uses eraRm2v(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDm2av ( double rmat[3][3], double axvec[3] ) {
+  eraRm2v( rmat, axvec );
+}
+
+/*
+*+
+*  Name:
+*     palDjcl
+
+*  Purpose:
+*     Modified Julian Date to Gregorian year, month, day and fraction of day
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDjcl( double djm, int *iy, int *im, int *id, double *fd, int *j );
+
+*  Arguments:
+*     djm = double (Given)
+*        modified Julian Date (JD-2400000.5)
+*     iy = int * (Returned)
+*        year
+*     im = int * (Returned)
+*        month
+*     id = int * (Returned)
+*        day
+*     fd = double * (Returned)
+*        Fraction of day.
+
+*  Description:
+*     Modified Julian Date to Gregorian year, month, day and fraction of day.
+
+*  Notes:
+*     - Uses eraJd2cal(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Requires additional SLA MJD reference date */
+void palDjcl ( double djm, int *iy, int *im, int *id, double *fd, int *j ) {
+  *j = eraJd2cal( PAL__MJD0, djm, iy, im, id, fd );
+}
+
+/*
+*+
+*  Name:
+*     palDmxm
+
+*  Purpose:
+*     Product of two 3x3 matrices
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDmxm( double a[3][3], double b[3][3], double c[3][3] );
+
+*  Arguments:
+*     a = double [3][3] (Given)
+*        Matrix
+*     b = double [3][3] (Given)
+*        Matrix
+*     c = double [3][3] (Returned)
+*        Matrix result
+
+*  Description:
+*     Product of two 3x3 matrices.
+
+*  Notes:
+*     - Uses eraRxr(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDmxm ( double a[3][3], double b[3][3], double c[3][3] ) {
+  eraRxr( a, b, c );
+}
+
+/*
+*+
+*  Name:
+*     palDmxv
+
+*  Purpose:
+*     Performs the 3-D forward unitary transformation
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDmxv( double dm[3][3], double va[3], double vb[3] );
+
+*  Arguments:
+*     dm = double [3][3] (Given)
+*        matrix
+*     va = double [3] (Given)
+*        vector
+*     dp = double [3] (Returned)
+*        result vector
+
+*  Description:
+*     Performs the 3-D forward unitary transformation.
+
+*  Notes:
+*     - Uses eraRxp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDmxv ( double dm[3][3], double va[3], double vb[3] ) {
+  eraRxp( dm, va, vb );
+}
+
+/*
+*+
+*  Name:
+*     palDpav
+
+*  Purpose:
+*     Position angle of one celestial direction with respect to another
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     pa = palDpav( double v1[3], double v2[3] );
+
+*  Arguments:
+*     v1 = double [3] (Given)
+*        direction cosines of one point.
+*     v2 = double [3] (Given)
+*        direction cosines of the other point.
+
+*  Returned Value:
+*     The result is the bearing (position angle), in radians, of point
+*     V2 with respect to point V1.  It is in the range +/- pi.  The
+*     sense is such that if V2 is a small distance east of V1, the
+*     bearing is about +pi/2.  Zero is returned if the two points
+*     are coincident.
+
+*  Description:
+*     Position angle of one celestial direction with respect to another.
+
+*  Notes:
+*     - The coordinate frames correspond to RA,Dec, Long,Lat etc.
+*     - Uses eraPap(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDpav ( double v1[3], double v2[3] ) {
+  return eraPap( v1, v2 );
+}
+
+/*
+*+
+*  Name:
+*     palDr2af
+
+*  Purpose:
+*     Convert an angle in radians to degrees, arcminutes, arcseconds
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDr2af( int ndp, double angle, char *sign, int idmsf[4] );
+
+*  Arguments:
+*     ndp = int (Given)
+*        number of decimal places of arcseconds
+*     angle = double (Given)
+*        angle in radians
+*     sign = char * (Returned)
+*        '+' or '-' (single character)
+*     idmsf = int [4] (Returned)
+*        Degrees, arcminutes, arcseconds, fraction
+
+*  Description:
+*     Convert an angle in radians to degrees, arcminutes, arcseconds.
+
+*  Notes:
+*     - Uses eraA2af(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDr2af ( int ndp, double angle, char *sign, int idmsf[4] ) {
+  eraA2af( ndp, angle, sign, idmsf );
+}
+
+/*
+*+
+*  Name:
+*     palDr2tf
+
+*  Purpose:
+*     Convert an angle in radians to hours, minutes, seconds
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDr2tf ( int ndp, double angle, char *sign, int ihmsf[4] );
+
+*  Arguments:
+*     ndp = int (Given)
+*        number of decimal places of arcseconds
+*     angle = double (Given)
+*        angle in radians
+*     sign = char * (Returned)
+*        '+' or '-' (single character)
+*     idmsf = int [4] (Returned)
+*        Hours, minutes, seconds, fraction
+
+*  Description:
+*     Convert an angle in radians to hours, minutes, seconds.
+
+*  Notes:
+*     - Uses eraA2tf(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDr2tf( int ndp, double angle, char *sign, int ihmsf[4] ) {
+  eraA2tf( ndp, angle, sign, ihmsf );
+}
+
+/*
+*+
+*  Name:
+*     palDranrm
+
+*  Purpose:
+*     Normalize angle into range 0-2 pi
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     norm = palDranrm( double angle );
+
+*  Arguments:
+*     angle = double (Given)
+*        angle in radians
+
+*  Returned Value:
+*     Angle expressed in the range 0-2 pi
+
+*  Description:
+*     Normalize angle into range 0-2 pi.
+
+*  Notes:
+*     - Uses eraAnp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDranrm ( double angle ) {
+  return eraAnp( angle );
+}
+
+/*
+*+
+*  Name:
+*     palDsep
+
+*  Purpose:
+*     Angle between two points on a sphere
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     ang = palDsep( double a1, double b1, double a2, double b2 );
+
+*  Arguments:
+*     a1 = double (Given)
+*        Spherical coordinate of one point (radians)
+*     b1 = double (Given)
+*        Spherical coordinate of one point (radians)
+*     a2 = double (Given)
+*        Spherical coordinate of other point (radians)
+*     b2 = double (Given)
+*        Spherical coordinate of other point (radians)
+
+*  Returned Value:
+*     Angle, in radians, between the two points. Always positive.
+
+*  Description:
+*     Angle between two points on a sphere.
+
+*  Notes:
+*     - The spherical coordinates are [RA,Dec], [Long,Lat] etc, in radians.
+*     - Uses eraSeps(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDsep ( double a1, double b1, double a2, double b2 ) {
+  return eraSeps( a1, b1, a2, b2 );
+}
+
+/*
+*+
+*  Name:
+*     palDsepv
+
+*  Purpose:
+*     Angle between two vectors
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     ang = palDsepv( double v1[3], double v2[3] );
+
+*  Arguments:
+*     v1 = double [3] (Given)
+*        First vector
+*     v2 = double [3] (Given)
+*        Second vector
+
+*  Returned Value:
+*     Angle, in radians, between the two points. Always positive.
+
+*  Description:
+*     Angle between two vectors.
+
+*  Notes:
+*     - Uses eraSepp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDsepv ( double v1[3], double v2[3] ) {
+  return eraSepp( v1, v2 );
+}
+
+/*
+*+
+*  Name:
+*     palDtf2d
+
+*  Purpose:
+*     Convert hours, minutes, seconds to days
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDtf2d( int ihour, int imin, double sec, double *days, int *j );
+
+*  Arguments:
+*     ihour = int (Given)
+*        Hours
+*     imin = int (Given)
+*        Minutes
+*     sec = double (Given)
+*        Seconds
+*     days = double * (Returned)
+*        Interval in days
+*     j = int * (Returned)
+*        status: 0 = ok, 1 = ihour outside range 0-23,
+*        2 = imin outside range 0-59, 3 = sec outside range 0-59.999...
+
+*  Description:
+*     Convert hours, minutes, seconds to days.
+
+*  Notes:
+*     - Uses eraTf2d(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Assumes that the sign is always positive and is dealt with externally */
+void palDtf2d ( int ihour, int imin, double sec, double *days, int *j ) {
+  *j = eraTf2d( ' ', ihour, imin, sec, days );
+}
+
+/*
+*+
+*  Name:
+*     palDtf2r
+
+*  Purpose:
+*     Convert hours, minutes, seconds to radians
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDtf2r( int ihour, int imin, double sec, double *rad, int *j );
+
+*  Arguments:
+*     ihour = int (Given)
+*        Hours
+*     imin = int (Given)
+*        Minutes
+*     sec = double (Given)
+*        Seconds
+*     days = double * (Returned)
+*        Angle in radians
+*     j = int * (Returned)
+*        status: 0 = ok, 1 = ihour outside range 0-23,
+*        2 = imin outside range 0-59, 3 = sec outside range 0-59.999...
+
+*  Description:
+*     Convert hours, minutes, seconds to radians.
+
+*  Notes:
+*     - Uses eraTf2a(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Assumes that the sign is dealt with outside this routine */
+void palDtf2r ( int ihour, int imin, double sec, double *rad, int *j ) {
+  *j = eraTf2a( ' ', ihour, imin, sec, rad );
+}
+
+/*
+*+
+*  Name:
+*     palDvdv
+
+*  Purpose:
+*     Scalar product of two 3-vectors
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     prod = palDvdv ( double va[3], double vb[3] );
+
+*  Arguments:
+*     va = double [3] (Given)
+*        First vector
+*     vb = double [3] (Given)
+*        Second vector
+
+*  Returned Value:
+*     Scalar product va.vb
+
+*  Description:
+*     Scalar product of two 3-vectors.
+
+*  Notes:
+*     - Uses eraPdp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+double palDvdv ( double va[3], double vb[3] ) {
+  return eraPdp( va, vb );
+}
+
+/*
+*+
+*  Name:
+*     palDvn
+
+*  Purpose:
+*     Normalizes a 3-vector also giving the modulus
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDvn( double v[3], double uv[3], double *vm );
+
+*  Arguments:
+*     v = double [3] (Given)
+*        vector
+*     uv = double [3] (Returned)
+*        unit vector in direction of "v"
+*     vm = double * (Returned)
+*        modulus of "v"
+
+*  Description:
+*     Normalizes a 3-vector also giving the modulus.
+
+*  Notes:
+*     - Uses eraPn(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Note that the arguments are flipped */
+void palDvn ( double v[3], double uv[3], double *vm ) {
+  eraPn( v, vm, uv );
+}
+
+/*
+*+
+*  Name:
+*     palDvxv
+
+*  Purpose:
+*     Vector product of two 3-vectors
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palDvxv( double va[3], double vb[3], double vc[3] );
+
+*  Arguments:
+*     va = double [3] (Given)
+*        First vector
+*     vb = double [3] (Given)
+*        Second vector
+*     vc = double [3] (Returned)
+*        Result vector
+
+*  Description:
+*     Vector product of two 3-vectors.
+
+*  Notes:
+*     - Uses eraPxp(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palDvxv ( double va[3], double vb[3], double vc[3] ) {
+  eraPxp( va, vb, vc );
+}
+
+/*
+*+
+*  Name:
+*     palEpb
+
+*  Purpose:
+*     Conversion of modified Julian Data to Besselian Epoch
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     epb = palEpb ( double date );
+
+*  Arguments:
+*     date = double (Given)
+*        Modified Julian Date (JD - 2400000.5)
+
+*  Returned Value:
+*      Besselian epoch.
+
+*  Description:
+*     Conversion of modified Julian Data to Besselian Epoch.
+
+*  Notes:
+*     - Uses eraEpb(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Requires additional SLA MJD reference date */
+double palEpb ( double date ) {
+  return eraEpb( PAL__MJD0, date );
+}
+
+/*
+*+
+*  Name:
+*     palEpb2d
+
+*  Purpose:
+*     Conversion of Besselian Epoch to Modified Julian Date
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     mjd = palEpb2d ( double epb );
+
+*  Arguments:
+*     epb = double (Given)
+*        Besselian Epoch
+
+*  Returned Value:
+*     Modified Julian Date (JD - 2400000.5)
+
+*  Description:
+*     Conversion of Besselian Epoch to Modified Julian Date.
+
+*  Notes:
+*     - Uses eraEpb2jd(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+
+double palEpb2d ( double epb ) {
+  double djm0, djm;
+  eraEpb2jd( epb, &djm0, &djm );
+  return djm;
+}
+
+/*
+*+
+*  Name:
+*     palEpj
+
+*  Purpose:
+*     Conversion of Modified Julian Date to Julian Epoch
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     epj = palEpj ( double date );
+
+*  Arguments:
+*     date = double (Given)
+*        Modified Julian Date (JD - 2400000.5)
+
+*  Returned Value:
+*     The Julian Epoch.
+
+*  Description:
+*     Conversion of Modified Julian Date to Julian Epoch.
+
+*  Notes:
+*     - Uses eraEpj(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Requires additional SLA MJD reference date */
+double palEpj ( double date ) {
+  return eraEpj( PAL__MJD0, date );
+}
+
+/*
+*+
+*  Name:
+*     palEpj2d
+
+*  Purpose:
+*     Conversion of Julian Epoch to Modified Julian Date
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     mjd = palEpj2d ( double epj );
+
+*  Arguments:
+*     epj = double (Given)
+*        Julian Epoch.
+
+*  Returned Value:
+*     Modified Julian Date (JD - 2400000.5)
+
+*  Description:
+*     Conversion of Julian Epoch to Modified Julian Date.
+
+*  Notes:
+*     - Uses eraEpj2d(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+double palEpj2d ( double epj ) {
+  double djm0, djm;
+  eraEpj2jd( epj, &djm0, &djm );
+  return djm;
+}
+
+/*
+*+
+*  Name:
+*     palEqeqx
+
+*  Purpose:
+*     Equation of the equinoxes (IAU 2000/2006)
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palEqeqx( double date );
+
+*  Arguments:
+*     date = double (Given)
+*        TT as Modified Julian Date (JD-400000.5)
+
+*  Description:
+*     Equation of the equinoxes (IAU 2000/2006).
+
+*  Notes:
+*     - Uses eraEe06a(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Requires additional SLA MJD reference date */
+double palEqeqx ( double date ) {
+  return eraEe06a( PAL__MJD0, date );
+}
+
+/*
+*+
+*  Name:
+*     palFk5hz
+
+*  Purpose:
+*     Transform an FK5 (J2000) star position into the frame of the
+*     Hipparcos catalogue.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palFk5hz ( double r5, double d5, double epoch,
+*                double *rh, double *dh );
+
+*  Arguments:
+*     r5 = double (Given)
+*        FK5 RA (radians), equinox J2000, epoch "epoch"
+*     d5 = double (Given)
+*        FK5 dec (radians), equinox J2000, epoch "epoch"
+*     epoch = double (Given)
+*        Julian epoch
+*     rh = double * (Returned)
+*        RA (radians)
+*     dh = double * (Returned)
+*        Dec (radians)
+
+*  Description:
+*     Transform an FK5 (J2000) star position into the frame of the
+*     Hipparcos catalogue.
+
+*  Notes:
+*     - Assumes zero Hipparcos proper motion.
+*     - Uses eraEpj2jd() and eraFk5hz.
+*       See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palFk5hz ( double r5, double d5, double epoch,
+                double *rh, double *dh ) {
+  /* Need to convert epoch to Julian date first */
+  double date1, date2;
+  eraEpj2jd( epoch, &date1, &date2 );
+  eraFk5hz( r5, d5, date1, date2, rh, dh );
+}
+
+/*
+*+
+*  Name:
+*     palGmst
+
+*  Purpose:
+*     Greenwich mean sidereal time (consistent with IAU 2006 precession).
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     mst = palGmst ( double ut1 );
+
+*  Arguments:
+*     ut1 = double (Given)
+*        Universal time (UT1) expressed as modified Julian Date (JD-2400000.5)
+
+*  Returned Value:
+*     Greenwich mean sidereal time
+
+*  Description:
+*     Greenwich mean sidereal time (consistent with IAU 2006 precession).
+
+*  Notes:
+*     - Uses eraGmst06(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Note that SOFA/ERFA has more accurate time arguments
+   and we use the 2006 precession model */
+double palGmst ( double ut1 ) {
+  return eraGmst06( PAL__MJD0, ut1, PAL__MJD0, ut1 );
+}
+
+/*
+*+
+*  Name:
+*     palGmsta
+
+*  Purpose:
+*     Greenwich mean sidereal time (consistent with IAU 2006 precession).
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     mst = palGmsta ( double date, double ut1 );
+
+*  Arguments:
+*     date = double (Given)
+*        UT1 date (MJD: integer part of JD-2400000.5)
+*     ut1 = double (Given)
+*        UT1 time (fraction of a day)
+
+*  Returned Value:
+*     Greenwich mean sidereal time (in range 0 to 2 pi)
+
+*  Description:
+*     Greenwich mean sidereal time (consistent with IAU 2006 precession).
+
+*  Notes:
+*     - For best accuracy use eraGmst06() directly.
+*     - Uses eraGmst06(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+/* Slightly better but still not as accurate as SOFA/ERFA */
+
+double palGmsta( double date, double ut ) {
+  date += PAL__MJD0;
+  return eraGmst06( date, ut, date, ut );
+}
+
+/*
+*+
+*  Name:
+*     palHfk5z
+
+*  Purpose:
+*     Hipparcos star position to FK5 J2000
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palHfk5z( double rh, double dh, double epoch,
+*               double *r5, double *d5, double *dr5, double *dd5 );
+
+*  Arguments:
+*     rh = double (Given)
+*        Hipparcos RA (radians)
+*     dh = double (Given)
+*        Hipparcos Dec (radians)
+*     epoch = double (Given)
+*        Julian epoch (TDB)
+*     r5 = double * (Returned)
+*        RA (radians, FK5, equinox J2000, epoch "epoch")
+*     d5 = double * (Returned)
+*        Dec (radians, FK5, equinox J2000, epoch "epoch")
+
+*  Description:
+*     Transform a Hipparcos star position into FK5 J2000, assuming
+*     zero Hipparcos proper motion.
+
+*  Notes:
+*     - Uses eraEpj2jd and eraHfk5z(). See SOFA/ERFA documentation for details.
+
+*-
+*/
+
+void palHfk5z ( double rh, double dh, double epoch,
+                double *r5, double *d5, double *dr5, double *dd5 ) {
+  /* Need to convert epoch to Julian date first */
+  double date1, date2;
+  eraEpj2jd( epoch, &date1, &date2 );
+  eraHfk5z( rh, dh, date1, date2, r5, d5, dr5, dd5 );
+}
+
+/*
+*+
+*  Name:
+*     palRefcoq
+
+*  Purpose:
+*     Determine the constants A and B in the atmospheric refraction model
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palRefcoq( double tdk, double pmb, double rh, double wl,
+*                double *refa, double *refb );
+
+*  Arguments:
+*     tdk = double (Given)
+*        Ambient temperature at the observer (K)
+*     pmb = double (Given)
+*        Pressure at the observer (millibar)
+*     rh =  double (Given)
+*        Relative humidity at the observer (range 0-1)
+*     wl =  double (Given)
+*        Effective wavelength of the source (micrometre).
+*        Radio refraction is chosen by specifying wl > 100 micrometres.
+*     refa = double * (Returned)
+*        tan Z coefficient (radian)
+*     refb = double * (Returned)
+*        tan**3 Z coefficient (radian)
+
+*  Description:
+*     Determine the constants A and B in the atmospheric refraction
+*     model dZ = A tan Z + B tan**3 Z.  This is a fast alternative
+*     to the palRefco routine.
+*
+*     Z is the "observed" zenith distance (i.e. affected by refraction)
+*     and dZ is what to add to Z to give the "topocentric" (i.e. in vacuo)
+*     zenith distance.
+
+*  Notes:
+*     - Uses eraRefco(). See SOFA/ERFA documentation for details.
+*     - Note that the SOFA/ERFA routine uses different order of
+*       of arguments and uses deg C rather than K.
+
+*-
+*/
+
+void palRefcoq ( double tdk, double pmb, double rh, double wl,
+                 double *refa, double *refb ) {
+  /* Note that SLA (and therefore PAL) uses units of kelvin
+     but SOFA/ERFA uses deg C */
+  eraRefco( pmb, tdk - 273.15, rh, wl, refa, refb );
+}
Index: trunk/FACT++/pal/palPa.c
===================================================================
--- trunk/FACT++/pal/palPa.c	(revision 18347)
+++ trunk/FACT++/pal/palPa.c	(revision 18347)
@@ -0,0 +1,91 @@
+/*
+*+
+*  Name:
+*     palPa
+
+*  Purpose:
+*     HA, Dec to Parallactic Angle
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palPa( double ha, double dec, double phi );
+
+*  Arguments:
+*     ha = double (Given)
+*        Hour angle in radians (Geocentric apparent)
+*     dec = double (Given)
+*        Declination in radians (Geocentric apparent)
+*     phi = double (Given)
+*        Observatory latitude in radians (geodetic)
+
+*  Returned Value:
+*     palPa = double
+*        Parallactic angle in the range -pi to +pi.
+
+*  Description:
+*     Converts HA, Dec to Parallactic Angle.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The parallactic angle at a point in the sky is the position
+*       angle of the vertical, i.e. the angle between the direction to
+*       the pole and to the zenith.  In precise applications care must
+*       be taken only to use geocentric apparent HA,Dec and to consider
+*       separately the effects of atmospheric refraction and telescope
+*       mount errors.
+*     - At the pole a zero result is returned.
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+#include <math.h>
+
+double palPa( double ha, double dec, double phi ) {
+  double cp, sqsz, cqsz;
+
+  cp = cos(phi);
+  sqsz = cp * sin(ha);
+  cqsz = sin(phi) * cos(dec) - cp * sin(dec) * cos(ha);
+  if (sqsz == 0.0 && cqsz == 0.0) cqsz = 1.0;
+  return atan2( sqsz, cqsz );
+}
Index: trunk/FACT++/pal/palPcd.c
===================================================================
--- trunk/FACT++/pal/palPcd.c	(revision 18347)
+++ trunk/FACT++/pal/palPcd.c	(revision 18347)
@@ -0,0 +1,105 @@
+/*
+*+
+*  Name:
+*     palPcd
+
+*  Purpose:
+*     Apply pincushion/barrel distortion to a tangent-plane [x,y]
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palPcd( double disco, double * x, double * y );
+
+*  Arguments:
+*     disco = double (Given)
+*        Pincushion/barrel distortion coefficient.
+*     x = double * (Given & Returned)
+*        On input the tangent-plane X coordinate, on output
+*        the distorted X coordinate.
+*     y = double * (Given & Returned)
+*        On input the tangent-plane Y coordinate, on output
+*        the distorted Y coordinate.
+
+*  Description:
+*     Applies pincushion and barrel distortion to a tangent
+*     plane coordinate.
+
+*  Authors:
+*     PTW: Pat Wallace (RAL)
+*     TIMJ: Tim Jenness
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The distortion is of the form RP = R*(1 + C*R**2), where R is
+*       the radial distance from the tangent point, C is the DISCO
+*       argument, and RP is the radial distance in the presence of
+*       the distortion.
+*
+*     - For pincushion distortion, C is +ve;  for barrel distortion,
+*       C is -ve.
+*
+*     - For X,Y in units of one projection radius (in the case of
+*       a photographic plate, the focal length), the following
+*       DISCO values apply:
+*
+*           Geometry          DISCO
+*
+*           astrograph         0.0
+*           Schmidt           -0.3333
+*           AAT PF doublet  +147.069
+*           AAT PF triplet  +178.585
+*           AAT f/8          +21.20
+*           JKT f/8          +13.32
+*
+*  See Also:
+*     - There is a companion routine, palUnpcd, which performs the
+*       inverse operation.
+
+*  History:
+*     2000-09-03 (PTW):
+*        SLALIB implementation.
+*     2015-01-01 (TIMJ):
+*        Initial version. Ported from Fortran.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2000 Rutherford Appleton Laboratory.
+*     Copyright (C) 2015 Tim Jenness
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or modify
+*     it under the terms of the GNU General Public License as published by
+*     the Free Software Foundation; either version 3 of the License, or
+*     (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program (see SLA_CONDITIONS); if not, write to the
+*     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+*     Boston, MA  02110-1301  USA
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palPcd( double disco, double *x, double *y ) {
+  double f;
+
+  f = 1.0 + disco * ( (*x) * (*x) + (*y) * (*y) );
+  *x *= f;
+  *y *= f;
+}
+
Index: trunk/FACT++/pal/palPertel.c
===================================================================
--- trunk/FACT++/pal/palPertel.c	(revision 18347)
+++ trunk/FACT++/pal/palPertel.c	(revision 18347)
@@ -0,0 +1,212 @@
+/*
+*+
+*  Name:
+*     palPertel
+
+*  Purpose:
+*     Update elements by applying planetary perturbations
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPertel (int jform, double date0, double date1,
+*                     double epoch0, double orbi0, double anode0,
+*                     double perih0, double aorq0, double e0, double am0,
+*                     double *epoch1, double *orbi1, double *anode1,
+*                     double *perih1, double *aorq1, double *e1, double *am1,
+*                     int *jstat );
+
+*  Arguments:
+*     jform = int (Given)
+*        Element set actually returned (1-3; Note 6)
+*     date0 = double (Given)
+*        Date of osculation (TT MJD) for the given elements.
+*     date1 = double (Given)
+*        Date of osculation (TT MJD) for the updated elements.
+*     epoch0 = double (Given)
+*        Epoch of elements (TT MJD)
+*     orbi0 = double (Given)
+*        inclination (radians)
+*     anode0 = double (Given)
+*        longitude of the ascending node (radians)
+*     perih0 = double (Given)
+*        longitude or argument of perihelion (radians)
+*     aorq0 = double (Given)
+*        mean distance or perihelion distance (AU)
+*     e0 = double (Given)
+*        eccentricity
+*     am0 = double (Given)
+*        mean anomaly (radians, JFORM=2 only)
+*     epoch1 = double * (Returned)
+*        Epoch of elements (TT MJD)
+*     orbi1 = double * (Returned)
+*        inclination (radians)
+*     anode1 = double * (Returned)
+*        longitude of the ascending node (radians)
+*     perih1 = double * (Returned)
+*        longitude or argument of perihelion (radians)
+*     aorq1 = double * (Returned)
+*        mean distance or perihelion distance (AU)
+*     e1 = double * (Returned)
+*        eccentricity
+*     am1 = double * (Returned)
+*        mean anomaly (radians, JFORM=2 only)
+*     jstat = int * (Returned)
+*        status:
+*          -      +102 = warning, distant epoch
+*          -      +101 = warning, large timespan ( > 100 years)
+*          - +1 to +10 = coincident with planet (Note 6)
+*          -         0 = OK
+*          -        -1 = illegal JFORM
+*          -        -2 = illegal E0
+*          -        -3 = illegal AORQ0
+*          -        -4 = internal error
+*          -        -5 = numerical error
+
+*  Description:
+*     Update the osculating orbital elements of an asteroid or comet by
+*     applying planetary perturbations.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Two different element-format options are available:
+*
+*       Option JFORM=2, suitable for minor planets:
+*
+*       EPOCH   = epoch of elements (TT MJD)
+*       ORBI    = inclination i (radians)
+*       ANODE   = longitude of the ascending node, big omega (radians)
+*       PERIH   = argument of perihelion, little omega (radians)
+*       AORQ    = mean distance, a (AU)
+*       E       = eccentricity, e
+*       AM      = mean anomaly M (radians)
+*
+*       Option JFORM=3, suitable for comets:
+*
+*       EPOCH   = epoch of perihelion (TT MJD)
+*       ORBI    = inclination i (radians)
+*       ANODE   = longitude of the ascending node, big omega (radians)
+*       PERIH   = argument of perihelion, little omega (radians)
+*       AORQ    = perihelion distance, q (AU)
+*       E       = eccentricity, e
+*
+*     - DATE0, DATE1, EPOCH0 and EPOCH1 are all instants of time in
+*       the TT timescale (formerly Ephemeris Time, ET), expressed
+*       as Modified Julian Dates (JD-2400000.5).
+*
+*       DATE0 is the instant at which the given (i.e. unperturbed)
+*       osculating elements are correct.
+*
+*       DATE1 is the specified instant at which the updated osculating
+*       elements are correct.
+*
+*       EPOCH0 and EPOCH1 will be the same as DATE0 and DATE1
+*       (respectively) for the JFORM=2 case, normally used for minor
+*       planets.  For the JFORM=3 case, the two epochs will refer to
+*       perihelion passage and so will not, in general, be the same as
+*       DATE0 and/or DATE1 though they may be similar to one another.
+*     - The elements are with respect to the J2000 ecliptic and equinox.
+*     - Unused elements (AM0 and AM1 for JFORM=3) are not accessed.
+*     - See the palPertue routine for details of the algorithm used.
+*     - This routine is not intended to be used for major planets, which
+*       is why JFORM=1 is not available and why there is no opportunity
+*       to specify either the longitude of perihelion or the daily
+*       motion.  However, if JFORM=2 elements are somehow obtained for a
+*       major planet and supplied to the routine, sensible results will,
+*       in fact, be produced.  This happens because the palPertue routine
+*       that is called to perform the calculations checks the separation
+*       between the body and each of the planets and interprets a
+*       suspiciously small value (0.001 AU) as an attempt to apply it to
+*       the planet concerned.  If this condition is detected, the
+*       contribution from that planet is ignored, and the status is set to
+*       the planet number (1-10 = Mercury, Venus, EMB, Mars, Jupiter,
+*       Saturn, Uranus, Neptune, Earth, Moon) as a warning.
+*
+*  See Also:
+*     - Sterne, Theodore E., "An Introduction to Celestial Mechanics",
+*       Interscience Publishers Inc., 1960.  Section 6.7, p199.
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version direct conversion of SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palPertel (int jform, double date0, double date1,
+                double epoch0, double orbi0, double anode0,
+                double perih0, double aorq0, double e0, double am0,
+                double *epoch1, double *orbi1, double *anode1,
+                double *perih1, double *aorq1, double *e1, double *am1,
+                int *jstat ) {
+
+  double u[13], dm;
+  int j, jf;
+
+  /*  Check that the elements are either minor-planet or comet format. */
+  if (jform < 2 || jform > 3) {
+    *jstat = -1;
+    return;
+  } else {
+
+    /*     Provisionally set the status to OK. */
+    *jstat = 0;
+  }
+
+  /*  Transform the elements from conventional to universal form. */
+  palEl2ue(date0,jform,epoch0,orbi0,anode0,perih0,
+           aorq0,e0,am0,0.0,u,&j);
+  if (j != 0) {
+    *jstat = j;
+    return;
+  }
+
+  /*  Update the universal elements. */
+  palPertue(date1,u,&j);
+  if (j > 0) {
+    *jstat = j;
+  } else if (j < 0) {
+    *jstat = -5;
+    return;
+  }
+
+  /*  Transform from universal to conventional elements. */
+  palUe2el(u, jform, &jf, epoch1, orbi1, anode1, perih1,
+           aorq1, e1, am1, &dm, &j);
+  if (jf != jform || j != 0) *jstat = -5;
+}
Index: trunk/FACT++/pal/palPertue.c
===================================================================
--- trunk/FACT++/pal/palPertue.c	(revision 18347)
+++ trunk/FACT++/pal/palPertue.c	(revision 18347)
@@ -0,0 +1,655 @@
+/*
+*+
+*  Name:
+*     palPertue
+
+*  Purpose:
+*     Update the universal elements by applying planetary perturbations
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPertue( double date, double u[13], int *jstat );
+
+*  Arguments:
+*     date = double (Given)
+*        Final epoch (TT MJD) for the update elements.
+*     u = const double [13] (Given & Returned)
+*        Universal orbital elements (Note 1)
+*            (0)  combined mass (M+m)
+*            (1)  total energy of the orbit (alpha)
+*            (2)  reference (osculating) epoch (t0)
+*          (3-5)  position at reference epoch (r0)
+*          (6-8)  velocity at reference epoch (v0)
+*            (9)  heliocentric distance at reference epoch
+*           (10)  r0.v0
+*           (11)  date (t)
+*           (12)  universal eccentric anomaly (psi) of date, approx
+*     jstat = int * (Returned)
+*        status:
+*                   +102 = warning, distant epoch
+*                   +101 = warning, large timespan ( > 100 years)
+*              +1 to +10 = coincident with major planet (Note 5)
+*                      0 = OK
+*                     -1 = numerical error
+
+*  Description:
+*     Update the universal elements of an asteroid or comet by applying
+*     planetary perturbations.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference 2).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - The universal elements are with respect to the J2000 equator and
+*       equinox.
+*     - The epochs DATE, U(3) and U(12) are all Modified Julian Dates
+*       (JD-2400000.5).
+*     - The algorithm is a simplified form of Encke's method.  It takes as
+*       a basis the unperturbed motion of the body, and numerically
+*       integrates the perturbing accelerations from the major planets.
+*       The expression used is essentially Sterne's 6.7-2 (reference 1).
+*       Everhart and Pitkin (reference 2) suggest rectifying the orbit at
+*       each integration step by propagating the new perturbed position
+*       and velocity as the new universal variables.  In the present
+*       routine the orbit is rectified less frequently than this, in order
+*       to gain a slight speed advantage.  However, the rectification is
+*       done directly in terms of position and velocity, as suggested by
+*       Everhart and Pitkin, bypassing the use of conventional orbital
+*       elements.
+*
+*       The f(q) part of the full Encke method is not used.  The purpose
+*       of this part is to avoid subtracting two nearly equal quantities
+*       when calculating the "indirect member", which takes account of the
+*       small change in the Sun's attraction due to the slightly displaced
+*       position of the perturbed body.  A simpler, direct calculation in
+*       double precision proves to be faster and not significantly less
+*       accurate.
+*
+*       Apart from employing a variable timestep, and occasionally
+*       "rectifying the orbit" to keep the indirect member small, the
+*       integration is done in a fairly straightforward way.  The
+*       acceleration estimated for the middle of the timestep is assumed
+*       to apply throughout that timestep;  it is also used in the
+*       extrapolation of the perturbations to the middle of the next
+*       timestep, to predict the new disturbed position.  There is no
+*       iteration within a timestep.
+*
+*       Measures are taken to reach a compromise between execution time
+*       and accuracy.  The starting-point is the goal of achieving
+*       arcsecond accuracy for ordinary minor planets over a ten-year
+*       timespan.  This goal dictates how large the timesteps can be,
+*       which in turn dictates how frequently the unperturbed motion has
+*       to be recalculated from the osculating elements.
+*
+*       Within predetermined limits, the timestep for the numerical
+*       integration is varied in length in inverse proportion to the
+*       magnitude of the net acceleration on the body from the major
+*       planets.
+*
+*       The numerical integration requires estimates of the major-planet
+*       motions.  Approximate positions for the major planets (Pluto
+*       alone is omitted) are obtained from the routine palPlanet.  Two
+*       levels of interpolation are used, to enhance speed without
+*       significantly degrading accuracy.  At a low frequency, the routine
+*       palPlanet is called to generate updated position+velocity "state
+*       vectors".  The only task remaining to be carried out at the full
+*       frequency (i.e. at each integration step) is to use the state
+*       vectors to extrapolate the planetary positions.  In place of a
+*       strictly linear extrapolation, some allowance is made for the
+*       curvature of the orbit by scaling back the radius vector as the
+*       linear extrapolation goes off at a tangent.
+*
+*       Various other approximations are made.  For example, perturbations
+*       by Pluto and the minor planets are neglected and relativistic
+*       effects are not taken into account.
+*
+*       In the interests of simplicity, the background calculations for
+*       the major planets are carried out en masse.  The mean elements and
+*       state vectors for all the planets are refreshed at the same time,
+*       without regard for orbit curvature, mass or proximity.
+*
+*       The Earth-Moon system is treated as a single body when the body is
+*       distant but as separate bodies when closer to the EMB than the
+*       parameter RNE, which incurs a time penalty but improves accuracy
+*       for near-Earth objects.
+*
+*     - This routine is not intended to be used for major planets.
+*       However, if major-planet elements are supplied, sensible results
+*       will, in fact, be produced.  This happens because the routine
+*       checks the separation between the body and each of the planets and
+*       interprets a suspiciously small value (0.001 AU) as an attempt to
+*       apply the routine to the planet concerned.  If this condition is
+*       detected, the contribution from that planet is ignored, and the
+*       status is set to the planet number (1-10 = Mercury, Venus, EMB,
+*       Mars, Jupiter, Saturn, Uranus, Neptune, Earth, Moon) as a warning.
+
+*  See Also:
+*     - Sterne, Theodore E., "An Introduction to Celestial Mechanics",
+*       Interscience Publishers Inc., 1960.  Section 6.7, p199.
+*     - Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version direct conversion of SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     2012-06-21 (TIMJ):
+*        Support a lack of copysign() function.
+*     2012-06-22 (TIMJ):
+*        Check __STDC_VERSION__
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+/* Use the config file if we have one, else look at
+   compiler defines to see if we have C99 */
+#if HAVE_CONFIG_H
+#include <config.h>
+#else
+#ifdef __STDC_VERSION__
+#  if (__STDC_VERSION__ >= 199901L)
+#    define HAVE_COPYSIGN 1
+#  endif
+#endif
+#endif
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+/* copysign is C99 */
+#if HAVE_COPYSIGN
+# define COPYSIGN copysign
+#else
+# define COPYSIGN(a,b) DSIGN(a,b)
+#endif
+
+void palPertue( double date, double u[13], int *jstat ) {
+
+  /*  Distance from EMB at which Earth and Moon are treated separately */
+  const double RNE=1.0;
+
+  /*  Coincidence with major planet distance */
+  const double COINC=0.0001;
+
+  /*  Coefficient relating timestep to perturbing force */
+  const double TSC=1e-4;
+
+  /*  Minimum and maximum timestep (days) */
+  const double TSMIN = 0.01;
+  const double TSMAX = 10.0;
+
+  /*  Age limit for major-planet state vector (days) */
+  const double AGEPMO=5.0;
+
+  /*  Age limit for major-planet mean elements (days) */
+  const double AGEPEL=50.0;
+
+  /*  Margin for error when deciding whether to renew the planetary data */
+  const double TINY=1e-6;
+
+  /*  Age limit for the body's osculating elements (before rectification) */
+  const double AGEBEL=100.0;
+
+  /*  Gaussian gravitational constant squared */
+  const double GCON2 = PAL__GCON * PAL__GCON;
+
+  /*  The final epoch */
+  double TFINAL;
+
+  /*  The body's current universal elements */
+  double UL[13];
+
+  /*  Current reference epoch */
+  double T0;
+
+  /*  Timespan from latest orbit rectification to final epoch (days) */
+  double TSPAN;
+
+  /*  Time left to go before integration is complete */
+  double TLEFT;
+
+  /*  Time direction flag: +1=forwards, -1=backwards */
+  double FB;
+
+  /*  First-time flag */
+  int FIRST = 0;
+
+  /*
+   *  The current perturbations
+   */
+
+  /*  Epoch (days relative to current reference epoch) */
+  double RTN;
+  /*  Position (AU) */
+  double PERP[3];
+  /*  Velocity (AU/d) */
+  double PERV[3];
+  /*  Acceleration (AU/d/d) */
+  double PERA[3];
+
+  /*  Length of current timestep (days), and half that */
+  double TS,HTS;
+
+  /*  Epoch of middle of timestep */
+  double T;
+
+  /*  Epoch of planetary mean elements */
+  double TPEL = 0.0;
+
+  /*  Planet number (1=Mercury, 2=Venus, 3=EMB...8=Neptune) */
+  int NP;
+
+  /*  Planetary universal orbital elements */
+  double UP[8][13];
+
+  /*  Epoch of planetary state vectors */
+  double TPMO = 0.0;
+
+  /*  State vectors for the major planets (AU,AU/s) */
+  double PVIN[8][6];
+
+  /*  Earth velocity and position vectors (AU,AU/s) */
+  double VB[3],PB[3],VH[3],PE[3];
+
+  /*  Moon geocentric state vector (AU,AU/s) and position part */
+  double PVM[6],PM[3];
+
+  /*  Date to J2000 de-precession matrix */
+  double PMAT[3][3];
+
+  /*
+   *  Correction terms for extrapolated major planet vectors
+   */
+
+  /*  Sun-to-planet distances squared multiplied by 3 */
+  double R2X3[8];
+  /*  Sunward acceleration terms, G/2R^3 */
+  double GC[8];
+  /*  Tangential-to-circular correction factor */
+  double FC;
+  /*  Radial correction factor due to Sunwards acceleration */
+  double FG;
+
+  /*  The body's unperturbed and perturbed state vectors (AU,AU/s) */
+  double PV0[6],PV[6];
+
+  /*  The body's perturbed and unperturbed heliocentric distances (AU) cubed */
+  double R03,R3;
+
+  /*  The perturbating accelerations, indirect and direct */
+  double FI[3],FD[3];
+
+  /*  Sun-to-planet vector, and distance cubed */
+  double RHO[3],RHO3;
+
+  /*  Body-to-planet vector, and distance cubed */
+  double DELTA[3],DELTA3;
+
+  /*  Miscellaneous */
+  int I,J;
+  double R2,W,DT,DT2,R,FT;
+  int NE;
+
+  /*  Planetary inverse masses, Mercury through Neptune then Earth and Moon */
+  const double AMAS[10] = {
+    6023600., 408523.5, 328900.5, 3098710.,
+    1047.355, 3498.5, 22869., 19314.,
+    332946.038, 27068709.
+  };
+
+  /*  Preset the status to OK. */
+  *jstat = 0;
+
+  /*  Copy the final epoch. */
+  TFINAL = date;
+
+  /*  Copy the elements (which will be periodically updated). */
+  for (I=0; I<13; I++) {
+    UL[I] = u[I];
+  }
+
+/*  Initialize the working reference epoch. */
+  T0=UL[2];
+
+  /*  Total timespan (days) and hence time left. */
+  TSPAN = TFINAL-T0;
+  TLEFT = TSPAN;
+
+  /*  Warn if excessive. */
+  if (fabs(TSPAN) > 36525.0) *jstat=101;
+
+  /*  Time direction: +1 for forwards, -1 for backwards. */
+  FB = COPYSIGN(1.0,TSPAN);
+
+  /*  Initialize relative epoch for start of current timestep. */
+  RTN = 0.0;
+
+  /*  Reset the perturbations (position, velocity, acceleration). */
+  for (I=0; I<3; I++) {
+    PERP[I] = 0.0;
+    PERV[I] = 0.0;
+    PERA[I] = 0.0;
+  }
+
+  /*  Set "first iteration" flag. */
+  FIRST = 1;
+
+  /*  Step through the time left. */
+  while (FB*TLEFT > 0.0) {
+
+    /*     Magnitude of current acceleration due to planetary attractions. */
+    if (FIRST) {
+      TS = TSMIN;
+    } else {
+      R2 = 0.0;
+      for (I=0; I<3; I++) {
+        W = FD[I];
+        R2 = R2+W*W;
+      }
+      W = sqrt(R2);
+
+      /*        Use the acceleration to decide how big a timestep can be tolerated. */
+      if (W != 0.0) {
+        TS = DMIN(TSMAX,DMAX(TSMIN,TSC/W));
+      } else {
+        TS = TSMAX;
+      }
+    }
+    TS = TS*FB;
+
+    /*     Override if final epoch is imminent. */
+    TLEFT = TSPAN-RTN;
+    if (fabs(TS) > fabs(TLEFT)) TS=TLEFT;
+
+    /*     Epoch of middle of timestep. */
+    HTS = TS/2.0;
+    T = T0+RTN+HTS;
+
+    /*     Is it time to recompute the major-planet elements? */
+    if (FIRST || fabs(T-TPEL)-AGEPEL >= TINY) {
+
+      /*        Yes: go forward in time by just under the maximum allowed. */
+      TPEL = T+FB*AGEPEL;
+
+      /*        Compute the state vector for the new epoch. */
+      for (NP=1; NP<=8; NP++) {
+        palPlanet(TPEL,NP,PV,&J);
+
+        /*           Warning if remote epoch, abort if error. */
+        if (J == 1) {
+          *jstat = 102;
+        } else if (J != 0) {
+          goto ABORT;
+        }
+
+        /*           Transform the vector into universal elements. */
+        palPv2ue(PV,TPEL,0.0,&(UP[NP-1][0]),&J);
+        if (J != 0) goto ABORT;
+      }
+    }
+
+    /*     Is it time to recompute the major-planet motions? */
+    if (FIRST || fabs(T-TPMO)-AGEPMO >= TINY) {
+
+      /*        Yes: look ahead. */
+      TPMO = T+FB*AGEPMO;
+
+      /*        Compute the motions of each planet (AU,AU/d). */
+      for (NP=1; NP<=8; NP++) {
+
+        /*           The planet's position and velocity (AU,AU/s). */
+        palUe2pv(TPMO,&(UP[NP-1][0]),&(PVIN[NP-1][0]),&J);
+        if (J != 0) goto ABORT;
+
+        /*           Scale velocity to AU/d. */
+        for (J=3; J<6; J++) {
+          PVIN[NP-1][J] = PVIN[NP-1][J]*PAL__SPD;
+        }
+
+        /*           Precompute also the extrapolation correction terms. */
+        R2 = 0.0;
+        for (I=0; I<3; I++) {
+          W = PVIN[NP-1][I];
+          R2 = R2+W*W;
+        }
+        R2X3[NP-1] = R2*3.0;
+        GC[NP-1] = GCON2/(2.0*R2*sqrt(R2));
+      }
+    }
+
+    /*     Reset the first-time flag. */
+    FIRST = 0;
+
+    /*     Unperturbed motion of the body at middle of timestep (AU,AU/s). */
+    palUe2pv(T,UL,PV0,&J);
+    if (J != 0) goto ABORT;
+
+    /*     Perturbed position of the body (AU) and heliocentric distance cubed. */
+    R2 = 0.0;
+    for (I=0; I<3; I++) {
+      W = PV0[I]+PERP[I]+(PERV[I]+PERA[I]*HTS/2.0)*HTS;
+      PV[I] = W;
+      R2 = R2+W*W;
+    }
+    R3 = R2*sqrt(R2);
+
+    /*     The body's unperturbed heliocentric distance cubed. */
+    R2 = 0.0;
+    for (I=0; I<3; I++) {
+      W = PV0[I];
+      R2 = R2+W*W;
+    }
+    R03 = R2*sqrt(R2);
+
+    /*     Compute indirect and initialize direct parts of the perturbation. */
+    for (I=0; I<3; I++) {
+      FI[I] = PV0[I]/R03-PV[I]/R3;
+      FD[I] = 0.0;
+    }
+
+    /*     Ready to compute the direct planetary effects. */
+
+    /*     Reset the "near-Earth" flag. */
+    NE = 0;
+
+    /*     Interval from state-vector epoch to middle of current timestep. */
+    DT = T-TPMO;
+    DT2 = DT*DT;
+
+    /*     Planet by planet, including separate Earth and Moon. */
+    for (NP=1; NP<10; NP++) {
+
+      /*        Which perturbing body? */
+      if (NP <= 8) {
+
+        /*           Planet: compute the extrapolation in longitude (squared). */
+        R2 = 0.0;
+        for (J=3; J<6; J++) {
+          W = PVIN[NP-1][J]*DT;
+          R2 = R2+W*W;
+        }
+
+        /*           Hence the tangential-to-circular correction factor. */
+        FC = 1.0+R2/R2X3[NP-1];
+
+        /*           The radial correction factor due to the inwards acceleration. */
+        FG = 1.0-GC[NP-1]*DT2;
+
+        /*           Planet's position. */
+        for (I=0; I<3; I++) {
+          RHO[I] = FG*(PVIN[NP-1][I]+FC*PVIN[NP-1][I+3]*DT);
+        }
+
+      } else if (NE) {
+
+        /*           Near-Earth and either Earth or Moon. */
+
+        if (NP == 9) {
+
+          /*              Earth: position. */
+          palEpv(T,PE,VH,PB,VB);
+          for (I=0; I<3; I++) {
+            RHO[I] = PE[I];
+          }
+
+        } else {
+
+          /*              Moon: position. */
+          palPrec(palEpj(T),2000.0,PMAT);
+          palDmoon(T,PVM);
+          eraRxp(PMAT,PVM,PM);
+          for (I=0; I<3; I++) {
+            RHO[I] = PM[I]+PE[I];
+          }
+        }
+      }
+
+      /*        Proceed unless Earth or Moon and not the near-Earth case. */
+      if (NP <= 8 || NE) {
+
+        /*           Heliocentric distance cubed. */
+        R2 = 0.0;
+        for (I=0; I<3; I++) {
+          W = RHO[I];
+          R2 = R2+W*W;
+        }
+        R = sqrt(R2);
+        RHO3 = R2*R;
+
+        /*           Body-to-planet vector, and distance. */
+        R2 = 0.0;
+        for (I=0; I<3; I++) {
+          W = RHO[I]-PV[I];
+          DELTA[I] = W;
+          R2 = R2+W*W;
+        }
+        R = sqrt(R2);
+
+        /*           If this is the EMB, set the near-Earth flag appropriately. */
+        if (NP == 3 && R < RNE) NE = 1;
+
+        /*           Proceed unless EMB and this is the near-Earth case. */
+        if ( ! (NE && NP == 3) ) {
+
+          /*              If too close, ignore this planet and set a warning. */
+          if (R < COINC) {
+            *jstat = NP;
+
+          } else {
+
+            /*                 Accumulate "direct" part of perturbation acceleration. */
+            DELTA3 = R2*R;
+            W = AMAS[NP-1];
+            for (I=0; I<3; I++) {
+              FD[I] = FD[I]+(DELTA[I]/DELTA3-RHO[I]/RHO3)/W;
+            }
+          }
+        }
+      }
+    }
+
+    /*     Update the perturbations to the end of the timestep. */
+    RTN += TS;
+    for (I=0; I<3; I++) {
+      W = (FI[I]+FD[I])*GCON2;
+      FT = W*TS;
+      PERP[I] = PERP[I]+(PERV[I]+FT/2.0)*TS;
+      PERV[I] = PERV[I]+FT;
+      PERA[I] = W;
+    }
+
+    /*     Time still to go. */
+    TLEFT = TSPAN-RTN;
+
+    /*     Is it either time to rectify the orbit or the last time through? */
+    if (fabs(RTN) >= AGEBEL || FB*TLEFT <= 0.0) {
+
+      /*        Yes: update to the end of the current timestep. */
+      T0 += RTN;
+      RTN = 0.0;
+
+      /*        The body's unperturbed motion (AU,AU/s). */
+      palUe2pv(T0,UL,PV0,&J);
+      if (J != 0) goto ABORT;
+
+      /*        Add and re-initialize the perturbations. */
+      for (I=0; I<3; I++) {
+        J = I+3;
+        PV[I] = PV0[I]+PERP[I];
+        PV[J] = PV0[J]+PERV[I]/PAL__SPD;
+        PERP[I] = 0.0;
+        PERV[I] = 0.0;
+        PERA[I] = FD[I]*GCON2;
+      }
+
+      /*        Use the position and velocity to set up new universal elements. */
+      palPv2ue(PV,T0,0.0,UL,&J);
+      if (J != 0) goto ABORT;
+
+      /*        Adjust the timespan and time left. */
+      TSPAN = TFINAL-T0;
+      TLEFT = TSPAN;
+    }
+
+    /*     Next timestep. */
+  }
+
+  /*  Return the updated universal-element set. */
+  for (I=0; I<13; I++) {
+    u[I] = UL[I];
+  }
+
+  /*  Finished. */
+  return;
+
+  /*  Miscellaneous numerical error. */
+ ABORT:
+  *jstat = -1;
+  return;
+}
Index: trunk/FACT++/pal/palPlanel.c
===================================================================
--- trunk/FACT++/pal/palPlanel.c	(revision 18347)
+++ trunk/FACT++/pal/palPlanel.c	(revision 18347)
@@ -0,0 +1,220 @@
+/*
+*+
+*  Name:
+*     palPlanel
+
+*  Purpose:
+*     Transform conventional elements into position and velocity
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPlanel ( double date, int jform, double epoch, double orbinc,
+*                      double anode, double perih, double aorq, double e,
+*                      double aorl, double dm, double pv[6], int *jstat );
+
+*  Arguments:
+*     date = double (Given)
+*        Epoch (TT MJD) of osculation (Note 1)
+*     jform = int (Given)
+*        Element set actually returned (1-3; Note 3)
+*     epoch = double (Given)
+*        Epoch of elements (TT MJD) (Note 4)
+*     orbinc = double (Given)
+*        inclination (radians)
+*     anode = double (Given)
+*        longitude of the ascending node (radians)
+*     perih = double (Given)
+*        longitude or argument of perihelion (radians)
+*     aorq = double (Given)
+*        mean distance or perihelion distance (AU)
+*     e = double (Given)
+*        eccentricity
+*     aorl = double (Given)
+*        mean anomaly or longitude (radians, JFORM=1,2 only)
+*     dm = double (Given)
+*        daily motion (radians, JFORM=1 only)
+*     u = double [13] (Returned)
+*        Universal orbital elements (Note 1)
+*            (0)  combined mass (M+m)
+*            (1)  total energy of the orbit (alpha)
+*            (2)  reference (osculating) epoch (t0)
+*          (3-5)  position at reference epoch (r0)
+*          (6-8)  velocity at reference epoch (v0)
+*            (9)  heliocentric distance at reference epoch
+*           (10)  r0.v0
+*           (11)  date (t)
+*           (12)  universal eccentric anomaly (psi) of date, approx
+*     jstat = int * (Returned)
+*        status:  0 = OK
+*              - -1 = illegal JFORM
+*              - -2 = illegal E
+*              - -3 = illegal AORQ
+*              - -4 = illegal DM
+*              - -5 = numerical error
+
+*  Description:
+*     Heliocentric position and velocity of a planet, asteroid or comet,
+*     starting from orbital elements.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - DATE is the instant for which the prediction is required.  It is
+*       in the TT timescale (formerly Ephemeris Time, ET) and is a
+*       Modified Julian Date (JD-2400000.5).
+*     - The elements are with respect to the J2000 ecliptic and equinox.
+*     - A choice of three different element-set options is available:
+*
+*       Option JFORM = 1, suitable for the major planets:
+*
+*         EPOCH  = epoch of elements (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = longitude of perihelion, curly pi (radians)
+*         AORQ   = mean distance, a (AU)
+*         E      = eccentricity, e (range 0 to <1)
+*         AORL   = mean longitude L (radians)
+*         DM     = daily motion (radians)
+*
+*       Option JFORM = 2, suitable for minor planets:
+*
+*         EPOCH  = epoch of elements (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = argument of perihelion, little omega (radians)
+*         AORQ   = mean distance, a (AU)
+*         E      = eccentricity, e (range 0 to <1)
+*         AORL   = mean anomaly M (radians)
+*
+*       Option JFORM = 3, suitable for comets:
+*
+*         EPOCH  = epoch of elements and perihelion (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = argument of perihelion, little omega (radians)
+*         AORQ   = perihelion distance, q (AU)
+*         E      = eccentricity, e (range 0 to 10)
+*
+*       Unused arguments (DM for JFORM=2, AORL and DM for JFORM=3) are not
+*       accessed.
+*     - Each of the three element sets defines an unperturbed heliocentric
+*       orbit.  For a given epoch of observation, the position of the body
+*       in its orbit can be predicted from these elements, which are
+*       called "osculating elements", using standard two-body analytical
+*       solutions.  However, due to planetary perturbations, a given set
+*       of osculating elements remains usable for only as long as the
+*       unperturbed orbit that it describes is an adequate approximation
+*       to reality.  Attached to such a set of elements is a date called
+*       the "osculating epoch", at which the elements are, momentarily,
+*       a perfect representation of the instantaneous position and
+*       velocity of the body.
+*
+*       Therefore, for any given problem there are up to three different
+*       epochs in play, and it is vital to distinguish clearly between
+*       them:
+*
+*       . The epoch of observation:  the moment in time for which the
+*         position of the body is to be predicted.
+*
+*       . The epoch defining the position of the body:  the moment in time
+*         at which, in the absence of purturbations, the specified
+*         position (mean longitude, mean anomaly, or perihelion) is
+*         reached.
+*
+*       . The osculating epoch:  the moment in time at which the given
+*         elements are correct.
+*
+*       For the major-planet and minor-planet cases it is usual to make
+*       the epoch that defines the position of the body the same as the
+*       epoch of osculation.  Thus, only two different epochs are
+*       involved:  the epoch of the elements and the epoch of observation.
+*
+*       For comets, the epoch of perihelion fixes the position in the
+*       orbit and in general a different epoch of osculation will be
+*       chosen.  Thus, all three types of epoch are involved.
+*
+*       For the present routine:
+*
+*       . The epoch of observation is the argument DATE.
+*
+*       . The epoch defining the position of the body is the argument
+*         EPOCH.
+*
+*       . The osculating epoch is not used and is assumed to be close
+*         enough to the epoch of observation to deliver adequate accuracy.
+*         If not, a preliminary call to palPertel may be used to update
+*         the element-set (and its associated osculating epoch) by
+*         applying planetary perturbations.
+*     - The reference frame for the result is with respect to the mean
+*       equator and equinox of epoch J2000.
+*     - The algorithm was originally adapted from the EPHSLA program of
+*       D.H.P.Jones (private communication, 1996).  The method is based
+*       on Stumpff's Universal Variables.
+
+*  See Also:
+*     Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version taken directly from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2002 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+
+void palPlanel ( double date, int jform, double epoch, double orbinc,
+		 double anode, double perih, double aorq, double e,
+		 double aorl, double dm, double pv[6], int *jstat ) {
+
+  int j;
+  double u[13];
+
+  /*  Validate elements and convert to "universal variables" parameters. */
+  palEl2ue( date, jform, epoch, orbinc, anode, perih, aorq, e, aorl,
+	    dm, u, &j );
+
+  /* Determine the position and velocity */
+  if (j == 0) {
+    palUe2pv( date, u, pv, &j);
+    if (j != 0) j = -5;
+  }
+
+  /* Wrap up */
+  *jstat = j;
+
+}
Index: trunk/FACT++/pal/palPlanet.c
===================================================================
--- trunk/FACT++/pal/palPlanet.c	(revision 18347)
+++ trunk/FACT++/pal/palPlanet.c	(revision 18347)
@@ -0,0 +1,99 @@
+/*
+*+
+*  Name:
+*     palPlanet
+
+*  Purpose:
+*     Approximate heliocentric position and velocity of major planet
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPlanet ( double date, int np, double pv[6], int *j );
+
+*  Arguments:
+*     date = double (Given)
+*        TDB Modified Julian Date (JD-2400000.5).
+*     np = int (Given)
+*        planet (1=Mercury, 2=Venus, 3=EMB, 4=Mars,
+*                5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune)
+*     pv = double [6] (Returned)
+*        heliocentric x,y,z,xdot,ydot,zdot, J2000, equatorial triad
+*        in units AU and AU/s.
+*     j = int * (Returned)
+*        - -2 = solution didn't converge.
+*        - -1 = illegal np (1-8)
+*        -  0 = OK
+*        - +1 = warning: year outside 1000-3000
+
+*  Description:
+*     Calculates the approximate heliocentric position and velocity of
+*     the specified major planet.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - See SOFA/ERFA eraPlan94 for details
+*     - Note that Pluto is supported in SLA/F but not in this routine
+*     - Status -2 is equivalent to eraPlan94 status +2.
+*     - Note that velocity units here match the SLA/F documentation.
+
+*  History:
+*     2012-03-07 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palPlanet ( double date, int np, double pv[6], int *j ) {
+  double erapv[2][3];
+
+  *j = eraPlan94( PAL__MJD0, date, np, erapv );
+
+  /* Convert the outputs to the correct form and also correct AU/d
+     to AU/s */
+  pv[0] = erapv[0][0];
+  pv[1] = erapv[0][1];
+  pv[2] = erapv[0][2];
+  pv[3] = erapv[1][0] / PAL__SPD;
+  pv[4] = erapv[1][1] / PAL__SPD;
+  pv[5] = erapv[1][2] / PAL__SPD;
+
+  /* SLA compatibility for status */
+  if (*j == 2) *j = -2;
+
+}
Index: trunk/FACT++/pal/palPlante.c
===================================================================
--- trunk/FACT++/pal/palPlante.c	(revision 18347)
+++ trunk/FACT++/pal/palPlante.c	(revision 18347)
@@ -0,0 +1,286 @@
+/*
+*+
+*  Name:
+*     palPlante
+
+*  Purpose:
+*     Topocentric RA,Dec of a Solar-System object from heliocentric orbital elements
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPlante ( double date, double elong, double phi, int jform,
+*                      double epoch, double orbinc, double anode, double perih,
+*                      double aorq, double e, double aorl, double dm,
+*                      double *ra, double *dec, double *r, int *jstat );
+
+
+*  Description:
+*     Topocentric apparent RA,Dec of a Solar-System object whose
+*     heliocentric orbital elements are known.
+
+*  Arguments:
+*     date = double (Given)
+*        TT MJD of observation (JD-2400000.5)
+*     elong = double (Given)
+*        Observer's east longitude (radians)
+*     phi = double (Given)
+*        Observer's geodetic latitude (radians)
+*     jform = int (Given)
+*        Element set actually returned (1-3; Note 6)
+*     epoch = double (Given)
+*        Epoch of elements (TT MJD)
+*     orbinc = double (Given)
+*        inclination (radians)
+*     anode = double (Given)
+*        longitude of the ascending node (radians)
+*     perih = double (Given)
+*        longitude or argument of perihelion (radians)
+*     aorq = double (Given)
+*        mean distance or perihelion distance (AU)
+*     e = double (Given)
+*        eccentricity
+*     aorl = double (Given)
+*        mean anomaly or longitude (radians, JFORM=1,2 only)
+*     dm = double (Given)
+*        daily motion (radians, JFORM=1 only)
+*     ra = double * (Returned)
+*        Topocentric apparent RA (radians)
+*     dec = double * (Returned)
+*        Topocentric apparent Dec (radians)
+*     r = double * (Returned)
+*        Distance from observer (AU)
+*     jstat = int * (Returned)
+*        status: 0 = OK
+*             - -1 = illegal jform
+*             - -2 = illegal e
+*             - -3 = illegal aorq
+*             - -4 = illegal dm
+*             - -5 = numerical error
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - DATE is the instant for which the prediction is required.  It is
+*       in the TT timescale (formerly Ephemeris Time, ET) and is a
+*       Modified Julian Date (JD-2400000.5).
+*     - The longitude and latitude allow correction for geocentric
+*       parallax.  This is usually a small effect, but can become
+*       important for near-Earth asteroids.  Geocentric positions can be
+*       generated by appropriate use of routines palEpv (or palEvp) and
+*       palUe2pv.
+*     - The elements are with respect to the J2000 ecliptic and equinox.
+*     - A choice of three different element-set options is available:
+*
+*       Option JFORM = 1, suitable for the major planets:
+*
+*         EPOCH  = epoch of elements (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = longitude of perihelion, curly pi (radians)
+*         AORQ   = mean distance, a (AU)
+*         E      = eccentricity, e (range 0 to <1)
+*         AORL   = mean longitude L (radians)
+*         DM     = daily motion (radians)
+*
+*       Option JFORM = 2, suitable for minor planets:
+*
+*         EPOCH  = epoch of elements (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = argument of perihelion, little omega (radians)
+*         AORQ   = mean distance, a (AU)
+*         E      = eccentricity, e (range 0 to <1)
+*         AORL   = mean anomaly M (radians)
+*
+*       Option JFORM = 3, suitable for comets:
+*
+*         EPOCH  = epoch of elements and perihelion (TT MJD)
+*         ORBINC = inclination i (radians)
+*         ANODE  = longitude of the ascending node, big omega (radians)
+*         PERIH  = argument of perihelion, little omega (radians)
+*         AORQ   = perihelion distance, q (AU)
+*         E      = eccentricity, e (range 0 to 10)
+*
+*       Unused arguments (DM for JFORM=2, AORL and DM for JFORM=3) are not
+*       accessed.
+*     - Each of the three element sets defines an unperturbed heliocentric
+*       orbit.  For a given epoch of observation, the position of the body
+*       in its orbit can be predicted from these elements, which are
+*       called "osculating elements", using standard two-body analytical
+*       solutions.  However, due to planetary perturbations, a given set
+*       of osculating elements remains usable for only as long as the
+*       unperturbed orbit that it describes is an adequate approximation
+*       to reality.  Attached to such a set of elements is a date called
+*       the "osculating epoch", at which the elements are, momentarily,
+*       a perfect representation of the instantaneous position and
+*       velocity of the body.
+*
+*       Therefore, for any given problem there are up to three different
+*       epochs in play, and it is vital to distinguish clearly between
+*       them:
+*
+*       . The epoch of observation:  the moment in time for which the
+*         position of the body is to be predicted.
+*
+*       . The epoch defining the position of the body:  the moment in time
+*         at which, in the absence of purturbations, the specified
+*         position (mean longitude, mean anomaly, or perihelion) is
+*         reached.
+*
+*       . The osculating epoch:  the moment in time at which the given
+*         elements are correct.
+*
+*       For the major-planet and minor-planet cases it is usual to make
+*       the epoch that defines the position of the body the same as the
+*       epoch of osculation.  Thus, only two different epochs are
+*       involved:  the epoch of the elements and the epoch of observation.
+*
+*       For comets, the epoch of perihelion fixes the position in the
+*       orbit and in general a different epoch of osculation will be
+*       chosen.  Thus, all three types of epoch are involved.
+*
+*       For the present routine:
+*
+*       . The epoch of observation is the argument DATE.
+*
+*       . The epoch defining the position of the body is the argument
+*         EPOCH.
+*
+*       . The osculating epoch is not used and is assumed to be close
+*         enough to the epoch of observation to deliver adequate accuracy.
+*         If not, a preliminary call to palPertel may be used to update
+*         the element-set (and its associated osculating epoch) by
+*         applying planetary perturbations.
+*     - Two important sources for orbital elements are Horizons, operated
+*       by the Jet Propulsion Laboratory, Pasadena, and the Minor Planet
+*       Center, operated by the Center for Astrophysics, Harvard.
+*
+*       The JPL Horizons elements (heliocentric, J2000 ecliptic and
+*       equinox) correspond to PAL/SLALIB arguments as follows.
+*
+*        Major planets:
+*
+*         JFORM  = 1
+*         EPOCH  = JDCT-2400000.5
+*         ORBINC = IN (in radians)
+*         ANODE  = OM (in radians)
+*         PERIH  = OM+W (in radians)
+*         AORQ   = A
+*         E      = EC
+*         AORL   = MA+OM+W (in radians)
+*         DM     = N (in radians)
+*
+*         Epoch of osculation = JDCT-2400000.5
+*
+*        Minor planets:
+*
+*         JFORM  = 2
+*         EPOCH  = JDCT-2400000.5
+*         ORBINC = IN (in radians)
+*         ANODE  = OM (in radians)
+*         PERIH  = W (in radians)
+*         AORQ   = A
+*         E      = EC
+*         AORL   = MA (in radians)
+*
+*         Epoch of osculation = JDCT-2400000.5
+*
+*        Comets:
+*
+*         JFORM  = 3
+*         EPOCH  = Tp-2400000.5
+*         ORBINC = IN (in radians)
+*         ANODE  = OM (in radians)
+*         PERIH  = W (in radians)
+*         AORQ   = QR
+*         E      = EC
+*
+*         Epoch of osculation = JDCT-2400000.5
+*
+*      The MPC elements correspond to SLALIB arguments as follows.
+*
+*        Minor planets:
+*
+*         JFORM  = 2
+*         EPOCH  = Epoch-2400000.5
+*         ORBINC = Incl. (in radians)
+*         ANODE  = Node (in radians)
+*         PERIH  = Perih. (in radians)
+*         AORQ   = a
+*         E      = e
+*         AORL   = M (in radians)
+*
+*         Epoch of osculation = Epoch-2400000.5
+*
+*       Comets:
+*
+*         JFORM  = 3
+*         EPOCH  = T-2400000.5
+*         ORBINC = Incl. (in radians)
+*         ANODE  = Node. (in radians)
+*         PERIH  = Perih. (in radians)
+*         AORQ   = q
+*         E      = e
+*
+*         Epoch of osculation = Epoch-2400000.5
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version direct conversion of SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palPlante ( double date, double elong, double phi, int jform,
+		 double epoch, double orbinc, double anode, double perih,
+		 double aorq, double e, double aorl, double dm,
+		 double *ra, double *dec, double *r, int *jstat ) {
+
+  double u[13];
+
+  /* Transform conventional elements to universal elements */
+  palEl2ue( date, jform, epoch, orbinc, anode, perih, aorq, e, aorl,
+	    dm, u, jstat );
+
+  /* If succcessful, make the prediction */
+  if (*jstat == 0) palPlantu( date, elong, phi, u, ra, dec, r, jstat );
+
+}
+
+
+
Index: trunk/FACT++/pal/palPlantu.c
===================================================================
--- trunk/FACT++/pal/palPlantu.c	(revision 18347)
+++ trunk/FACT++/pal/palPlantu.c	(revision 18347)
@@ -0,0 +1,189 @@
+/*
+*+
+*  Name:
+*     palPlantu
+
+*  Purpose:
+*     Topocentric RA,Dec of a Solar-System object from universal elements
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPlantu ( double date, double elong, double phi, const double u[13],
+*                      double *ra, double *dec, double *r, int *jstat ) {
+
+*  Description:
+*     Topocentric apparent RA,Dec of a Solar-System object whose
+*     heliocentric universal elements are known.
+
+*  Arguments:
+*     date = double (Given)
+*        TT MJD of observation (JD-2400000.5)
+*     elong = double (Given)
+*        Observer's east longitude (radians)
+*     phi = double (Given)
+*        Observer's geodetic latitude (radians)
+*     u = const double [13] (Given)
+*        Universal orbital elements
+*          -   (0)  combined mass (M+m)
+*          -   (1)  total energy of the orbit (alpha)
+*          -   (2)  reference (osculating) epoch (t0)
+*          - (3-5)  position at reference epoch (r0)
+*          - (6-8)  velocity at reference epoch (v0)
+*          -   (9)  heliocentric distance at reference epoch
+*          -  (10)  r0.v0
+*          -  (11)  date (t)
+*          -  (12)  universal eccentric anomaly (psi) of date, approx
+*     ra = double * (Returned)
+*        Topocentric apparent RA (radians)
+*     dec = double * (Returned)
+*        Topocentric apparent Dec (radians)
+*     r = double * (Returned)
+*        Distance from observer (AU)
+*     jstat = int * (Returned)
+*        status: 0 = OK
+*             - -1 = radius vector zero
+*             - -2 = failed to converge
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - DATE is the instant for which the prediction is required.  It is
+*       in the TT timescale (formerly Ephemeris Time, ET) and is a
+*       Modified Julian Date (JD-2400000.5).
+*     - The longitude and latitude allow correction for geocentric
+*       parallax.  This is usually a small effect, but can become
+*       important for near-Earth asteroids.  Geocentric positions can be
+*       generated by appropriate use of routines palEpv (or palEvp) and
+*       palUe2pv.
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference 2).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - The universal elements are with respect to the J2000 equator and
+*       equinox.
+
+*  See Also:
+*     - Sterne, Theodore E., "An Introduction to Celestial Mechanics",
+*       Interscience Publishers Inc., 1960.  Section 6.7, p199.
+*     - Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-12 (TIMJ):
+*        Initial version direct conversion of SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+#include "pal1sofa.h"
+
+void palPlantu ( double date, double elong, double phi, const double u[13],
+                 double *ra, double *dec, double *r, int *jstat ) {
+
+  int i;
+  double dvb[3], dpb[3], vsg[6], vsp[6], v[6], rmat[3][3],
+    vgp[6], stl, vgo[6], dx, dy, dz, d, tl;
+
+  double ucp[13];
+
+  /* To retain the stated const API and conform to the documentation
+     we must copy the contents of the u array as palUe2pv updates
+     the final two elements */
+  for (i=0;i<13;i++) {
+    ucp[i] = u[i];
+  }
+
+  /* Sun to geocentre (J2000, velocity in AU/s) */
+  palEpv( date, vsg, &(vsg[3]), dpb, dvb );
+  for (i=3; i < 6; i++) {
+    vsg[i] /= PAL__SPD;
+  }
+
+  /* Sun to planet (J2000) */
+  palUe2pv( date, ucp, vsp, jstat );
+
+  /* Geocentre to planet (J2000) */
+  for (i=0; i<6; i++) {
+    v[i] = vsp[i] - vsg[i];
+  }
+
+  /* Precession and nutation to date */
+  palPrenut( 2000.0, date, rmat );
+  eraRxp(rmat, v, vgp);
+  eraRxp( rmat, &(v[3]), &(vgp[3]) );
+
+  /* Geocentre to observer (date) */
+  stl = palGmst( date - palDt( palEpj(date) ) / PAL__SPD ) + elong;
+  palPvobs( phi, 0.0, stl, vgo );
+
+  /* Observer to planet (date) */
+  for (i=0; i<6; i++) {
+    v[i] = vgp[i] - vgo[i];
+  }
+
+  /* Geometric distance (AU) */
+  dx = v[0];
+  dy = v[1];
+  dz = v[2];
+  d = sqrt( dx*dx + dy*dy + dz*dz );
+
+  /* Light time (sec) */
+  tl = PAL__CR * d;
+
+  /* Correct position for planetary aberration */
+  for (i=0; i<3; i++) {
+    v[i] -= tl * v[i+3];
+  }
+
+  /* To RA,Dec */
+  eraC2s( v, ra, dec );
+  *ra = eraAnp( *ra );
+  *r = d;
+}
+
Index: trunk/FACT++/pal/palPm.c
===================================================================
--- trunk/FACT++/pal/palPm.c	(revision 18347)
+++ trunk/FACT++/pal/palPm.c	(revision 18347)
@@ -0,0 +1,108 @@
+/*
+*+
+*  Name:
+*     palPm
+
+*  Purpose:
+*     Apply corrections for proper motion a star RA,Dec
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPm ( double r0, double d0, double pr, double pd,
+*                  double px, double rv, double ep0, double ep1,
+*                  double *r1, double *d1 );
+
+*  Arguments:
+*     r0 = double (Given)
+*        RA at epoch ep0 (radians)
+*     d0 = double (Given)
+*        Dec at epoch ep0 (radians)
+*     pr = double (Given)
+*        RA proper motion in radians per year.
+*     pd = double (Given)
+*        Dec proper motion in radians per year.
+*     px = double (Given)
+*        Parallax (arcsec)
+*     rv = double (Given)
+*        Radial velocity (km/sec +ve if receding)
+*     ep0 = double (Given)
+*        Start epoch in years, assumed to be Julian.
+*     ep1 = double (Given)
+*        End epoch in years, assumed to be Julian.
+*     r1 = double * (Returned)
+*        RA at epoch ep1 (radians)
+*     d1 = double * (Returned)
+*        Dec at epoch ep1 (radians)
+
+*  Description:
+*     Apply corrections for proper motion to a star RA,Dec using the
+*     SOFA/ERFA routine eraStarpm.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Uses eraStarpm but ignores the status returns from that routine.
+*       In particular note that parallax should not be zero when the
+*       proper motions are non-zero. SLA/F allows parallax to be zero.
+*     - Assumes all epochs are Julian epochs.
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palPm ( double r0, double d0, double pr, double pd,
+             double px, double rv, double ep0, double ep1,
+             double *r1, double *d1 ) {
+
+  int status;
+  double ep1a, ep1b, ep2a, ep2b;
+  double pmr2, pmd2, px2, rv2;
+
+  /* SOFA/ERFA requires the epochs in TDB MJD so we have to
+     assume that the supplied epochs are Julian years */
+  eraEpj2jd( ep0, &ep1a, &ep1b );
+  eraEpj2jd( ep1, &ep2a, &ep2b );
+
+  status = eraStarpm( r0, d0, pr, pd, px, rv,
+                      ep1a, ep1b, ep2a, ep2b,
+                      r1, d1,
+                      &pmr2, &pmd2, &px2, &rv2 );
+
+}
Index: trunk/FACT++/pal/palPolmo.c
===================================================================
--- trunk/FACT++/pal/palPolmo.c	(revision 18347)
+++ trunk/FACT++/pal/palPolmo.c	(revision 18347)
@@ -0,0 +1,190 @@
+/*
+*+
+*  Name:
+*     palPolmo
+
+*  Purpose:
+*     Correct for polar motion
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palPolmo ( double elongm, double phim, double xp, double yp,
+*                double *elong, double *phi, double *daz );
+
+*  Arguments:
+*     elongm = double (Given)
+*        Mean logitude of the observer (radians, east +ve)
+*     phim = double (Given)
+*        Mean geodetic latitude of the observer (radians)
+*     xp = double (Given)
+*        Polar motion x-coordinate (radians)
+*     yp = double (Given)
+*        Polar motion y-coordinate (radians)
+*     elong = double * (Returned)
+*        True longitude of the observer (radians, east +ve)
+*     phi = double * (Returned)
+*        True geodetic latitude of the observer (radians)
+*     daz = double * (Returned)
+*        Azimuth correction (terrestrial-celestial, radians)
+
+*  Description:
+*     Polar motion:  correct site longitude and latitude for polar
+*     motion and calculate azimuth difference between celestial and
+*     terrestrial poles.
+
+*  Authors:
+*     PTW: Patrick Wallace (STFC)
+*     TIMJ: Tim Jenness (Cornell)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - "Mean" longitude and latitude are the (fixed) values for the
+*       site's location with respect to the IERS terrestrial reference
+*       frame;  the latitude is geodetic.  TAKE CARE WITH THE LONGITUDE
+*       SIGN CONVENTION.  The longitudes used by the present routine
+*       are east-positive, in accordance with geographical convention
+*       (and right-handed).  In particular, note that the longitudes
+*       returned by the sla_OBS routine are west-positive, following
+*       astronomical usage, and must be reversed in sign before use in
+*       the present routine.
+*
+*     - XP and YP are the (changing) coordinates of the Celestial
+*       Ephemeris Pole with respect to the IERS Reference Pole.
+*       XP is positive along the meridian at longitude 0 degrees,
+*       and YP is positive along the meridian at longitude
+*       270 degrees (i.e. 90 degrees west).  Values for XP,YP can
+*       be obtained from IERS circulars and equivalent publications;
+*       the maximum amplitude observed so far is about 0.3 arcseconds.
+*
+*     - "True" longitude and latitude are the (moving) values for
+*       the site's location with respect to the celestial ephemeris
+*       pole and the meridian which corresponds to the Greenwich
+*       apparent sidereal time.  The true longitude and latitude
+*       link the terrestrial coordinates with the standard celestial
+*       models (for precession, nutation, sidereal time etc).
+*
+*     - The azimuths produced by sla_AOP and sla_AOPQK are with
+*       respect to due north as defined by the Celestial Ephemeris
+*       Pole, and can therefore be called "celestial azimuths".
+*       However, a telescope fixed to the Earth measures azimuth
+*       essentially with respect to due north as defined by the
+*       IERS Reference Pole, and can therefore be called "terrestrial
+*       azimuth".  Uncorrected, this would manifest itself as a
+*       changing "azimuth zero-point error".  The value DAZ is the
+*       correction to be added to a celestial azimuth to produce
+*       a terrestrial azimuth.
+*
+*     - The present routine is rigorous.  For most practical
+*       purposes, the following simplified formulae provide an
+*       adequate approximation:
+*
+*       elong = elongm+xp*cos(elongm)-yp*sin(elongm)
+*       phi   = phim+(xp*sin(elongm)+yp*cos(elongm))*tan(phim)
+*       daz   = -sqrt(xp*xp+yp*yp)*cos(elongm-atan2(xp,yp))/cos(phim)
+*
+*       An alternative formulation for DAZ is:
+*
+*       x = cos(elongm)*cos(phim)
+*       y = sin(elongm)*cos(phim)
+*       daz = atan2(-x*yp-y*xp,x*x+y*y)
+*
+*     - Reference:  Seidelmann, P.K. (ed), 1992.  "Explanatory Supplement
+*                   to the Astronomical Almanac", ISBN 0-935702-68-7,
+*                   sections 3.27, 4.25, 4.52.
+
+*  History:
+*     2000-11-30 (PTW):
+*        SLALIB implementation.
+*     2014-10-18 (TIMJ):
+*        Initial version in C.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2000 Rutherford Appleton Laboratory.
+*     Copyright (C) 2014 Cornell University
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+
+void palPolmo ( double elongm, double phim, double xp, double yp,
+                double *elong, double *phi, double *daz ) {
+
+  double  sel,cel,sph,cph,xm,ym,zm,xnm,ynm,znm,
+    sxp,cxp,syp,cyp,zw,xt,yt,zt,xnt,ynt;
+
+  /*  Site mean longitude and mean geodetic latitude as a Cartesian vector */
+  sel=sin(elongm);
+  cel=cos(elongm);
+  sph=sin(phim);
+  cph=cos(phim);
+
+  xm=cel*cph;
+  ym=sel*cph;
+  zm=sph;
+
+  /*  Rotate site vector by polar motion, Y-component then X-component */
+  sxp=sin(xp);
+  cxp=cos(xp);
+  syp=sin(yp);
+  cyp=cos(yp);
+
+  zw=(-ym*syp+zm*cyp);
+
+  xt=xm*cxp-zw*sxp;
+  yt=ym*cyp+zm*syp;
+  zt=xm*sxp+zw*cxp;
+
+  /*  Rotate also the geocentric direction of the terrestrial pole (0,0,1) */
+  xnm=-sxp*cyp;
+  ynm=syp;
+  znm=cxp*cyp;
+
+  cph=sqrt(xt*xt+yt*yt);
+  if (cph == 0.0) xt=1.0;
+  sel=yt/cph;
+  cel=xt/cph;
+
+  /*  Return true longitude and true geodetic latitude of site */
+  if (xt != 0.0 || yt != 0.0) {
+    *elong=atan2(yt,xt);
+  } else {
+    *elong=0.0;
+  }
+  *phi=atan2(zt,cph);
+
+  /*  Return current azimuth of terrestrial pole seen from site position */
+  xnt=(xnm*cel+ynm*sel)*zt-znm*cph;
+  ynt=-xnm*sel+ynm*cel;
+  if (xnt != 0.0 || ynt != 0.0) {
+    *daz=atan2(-ynt,-xnt);
+  } else {
+    *daz=0.0;
+  }
+
+}
Index: trunk/FACT++/pal/palPrebn.c
===================================================================
--- trunk/FACT++/pal/palPrebn.c	(revision 18347)
+++ trunk/FACT++/pal/palPrebn.c	(revision 18347)
@@ -0,0 +1,98 @@
+/*
+*+
+*  Name:
+*     palPrebn
+
+*  Purpose:
+*     Generate the matrix of precession between two objects (old)
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPrebn ( double bep0, double bep1, double rmatp[3][3] );
+
+*  Arguments:
+*     bep0 = double (Given)
+*        Beginning Besselian epoch.
+*     bep1 = double (Given)
+*        Ending Besselian epoch
+*     rmatp = double[3][3] (Returned)
+*        precession matrix in the sense V(BEP1) = RMATP * V(BEP0)
+
+*  Description:
+*     Generate the matrix of precession between two epochs,
+*     using the old, pre-IAU1976, Bessel-Newcomb model, using
+*     Kinoshita's formulation
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  See Also:
+*     Kinoshita, H. (1975) 'Formulas for precession', SAO Special
+*     Report No. 364, Smithsonian Institution Astrophysical
+*     Observatory, Cambridge, Massachusetts.
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+
+void palPrebn ( double bep0, double bep1, double rmatp[3][3] ) {
+
+  double t,bigt, zeta, theta, z, tas2r, w;
+
+  /* Interval between basic epoch B1850.0 and beginning epoch in TC */
+  bigt = (bep0-1850)/100.;
+
+  /*  Interval over which precession required, in tropical centuries */
+  t = (bep1-bep0)/100.;
+
+  /* Euler angles */
+  tas2r = t * PAL__DAS2R;
+  w = 2303.5548 + ( 1.39720 + 0.000059 * bigt) * bigt;
+
+  zeta = ( w + ( 0.30242 - 0.000269 * bigt + 0.017996 * t ) * t ) * tas2r;
+  z = ( w + ( 1.09478 + 0.000387 * bigt + 0.018324 * t ) * t ) * tas2r;
+  theta = ( 2005.1125 + ( -0.85294 - 0.000365 * bigt ) * bigt +
+	    (-0.42647 - 0.000365 * bigt - 0.041802 * t ) * t ) * tas2r;
+
+  /*  Rotation matrix */
+  palDeuler("ZYZ", -zeta, theta, -z, rmatp);
+
+}
Index: trunk/FACT++/pal/palPrec.c
===================================================================
--- trunk/FACT++/pal/palPrec.c	(revision 18347)
+++ trunk/FACT++/pal/palPrec.c	(revision 18347)
@@ -0,0 +1,107 @@
+/*
+*+
+*  Name:
+*     palPrec
+
+*  Purpose:
+*     Form the matrix of precession between two epochs (IAU 2006)
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palPrec( double ep0, double ep1, double rmatp[3][3] )
+
+*  Arguments:
+*     ep0 = double (Given)
+*        Beginning epoch
+*     ep1 = double (Given)
+*        Ending epoch
+*     rmatp = double[3][3] (Returned)
+*        Precession matrix
+
+*  Description:
+*     The IAU 2006 precession matrix from ep0 to ep1 is found and
+*     returned. The matrix is in the sense  V(EP1)  =  RMATP * V(EP0).
+*     The epochs are TDB (loosely TT) Julian epochs.
+*
+*     Though the matrix method itself is rigorous, the precession
+*     angles are expressed through canonical polynomials which are
+*     valid only for a limited time span of a few hundred years around
+*     the current epoch.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-10 (DSB):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1996 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palPrec( double ep0, double ep1, double rmatp[3][3] ){
+
+/* Local Variables: */
+   double rmatq[3][3];
+   double ep0_days;
+   double ep1_days;
+
+/* Convert supplied dates to days since J2000 */
+   ep0_days = ( ep0 - 2000.0 )*ERFA_DJY;
+   ep1_days = ( ep1 - 2000.0 )*ERFA_DJY;
+
+/* If beginning epoch is J2000, just return the rotation matrix from
+   J2000 to EP1. */
+   if( ep0 == 2000.0 ) {
+      eraPmat06( ERFA_DJ00, ep1_days, rmatp );
+
+/* If end epoch is J2000, get the rotation matrix from J2000 to EP0 and
+   then transpose it to get the rotation matrix from EP0 to J2000. */
+   } else if( ep1 == 2000.0 ) {
+      eraPmat06( ERFA_DJ00, ep0_days, rmatp );
+      eraTr( rmatp, rmatp );
+
+/* Otherwise. get the two matrices used above and multiply them
+   together. */
+   } else {
+      eraPmat06( ERFA_DJ00, ep0_days, rmatp );
+      eraTr( rmatp, rmatp );
+      eraPmat06( ERFA_DJ00, ep1_days, rmatq );
+      eraRxr( rmatp, rmatq, rmatp );
+   }
+
+}
Index: trunk/FACT++/pal/palPreces.c
===================================================================
--- trunk/FACT++/pal/palPreces.c	(revision 18347)
+++ trunk/FACT++/pal/palPreces.c	(revision 18347)
@@ -0,0 +1,118 @@
+/*
+*+
+*  Name:
+*     palPreces
+
+*  Purpose:
+*     Precession - either FK4 or FK5 as required.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPreces ( const char sys[3], double ep0, double ep1,
+*                      double *ra, double *dc );
+
+*  Arguments:
+*     sys = const char [3] (Given)
+*        Precession to be applied: FK4 or FK5. Case insensitive.
+*     ep0 = double (Given)
+*        Starting epoch.
+*     ep1 = double (Given)
+*        Ending epoch
+*     ra = double * (Given & Returned)
+*        On input the RA mean equator & equinox at epoch ep0. On exit
+*        the RA mean equator & equinox of epoch ep1.
+*     dec = double * (Given & Returned)
+*        On input the dec mean equator & equinox at epoch ep0. On exit
+*        the dec mean equator & equinox of epoch ep1.
+
+*  Description:
+*     Precess coordinates using the appropriate system and epochs.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Uses palPrec for FK5 data and palPrebn for FK4 data.
+*     - The epochs are Besselian if SYSTEM='FK4' and Julian if 'FK5'.
+*        For example, to precess coordinates in the old system from
+*        equinox 1900.0 to 1950.0 the call would be:
+*             palPreces( "FK4", 1900.0, 1950.0, &ra, &dc );
+*     - This routine will NOT correctly convert between the old and
+*       the new systems - for example conversion from B1950 to J2000.
+*       For these purposes see palFk425, palFk524, palFk45z and
+*       palFk54z.
+*     - If an invalid SYSTEM is supplied, values of -99D0,-99D0 will
+*       be returned for both RA and DC.
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+#include <string.h>
+
+void palPreces ( const char sys[3], double ep0, double ep1,
+                 double *ra, double *dc ) {
+
+  double pm[3][3];
+  double v1[3];
+  double v2[3];
+
+  /* Generate appropriate precession matrix */
+  if ( strncasecmp( "FK4", sys, 3 ) == 0 ) {
+    palPrebn( ep0, ep1, pm );
+  } else if (strncasecmp( "FK5", sys, 3 ) == 0 ) {
+    palPrec( ep0, ep1, pm );
+  } else {
+    *ra = -99.0;
+    *dc = -99.0;
+    return;
+  }
+
+  /* Convert RA,Dec to x,y,z */
+  eraS2c( *ra, *dc, v1 );
+
+  /* Precess */
+  eraRxp( pm, v1, v2 );
+
+  /* Back to RA,Dec */
+  eraC2s( v2, ra, dc );
+  *ra = eraAnp( *ra );
+}
Index: trunk/FACT++/pal/palPrenut.c
===================================================================
--- trunk/FACT++/pal/palPrenut.c	(revision 18347)
+++ trunk/FACT++/pal/palPrenut.c	(revision 18347)
@@ -0,0 +1,111 @@
+/*
+*+
+*  Name:
+*     palPrenut
+
+*  Purpose:
+*     Form the matrix of bias-precession-nutation (IAU 2006/2000A)
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPrenut( double epoch, double date, double rmatpn[3][3] )
+
+*  Arguments:
+*     epoch = double (Returned)
+*        Julian epoch for mean coordinates.
+*     date = double (Returned)
+*        Modified Julian Date (JD-2400000.5) for true coordinates.
+*     rmatpn = double[3][3] (Returned)
+*        combined NPB matrix
+
+*  Description:
+*     Form the matrix of bias-precession-nutation (IAU 2006/2000A).
+*     The epoch and date are TT (but TDB is usually close enough).
+*     The matrix is in the sense   v(true)  =  rmatpn * v(mean).
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-10 (PTW):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palPrenut ( double epoch, double date, double rmatpn[3][3] ){
+
+/* Local Variables: */
+   double bpa;
+   double bpia;
+   double bqa;
+   double chia;
+   double d1;
+   double d2;
+   double eps0;
+   double epsa;
+   double gam;
+   double oma;
+   double pa;
+   double phi;
+   double pia;
+   double psi;
+   double psia;
+   double r1[3][3];
+   double r2[3][3];
+   double thetaa;
+   double za;
+   double zetaa;
+
+/* Specified Julian epoch as a 2-part JD. */
+   eraEpj2jd( epoch, &d1, &d2 );
+
+/* P matrix, from specified epoch to J2000.0. */
+   eraP06e( d1, d2, &eps0, &psia, &oma, &bpa, &bqa, &pia, &bpia, &epsa,
+            &chia, &za, &zetaa, &thetaa, &pa, &gam, &phi, &psi );
+   eraIr( r1 );
+   eraRz( -chia, r1 );
+   eraRx( oma, r1 );
+   eraRz( psia, r1 );
+   eraRx( -eps0, r1 );
+
+/* NPB matrix, from J2000.0 to date. */
+   eraPnm06a( PAL__MJD0, date, r2 );
+
+/* NPB matrix, from specified epoch to date. */
+   eraRxr( r2, r1, rmatpn );
+}
Index: trunk/FACT++/pal/palPv2el.c
===================================================================
--- trunk/FACT++/pal/palPv2el.c	(revision 18347)
+++ trunk/FACT++/pal/palPv2el.c	(revision 18347)
@@ -0,0 +1,405 @@
+/*
+*+
+*  Name:
+*     palPv2el
+
+*  Purpose:
+*     Position velocity to heliocentirc osculating elements
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPv2el ( const double pv[6], double date, double pmass, int jformr,
+*                     int *jform, double *epoch, double *orbinc,
+*                     double *anode, double *perih, double *aorq, double *e,
+*                     double *aorl, double *dm, int *jstat );
+
+*  Arguments:
+*     pv = const double [6] (Given)
+*        Heliocentric x,y,z,xdot,ydot,zdot of date,
+*        J2000 equatorial triad (AU,AU/s; Note 1)
+*     date = double (Given)
+*        Date (TT Modified Julian Date = JD-2400000.5)
+*     pmass = double (Given)
+*        Mass of the planet (Sun=1; Note 2)
+*     jformr = int (Given)
+*        Requested element set (1-3; Note 3)
+*     jform = int * (Returned)
+*        Element set actually returned (1-3; Note 4)
+*     epoch = double * (Returned)
+*        Epoch of elements (TT MJD)
+*     orbinc = double * (Returned)
+*        inclination (radians)
+*     anode = double * (Returned)
+*        longitude of the ascending node (radians)
+*     perih = double * (Returned)
+*        longitude or argument of perihelion (radians)
+*     aorq = double * (Returned)
+*        mean distance or perihelion distance (AU)
+*     e = double * (Returned)
+*        eccentricity
+*     aorl = double * (Returned)
+*        mean anomaly or longitude (radians, JFORM=1,2 only)
+*     dm = double * (Returned)
+*        daily motion (radians, JFORM=1 only)
+*     jstat = int * (Returned)
+*        status:  0 = OK
+*               - -1 = illegal PMASS
+*               - -2 = illegal JFORMR
+*               - -3 = position/velocity out of range
+
+*  Description:
+*     Heliocentric osculating elements obtained from instantaneous position
+*     and velocity.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The PV 6-vector is with respect to the mean equator and equinox of
+*       epoch J2000.  The orbital elements produced are with respect to
+*       the J2000 ecliptic and mean equinox.
+*     - The mass, PMASS, is important only for the larger planets.  For
+*       most purposes (e.g. asteroids) use 0D0.  Values less than zero
+*       are illegal.
+*     - Three different element-format options are supported:
+*
+*       Option JFORM=1, suitable for the major planets:
+*
+*       EPOCH  = epoch of elements (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = longitude of perihelion, curly pi (radians)
+*       AORQ   = mean distance, a (AU)
+*       E      = eccentricity, e
+*       AORL   = mean longitude L (radians)
+*       DM     = daily motion (radians)
+*
+*       Option JFORM=2, suitable for minor planets:
+*
+*       EPOCH  = epoch of elements (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = argument of perihelion, little omega (radians)
+*       AORQ   = mean distance, a (AU)
+*       E      = eccentricity, e
+*       AORL   = mean anomaly M (radians)
+*
+*       Option JFORM=3, suitable for comets:
+*
+*       EPOCH  = epoch of perihelion (TT MJD)
+*       ORBINC = inclination i (radians)
+*       ANODE  = longitude of the ascending node, big omega (radians)
+*       PERIH  = argument of perihelion, little omega (radians)
+*       AORQ   = perihelion distance, q (AU)
+*       E      = eccentricity, e
+*
+*     - It may not be possible to generate elements in the form
+*       requested through JFORMR.  The caller is notified of the form
+*       of elements actually returned by means of the JFORM argument:
+
+*        JFORMR   JFORM     meaning
+*
+*          1        1       OK - elements are in the requested format
+*          1        2       never happens
+*          1        3       orbit not elliptical
+*
+*          2        1       never happens
+*          2        2       OK - elements are in the requested format
+*          2        3       orbit not elliptical
+*
+*          3        1       never happens
+*          3        2       never happens
+*          3        3       OK - elements are in the requested format
+*
+*     - The arguments returned for each value of JFORM (cf Note 5: JFORM
+*       may not be the same as JFORMR) are as follows:
+*
+*         JFORM         1              2              3
+*         EPOCH         t0             t0             T
+*         ORBINC        i              i              i
+*         ANODE         Omega          Omega          Omega
+*         PERIH         curly pi       omega          omega
+*         AORQ          a              a              q
+*         E             e              e              e
+*         AORL          L              M              -
+*         DM            n              -              -
+*
+*       where:
+*
+*         t0           is the epoch of the elements (MJD, TT)
+*         T              "    epoch of perihelion (MJD, TT)
+*         i              "    inclination (radians)
+*         Omega          "    longitude of the ascending node (radians)
+*         curly pi       "    longitude of perihelion (radians)
+*         omega          "    argument of perihelion (radians)
+*         a              "    mean distance (AU)
+*         q              "    perihelion distance (AU)
+*         e              "    eccentricity
+*         L              "    longitude (radians, 0-2pi)
+*         M              "    mean anomaly (radians, 0-2pi)
+*         n              "    daily motion (radians)
+*         -             means no value is set
+*
+*     - At very small inclinations, the longitude of the ascending node
+*       ANODE becomes indeterminate and under some circumstances may be
+*       set arbitrarily to zero.  Similarly, if the orbit is close to
+*       circular, the true anomaly becomes indeterminate and under some
+*       circumstances may be set arbitrarily to zero.  In such cases,
+*       the other elements are automatically adjusted to compensate,
+*       and so the elements remain a valid description of the orbit.
+*     - The osculating epoch for the returned elements is the argument
+*       DATE.
+*
+*     - Reference:  Sterne, Theodore E., "An Introduction to Celestial
+*                   Mechanics", Interscience Publishers, 1960
+
+*  History:
+*     2012-03-09 (TIMJ):
+*        Initial version converted from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal1sofa.h"
+#include "pal.h"
+#include "palmac.h"
+
+void palPv2el ( const double pv[6], double date, double pmass, int jformr,
+                int *jform, double *epoch, double *orbinc,
+                double *anode, double *perih, double *aorq, double *e,
+                double *aorl, double *dm, int *jstat ) {
+
+  /*  Sin and cos of J2000 mean obliquity (IAU 1976) */
+  const double SE = 0.3977771559319137;
+  const double CE = 0.9174820620691818;
+
+  /*  Minimum allowed distance (AU) and speed (AU/day) */
+  const double RMIN = 1e-3;
+  const double VMIN = 1e-8;
+
+  /*  How close to unity the eccentricity has to be to call it a parabola */
+  const double PARAB = 1.0e-8;
+
+  double X,Y,Z,XD,YD,ZD,R,V2,V,RDV,GMU,HX,HY,HZ,
+    HX2PY2,H2,H,OI,BIGOM,AR,ECC,S,C,AT,U,OM,
+    GAR3,EM1,EP1,HAT,SHAT,CHAT,AE,AM,DN,PL,
+    EL,Q,TP,THAT,THHF,F;
+
+  int JF;
+
+  /*  Validate arguments PMASS and JFORMR.*/
+  if (pmass < 0.0) {
+    *jstat = -1;
+    return;
+  }
+  if (jformr < 1 || jformr > 3) {
+    *jstat = -2;
+    return;
+  }
+
+  /*  Provisionally assume the elements will be in the chosen form. */
+  JF = jformr;
+
+  /*  Rotate the position from equatorial to ecliptic coordinates. */
+  X = pv[0];
+  Y = pv[1]*CE+pv[2]*SE;
+  Z = -pv[1]*SE+pv[2]*CE;
+
+  /*  Rotate the velocity similarly, scaling to AU/day. */
+  XD = PAL__SPD*pv[3];
+  YD = PAL__SPD*(pv[4]*CE+pv[5]*SE);
+  ZD = PAL__SPD*(-pv[4]*SE+pv[5]*CE);
+
+  /*  Distance and speed. */
+  R = sqrt(X*X+Y*Y+Z*Z);
+  V2 = XD*XD+YD*YD+ZD*ZD;
+  V = sqrt(V2);
+
+  /*  Reject unreasonably small values. */
+  if (R < RMIN || V < VMIN) {
+    *jstat = -3;
+    return;
+  }
+
+  /*  R dot V. */
+  RDV = X*XD+Y*YD+Z*ZD;
+
+  /*  Mu. */
+  GMU = (1.0+pmass)*PAL__GCON*PAL__GCON;
+
+  /*  Vector angular momentum per unit reduced mass. */
+  HX = Y*ZD-Z*YD;
+  HY = Z*XD-X*ZD;
+  HZ = X*YD-Y*XD;
+
+  /*  Areal constant. */
+  HX2PY2 = HX*HX+HY*HY;
+  H2 = HX2PY2+HZ*HZ;
+  H = sqrt(H2);
+
+  /*  Inclination. */
+  OI = atan2(sqrt(HX2PY2),HZ);
+
+  /*  Longitude of ascending node. */
+  if (HX != 0.0 || HY != 0.0) {
+    BIGOM = atan2(HX,-HY);
+  } else {
+    BIGOM=0.0;
+  }
+
+  /*  Reciprocal of mean distance etc. */
+  AR = 2.0/R-V2/GMU;
+
+  /*  Eccentricity. */
+  ECC = sqrt(DMAX(1.0-AR*H2/GMU,0.0));
+
+  /*  True anomaly. */
+  S = H*RDV;
+  C = H2-R*GMU;
+  if (S != 0.0 || C != 0.0) {
+    AT = atan2(S,C);
+  } else {
+    AT = 0.0;
+  }
+
+  /*  Argument of the latitude. */
+  S = sin(BIGOM);
+  C = cos(BIGOM);
+  U = atan2((-X*S+Y*C)*cos(OI)+Z*sin(OI),X*C+Y*S);
+
+  /*  Argument of perihelion. */
+  OM = U-AT;
+
+  /*  Capture near-parabolic cases. */
+  if (fabs(ECC-1.0) < PARAB) ECC=1.0;
+
+  /*  Comply with JFORMR = 1 or 2 only if orbit is elliptical. */
+  if (ECC > 1.0) JF=3;
+
+  /*  Functions. */
+  GAR3 = GMU*AR*AR*AR;
+  EM1 = ECC-1.0;
+  EP1 = ECC+1.0;
+  HAT = AT/2.0;
+  SHAT = sin(HAT);
+  CHAT = cos(HAT);
+
+  /*  Variable initializations to avoid compiler warnings. */
+  AM = 0.0;
+  DN = 0.0;
+  PL = 0.0;
+  EL = 0.0;
+  Q = 0.0;
+  TP = 0.0;
+
+  /*  Ellipse? */
+  if (ECC < 1.0 ) {
+
+    /*     Eccentric anomaly. */
+    AE = 2.0*atan2(sqrt(-EM1)*SHAT,sqrt(EP1)*CHAT);
+
+    /*     Mean anomaly. */
+    AM = AE-ECC*sin(AE);
+
+    /*     Daily motion. */
+    DN = sqrt(GAR3);
+  }
+
+  /*  "Major planet" element set? */
+  if (JF == 1) {
+
+    /*     Longitude of perihelion. */
+    PL = BIGOM+OM;
+
+    /*     Longitude at epoch. */
+    EL = PL+AM;
+  }
+
+  /*  "Comet" element set? */
+  if (JF == 3) {
+
+    /*     Perihelion distance. */
+    Q = H2/(GMU*EP1);
+
+    /*     Ellipse, parabola, hyperbola? */
+    if (ECC < 1.0) {
+
+      /*        Ellipse: epoch of perihelion. */
+      TP = date-AM/DN;
+
+    } else {
+
+      /*        Parabola or hyperbola: evaluate tan ( ( true anomaly ) / 2 ) */
+      THAT = SHAT/CHAT;
+      if (ECC == 1.0) {
+
+        /*           Parabola: epoch of perihelion. */
+        TP = date-THAT*(1.0+THAT*THAT/3.0)*H*H2/(2.0*GMU*GMU);
+
+      } else {
+
+        /*           Hyperbola: epoch of perihelion. */
+        THHF = sqrt(EM1/EP1)*THAT;
+        F = log(1.0+THHF)-log(1.0-THHF);
+        TP = date-(ECC*sinh(F)-F)/sqrt(-GAR3);
+      }
+    }
+  }
+
+  /*  Return the appropriate set of elements. */
+  *jform = JF;
+  *orbinc = OI;
+  *anode = eraAnp(BIGOM);
+  *e = ECC;
+  if (JF == 1) {
+    *perih = eraAnp(PL);
+    *aorl = eraAnp(EL);
+    *dm = DN;
+  } else {
+    *perih = eraAnp(OM);
+    if (JF == 2) *aorl = eraAnp(AM);
+  }
+  if (JF != 3) {
+    *epoch = date;
+    *aorq = 1.0/AR;
+  } else {
+    *epoch = TP;
+    *aorq = Q;
+  }
+  *jstat = 0;
+
+}
Index: trunk/FACT++/pal/palPv2ue.c
===================================================================
--- trunk/FACT++/pal/palPv2ue.c	(revision 18347)
+++ trunk/FACT++/pal/palPv2ue.c	(revision 18347)
@@ -0,0 +1,182 @@
+/*
+*+
+*  Name:
+*     palPv2ue
+
+*  Purpose:
+*     Universal elements to position and velocity.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palPv2ue( const double pv[6], double date, double pmass,
+*                    double u[13], int * jstat );
+
+*  Arguments:
+*     pv = double [6] (Given)
+*        Heliocentric x,y,z,xdot,ydot,zdot of date, (AU,AU/s; Note 1)
+*     date = double (Given)
+*        Date (TT modified Julian Date = JD-2400000.5)
+*     pmass = double (Given)
+*        Mass of the planet (Sun=1; note 2)
+*     u = double [13] (Returned)
+*        Universal orbital elements (Note 3)
+*
+*          -  (0)  combined mass (M+m)
+*          -   (1)  total energy of the orbit (alpha)
+*          -   (2)  reference (osculating) epoch (t0)
+*          - (3-5)  position at reference epoch (r0)
+*          - (6-8)  velocity at reference epoch (v0)
+*          -   (9)  heliocentric distance at reference epoch
+*          -  (10)  r0.v0
+*          -  (11)  date (t)
+*          -  (12)  universal eccentric anomaly (psi) of date, approx
+*     jstat = int * (Returned)
+*        status: 0 = OK
+*               - -1 = illegal PMASS
+*               - -2 = too close to Sun
+*               - -3 = too slow
+
+*  Description:
+*     Construct a universal element set based on an instantaneous position
+*     and velocity.
+
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The PV 6-vector can be with respect to any chosen inertial frame,
+*       and the resulting universal-element set will be with respect to
+*       the same frame.  A common choice will be mean equator and ecliptic
+*       of epoch J2000.
+*     - The mass, PMASS, is important only for the larger planets.  For
+*       most purposes (e.g. asteroids) use 0D0.  Values less than zero
+*       are illegal.
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - Reference:  Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-09 (TIMJ):
+*        Initial version from the SLA/F implementation.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void palPv2ue( const double pv[6], double date, double pmass,
+               double u[13], int * jstat ) {
+
+  /*  Canonical days to seconds */
+  const double CD2S = PAL__GCON / PAL__SPD;
+
+  /*  Minimum allowed distance (AU) and speed (AU per canonical day) */
+  const double RMIN = 1e-3;
+  const double VMIN = 1e-3;
+
+  double T0,CM,X,Y,Z,XD,YD,ZD,R,V2,V,ALPHA,RDV;
+
+  /*  Reference epoch. */
+  T0 = date;
+
+  /*  Combined mass (mu=M+m). */
+  if (pmass < 0.0 ) { /* Negative planet mass */
+    *jstat = -1;
+    return;
+  }
+  CM = 1.0+pmass;
+
+  /*  Unpack the state vector, expressing velocity in AU per canonical day. */
+  X = pv[0];
+  Y = pv[1];
+  Z = pv[2];
+  XD = pv[3]/CD2S;
+  YD = pv[4]/CD2S;
+  ZD = pv[5]/CD2S;
+
+  /*  Heliocentric distance, and speed. */
+  R = sqrt(X*X+Y*Y+Z*Z);
+  V2 = XD*XD+YD*YD+ZD*ZD;
+  V = sqrt(V2);
+
+  /*  Reject unreasonably small values. */
+  if (R < RMIN) { /* Too close */
+    *jstat = -2;
+    return;
+  }
+  if (V < VMIN) { /* Too slow */
+    *jstat = -3;
+    return;
+  }
+
+  /*  Total energy of the orbit. */
+  ALPHA = V2-2.0*CM/R;
+
+  /*  Outward component of velocity. */
+  RDV = X*XD+Y*YD+Z*ZD;
+
+  /*  Construct the universal-element set. */
+  u[0] = CM;
+  u[1] = ALPHA;
+  u[2] = T0;
+  u[3] = X;
+  u[4] = Y;
+  u[5] = Z;
+  u[6] = XD;
+  u[7] = YD;
+  u[8] = ZD;
+  u[9] = R;
+  u[10] = RDV;
+  u[11] = T0;
+  u[12] = 0.0;
+
+  *jstat = 0;
+  return;
+}
Index: trunk/FACT++/pal/palPvobs.c
===================================================================
--- trunk/FACT++/pal/palPvobs.c	(revision 18347)
+++ trunk/FACT++/pal/palPvobs.c	(revision 18347)
@@ -0,0 +1,108 @@
+/*
+*+
+*  Name:
+*     palPvobs
+
+*  Purpose:
+*     Position and velocity of an observing station.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palPvobs( double p, double h, double stl, double pv[6] )
+
+*  Arguments:
+*     p = double (Given)
+*        Latitude (geodetic, radians).
+*     h = double (Given)
+*        Height above reference spheroid (geodetic, metres).
+*     stl = double (Given)
+*        Local apparent sidereal time (radians).
+*     pv = double[ 6 ] (Returned)
+*        position/velocity 6-vector (AU, AU/s, true equator
+*                                    and equinox of date).
+
+*  Description:
+*     Returns the position and velocity of an observing station.
+
+*  Notes:
+*     - The WGS84 reference ellipsoid is used.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-16 (DSB):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palPvobs( double p, double h, double stl, double pv[6] ){
+
+/* Local Variables: */
+   double xyz[3], z, r, s, c, v;
+
+/* Geodetic to geocentric conversion (WGS84 reference ellipsoid). */
+   eraGd2gc( ERFA_WGS84, 0.0, p, h, xyz );
+
+/* Convert from metres to AU */
+   r = xyz[ 0 ]/ERFA_DAU;
+   z = xyz[ 2 ]/ERFA_DAU;
+
+/* Functions of ST. */
+   s = sin( stl );
+   c = cos( stl );
+
+/* Speed. */
+   v = PAL__SR*r;
+
+/* Position. */
+   pv[ 0 ] = r*c;
+   pv[ 1 ] = r*s;
+   pv[ 2 ] = z;
+
+/* Velocity. */
+   pv[ 3 ] = -v*s;
+   pv[ 4 ] = v*c;
+   pv[ 5 ] = 0.0;
+
+}
+
+
Index: trunk/FACT++/pal/palRdplan.c
===================================================================
--- trunk/FACT++/pal/palRdplan.c	(revision 18347)
+++ trunk/FACT++/pal/palRdplan.c	(revision 18347)
@@ -0,0 +1,224 @@
+/*
+*+
+*  Name:
+*     palRdplan
+
+*  Purpose:
+*     Approximate topocentric apparent RA,Dec of a planet
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palRdplan( double date, int np, double elong, double phi,
+*                     double * ra, double * dec, double * diam );
+
+*  Arguments:
+*     date = double (Given)
+*        MJD of observation (JD-2400000.5) in TDB. For all practical
+*        purposes TT can be used instead of TDB, and for many applications
+*        UT will do (except for the Moon).
+*     np = int (Given)
+*        Planet: 1 = Mercury
+*                2 = Venus
+*                3 = Moon
+*                4 = Mars
+*                5 = Jupiter
+*                6 = Saturn
+*                7 = Uranus
+*                8 = Neptune
+*             else = Sun
+*     elong = double (Given)
+*        Observer's east longitude (radians)
+*     phi = double (Given)
+*        Observer's geodetic latitude (radians)
+*     ra = double * (Returned)
+*        RA (topocentric apparent, radians)
+*     dec = double * (Returned)
+*        Dec (topocentric apparent, radians)
+*     diam = double * (Returned)
+*        Angular diameter (equatorial, radians)
+
+*  Description:
+*     Approximate topocentric apparent RA,Dec of a planet, and its
+*     angular diameter.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Unlike with slaRdplan, Pluto is not supported.
+*     - The longitude and latitude allow correction for geocentric
+*       parallax.  This is a major effect for the Moon, but in the
+*       context of the limited accuracy of the present routine its
+*       effect on planetary positions is small (negligible for the
+*       outer planets).  Geocentric positions can be generated by
+*       appropriate use of the routines palDmoon and eraPlan94.
+
+*  History:
+*     2012-03-07 (TIMJ):
+*        Initial version, with some documentation from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1997 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+#include "pal1sofa.h"
+
+void palRdplan( double date, int np, double elong, double phi,
+                double * ra, double * dec, double * diam ) {
+
+  /* AU in km */
+  const double AUKM = 1.49597870e8;
+
+  /* Equatorial radii (km) */
+  const double EQRAU[] = {
+    696000.0, /* Sun */
+      2439.7,
+      6051.9,
+      1738,
+      3397,
+     71492,
+     60268,
+     25559,
+     24764
+  };
+
+  /* Local variables */
+  int i, j;
+  double stl;
+  double vgm[6];
+  double v[6];
+  double rmat[3][3];
+  double vse[6];
+  double vsg[6];
+  double vsp[6];
+  double vgo[6];
+  double dx,dy,dz,r,tl;
+
+  /* Classify np */
+  if (np < 0 || np > 8 ) np=0;  /* Sun */
+
+  /* Approximate local sidereal time */
+  stl = palGmst( date - palDt( palEpj(date)) / 86400.0) + elong;
+
+  /* Geocentre to Moon (mean of date) */
+  palDmoon( date, v );
+
+  /* Nutation to true of date */
+  palNut( date, rmat );
+  eraRxp( rmat, v, vgm );
+  eraRxp( rmat, &(v[3]), &(vgm[3]) );
+
+  /* Moon? */
+  if (np == 3) {
+
+    /* geocentre to Moon (true of date) */
+    for (i=0; i<6; i++) {
+      v[i] = vgm[i];
+    }
+
+  } else {
+
+    /* Not moon: precession/nutation matrix J2000 to date */
+    palPrenut( 2000.0, date, rmat );
+
+    /* Sun to Earth-Moon Barycentre (J2000) */
+    palPlanet( date, 3, v, &j );
+
+    /* Precession and nutation to date */
+    eraRxp( rmat, v, vse );
+    eraRxp( rmat, &(v[3]), &(vse[3]) );
+
+    /* Sun to geocentre (true of date) */
+    for (i=0; i<6; i++) {
+      vsg[i] = vse[i] - 0.012150581 * vgm[i];
+    }
+
+    /* Sun ? */
+    if (np == 0) {
+
+      /* Geocentre to Sun */
+      for (i=0; i<6; i++) {
+        v[i] = -vsg[i];
+      }
+
+    } else {
+
+      /* Sun to Planet (J2000) */
+      palPlanet( date, np, v, &j );
+
+      /* Precession and nutation to date */
+      eraRxp( rmat, v, vsp );
+      eraRxp( rmat, &(v[3]), &(vsp[3]) );
+
+      /* Geocentre to planet */
+      for (i=0; i<6; i++) {
+        v[i] = vsp[i] - vsg[i];
+      }
+
+    }
+
+  }
+
+  /* Refer to origina at the observer */
+  palPvobs( phi, 0.0, stl, vgo );
+  for (i=0; i<6; i++) {
+    v[i] -= vgo[i];
+  }
+
+  /* Geometric distance (AU) */
+  dx = v[0];
+  dy = v[1];
+  dz = v[2];
+  r = sqrt( dx*dx + dy*dy + dz*dz );
+
+  /* Light time */
+  tl = PAL__CR * r;
+
+  /* Correct position for planetary aberration */
+  for (i=0; i<3; i++) {
+    v[i] -= tl * v[i+3];
+  }
+
+  /* To RA,Dec */
+  eraC2s( v, ra, dec );
+  *ra = eraAnp( *ra );
+
+  /* Angular diameter (radians) */
+  *diam = 2.0 * asin( EQRAU[np] / (r * AUKM ) );
+
+}
Index: trunk/FACT++/pal/palRefco.c
===================================================================
--- trunk/FACT++/pal/palRefco.c	(revision 18347)
+++ trunk/FACT++/pal/palRefco.c	(revision 18347)
@@ -0,0 +1,120 @@
+/*
+*+
+*  Name:
+*     palRefco
+
+*  Purpose:
+*     Determine constants in atmospheric refraction model
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palRefco ( double hm, double tdk, double pmb, double rh,
+*                     double wl, double phi, double tlr, double eps,
+*                     double *refa, double *refb );
+
+*  Arguments:
+*     hm = double (Given)
+*        Height of the observer above sea level (metre)
+*     tdk = double (Given)
+*        Ambient temperature at the observer (K)
+*     pmb = double (Given)
+*        Pressure at the observer (millibar)
+*     rh = double (Given)
+*        Relative humidity at the observer (range 0-1)
+*     wl = double (Given)
+*        Effective wavelength of the source (micrometre)
+*     phi = double (Given)
+*        Latitude of the observer (radian, astronomical)
+*     tlr = double (Given)
+*        Temperature lapse rate in the troposphere (K/metre)
+*     eps = double (Given)
+*        Precision required to terminate iteration (radian)
+*     refa = double * (Returned)
+*        tan Z coefficient (radian)
+*     refb = double * (Returned)
+*        tan**3 Z coefficient (radian)
+
+*  Description:
+*     Determine the constants A and B in the atmospheric refraction
+*     model dZ = A tan Z + B tan**3 Z.
+*
+*     Z is the "observed" zenith distance (i.e. affected by refraction)
+*     and dZ is what to add to Z to give the "topocentric" (i.e. in vacuo)
+*     zenith distance.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Typical values for the TLR and EPS arguments might be 0.0065 and
+*     1E-10 respectively.
+*
+*     - The radio refraction is chosen by specifying WL > 100 micrometres.
+*
+*     - The routine is a slower but more accurate alternative to the
+*     palRefcoq routine.  The constants it produces give perfect
+*     agreement with palRefro at zenith distances arctan(1) (45 deg)
+*     and arctan(4) (about 76 deg).  It achieves 0.5 arcsec accuracy
+*     for ZD < 80 deg, 0.01 arcsec accuracy for ZD < 60 deg, and
+*     0.001 arcsec accuracy for ZD < 45 deg.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version. A direct copy of the Fortran SLA implementation.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+void palRefco ( double hm, double tdk, double pmb, double rh,
+                double wl, double phi, double tlr, double eps,
+                double *refa, double *refb ) {
+
+  double r1, r2;
+
+  /*  Sample zenith distances: arctan(1) and arctan(4) */
+  const double ATN1 = 0.7853981633974483;
+  const double ATN4 = 1.325817663668033;
+
+  /*  Determine refraction for the two sample zenith distances */
+  palRefro(ATN1,hm,tdk,pmb,rh,wl,phi,tlr,eps,&r1);
+  palRefro(ATN4,hm,tdk,pmb,rh,wl,phi,tlr,eps,&r2);
+
+  /*  Solve for refraction constants */
+  *refa = (64.0*r1-r2)/60.0;
+  *refb = (r2-4.0*r1)/60.0;
+
+}
Index: trunk/FACT++/pal/palRefro.c
===================================================================
--- trunk/FACT++/pal/palRefro.c	(revision 18347)
+++ trunk/FACT++/pal/palRefro.c	(revision 18347)
@@ -0,0 +1,437 @@
+/*
+*+
+*  Name:
+*     palRefro
+
+*  Purpose:
+*     Atmospheric refraction for radio and optical/IR wavelengths
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palRefro( double zobs, double hm, double tdk, double pmb,
+*                    double rh, double wl, double phi, double tlr,
+*                    double eps, double * ref ) {
+
+*  Arguments:
+*     zobs = double (Given)
+*        Observed zenith distance of the source (radian)
+*     hm = double (Given)
+*        Height of the observer above sea level (metre)
+*     tdk = double (Given)
+*        Ambient temperature at the observer (K)
+*     pmb = double (Given)
+*        Pressure at the observer (millibar)
+*     rh = double (Given)
+*        Relative humidity at the observer (range 0-1)
+*     wl = double (Given)
+*        Effective wavelength of the source (micrometre)
+*     phi = double (Given)
+*        Latitude of the observer (radian, astronomical)
+*     tlr = double (Given)
+*        Temperature lapse rate in the troposphere (K/metre)
+*     eps = double (Given)
+*        Precision required to terminate iteration (radian)
+*     ref = double * (Returned)
+*        Refraction: in vacuao ZD minus observed ZD (radian)
+
+*  Description:
+*     Calculates the atmospheric refraction for radio and optical/IR
+*     wavelengths.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - A suggested value for the TLR argument is 0.0065.  The
+*     refraction is significantly affected by TLR, and if studies
+*     of the local atmosphere have been carried out a better TLR
+*     value may be available.  The sign of the supplied TLR value
+*     is ignored.
+*
+*     - A suggested value for the EPS argument is 1E-8.  The result is
+*     usually at least two orders of magnitude more computationally
+*     precise than the supplied EPS value.
+*
+*     - The routine computes the refraction for zenith distances up
+*     to and a little beyond 90 deg using the method of Hohenkerk
+*     and Sinclair (NAO Technical Notes 59 and 63, subsequently adopted
+*     in the Explanatory Supplement, 1992 edition - see section 3.281).
+*
+*     - The code is a development of the optical/IR refraction subroutine
+*     AREF of C.Hohenkerk (HMNAO, September 1984), with extensions to
+*     support the radio case.  Apart from merely cosmetic changes, the
+*     following modifications to the original HMNAO optical/IR refraction
+*     code have been made:
+*
+*     .  The angle arguments have been changed to radians.
+*
+*     .  Any value of ZOBS is allowed (see note 6, below).
+*
+*     .  Other argument values have been limited to safe values.
+*
+*     .  Murray's values for the gas constants have been used
+*        (Vectorial Astrometry, Adam Hilger, 1983).
+*
+*     .  The numerical integration phase has been rearranged for
+*        extra clarity.
+*
+*     .  A better model for Ps(T) has been adopted (taken from
+*        Gill, Atmosphere-Ocean Dynamics, Academic Press, 1982).
+*
+*     .  More accurate expressions for Pwo have been adopted
+*        (again from Gill 1982).
+*
+*     .  The formula for the water vapour pressure, given the
+*        saturation pressure and the relative humidity, is from
+*        Crane (1976), expression 2.5.5.
+
+*     .  Provision for radio wavelengths has been added using
+*        expressions devised by A.T.Sinclair, RGO (private
+*        communication 1989).  The refractivity model currently
+*        used is from J.M.Rueger, "Refractive Index Formulae for
+*        Electronic Distance Measurement with Radio and Millimetre
+*        Waves", in Unisurv Report S-68 (2002), School of Surveying
+*        and Spatial Information Systems, University of New South
+*        Wales, Sydney, Australia.
+*
+*     .  The optical refractivity for dry air is from Resolution 3 of
+*        the International Association of Geodesy adopted at the XXIIth
+*        General Assembly in Birmingham, UK, 1999.
+*
+*     .  Various small changes have been made to gain speed.
+*
+*     - The radio refraction is chosen by specifying WL > 100 micrometres.
+*     Because the algorithm takes no account of the ionosphere, the
+*     accuracy deteriorates at low frequencies, below about 30 MHz.
+*
+*     - Before use, the value of ZOBS is expressed in the range +/- pi.
+*     If this ranged ZOBS is -ve, the result REF is computed from its
+*     absolute value before being made -ve to match.  In addition, if
+*     it has an absolute value greater than 93 deg, a fixed REF value
+*     equal to the result for ZOBS = 93 deg is returned, appropriately
+*     signed.
+*
+*     - As in the original Hohenkerk and Sinclair algorithm, fixed values
+*     of the water vapour polytrope exponent, the height of the
+*     tropopause, and the height at which refraction is negligible are
+*     used.
+*
+*     - The radio refraction has been tested against work done by
+*     Iain Coulson, JACH, (private communication 1995) for the
+*     James Clerk Maxwell Telescope, Mauna Kea.  For typical conditions,
+*     agreement at the 0.1 arcsec level is achieved for moderate ZD,
+*     worsening to perhaps 0.5-1.0 arcsec at ZD 80 deg.  At hot and
+*     humid sea-level sites the accuracy will not be as good.
+*
+*     - It should be noted that the relative humidity RH is formally
+*     defined in terms of "mixing ratio" rather than pressures or
+*     densities as is often stated.  It is the mass of water per unit
+*     mass of dry air divided by that for saturated air at the same
+*     temperature and pressure (see Gill 1982).
+
+*     - The algorithm is designed for observers in the troposphere. The
+*     supplied temperature, pressure and lapse rate are assumed to be
+*     for a point in the troposphere and are used to define a model
+*     atmosphere with the tropopause at 11km altitude and a constant
+*     temperature above that.  However, in practice, the refraction
+*     values returned for stratospheric observers, at altitudes up to
+*     25km, are quite usable.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version, direct port of SLA Fortran source.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Patrick T. Wallace
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "pal1.h"
+#include "palmac.h"
+
+void palRefro( double zobs, double hm, double tdk, double pmb,
+               double rh, double wl, double phi, double tlr,
+               double eps, double * ref ) {
+
+  /*
+   *  Fixed parameters
+   */
+
+  /*  93 degrees in radians */
+  const double D93 = 1.623156204;
+  /*  Universal gas constant */
+  const double GCR = 8314.32;
+  /*  Molecular weight of dry air */
+  const double DMD = 28.9644;
+  /*  Molecular weight of water vapour */
+  const double DMW = 18.0152;
+  /*  Mean Earth radius (metre) */
+  const double S = 6378120.;
+  /*  Exponent of temperature dependence of water vapour pressure */
+  const double DELTA = 18.36;
+  /*  Height of tropopause (metre) */
+  const double HT = 11000.;
+  /*  Upper limit for refractive effects (metre) */
+  const double HS = 80000.;
+  /*  Numerical integration: maximum number of strips. */
+  const int ISMAX=16384l;
+
+  /* Local variables */
+  int is, k, n, i, j;
+
+  int optic, loop; /* booleans */
+
+  double zobs1,zobs2,hmok,tdkok,pmbok,rhok,wlok,alpha,
+    tol,wlsq,gb,a,gamal,gamma,gamm2,delm2,
+    tdc,psat,pwo,w,
+    c1,c2,c3,c4,c5,c6,r0,tempo,dn0,rdndr0,sk0,f0,
+    rt,tt,dnt,rdndrt,sine,zt,ft,dnts,rdndrp,zts,fts,
+    rs,dns,rdndrs,zs,fs,refold,z0,zrange,fb,ff,fo,fe,
+    h,r,sz,rg,dr,tg,dn,rdndr,t,f,refp,reft;
+
+  /*  The refraction integrand */
+#define refi(DN,RDNDR) RDNDR/(DN+RDNDR)
+
+  /*  Transform ZOBS into the normal range. */
+  zobs1 = palDrange(zobs);
+  zobs2 = DMIN(fabs(zobs1),D93);
+
+  /*  keep other arguments within safe bounds. */
+  hmok = DMIN(DMAX(hm,-1e3),HS);
+  tdkok = DMIN(DMAX(tdk,100.0),500.0);
+  pmbok = DMIN(DMAX(pmb,0.0),10000.0);
+  rhok = DMIN(DMAX(rh,0.0),1.0);
+  wlok = DMAX(wl,0.1);
+  alpha = DMIN(DMAX(fabs(tlr),0.001),0.01);
+
+  /*  tolerance for iteration. */
+  tol = DMIN(DMAX(fabs(eps),1e-12),0.1)/2.0;
+
+  /*  decide whether optical/ir or radio case - switch at 100 microns. */
+  optic = wlok < 100.0;
+
+  /*  set up model atmosphere parameters defined at the observer. */
+  wlsq = wlok*wlok;
+  gb = 9.784*(1.0-0.0026*cos(phi+phi)-0.00000028*hmok);
+  if (optic) {
+    a = (287.6155+(1.62887+0.01360/wlsq)/wlsq) * 273.15e-6/1013.25;
+  } else {
+    a = 77.6890e-6;
+  }
+  gamal = (gb*DMD)/GCR;
+  gamma = gamal/alpha;
+  gamm2 = gamma-2.0;
+  delm2 = DELTA-2.0;
+  tdc = tdkok-273.15;
+  psat = pow(10.0,(0.7859+0.03477*tdc)/(1.0+0.00412*tdc)) *
+    (1.0+pmbok*(4.5e-6+6.0e-10*tdc*tdc));
+  if (pmbok > 0.0) {
+    pwo = rhok*psat/(1.0-(1.0-rhok)*psat/pmbok);
+  } else {
+    pwo = 0.0;
+  }
+  w = pwo*(1.0-DMW/DMD)*gamma/(DELTA-gamma);
+  c1 = a*(pmbok+w)/tdkok;
+  if (optic) {
+    c2 = (a*w+11.2684e-6*pwo)/tdkok;
+  } else {
+    c2 = (a*w+6.3938e-6*pwo)/tdkok;
+  }
+  c3 = (gamma-1.0)*alpha*c1/tdkok;
+  c4 = (DELTA-1.0)*alpha*c2/tdkok;
+  if (optic) {
+    c5 = 0.0;
+    c6 = 0.0;
+  } else {
+    c5 = 375463e-6*pwo/tdkok;
+    c6 = c5*delm2*alpha/(tdkok*tdkok);
+  }
+
+  /*  conditions at the observer. */
+  r0 = S+hmok;
+  pal1Atmt(r0,tdkok,alpha,gamm2,delm2,c1,c2,c3,c4,c5,c6,
+           r0,&tempo,&dn0,&rdndr0);
+  sk0 = dn0*r0*sin(zobs2);
+  f0 = refi(dn0,rdndr0);
+
+  /*  conditions in the troposphere at the tropopause. */
+  rt = S+DMAX(HT,hmok);
+  pal1Atmt(r0,tdkok,alpha,gamm2,delm2,c1,c2,c3,c4,c5,c6,
+           rt,&tt,&dnt,&rdndrt);
+  sine = sk0/(rt*dnt);
+  zt = atan2(sine,sqrt(DMAX(1.0-sine*sine,0.0)));
+  ft = refi(dnt,rdndrt);
+
+  /*  conditions in the stratosphere at the tropopause. */
+  pal1Atms(rt,tt,dnt,gamal,rt,&dnts,&rdndrp);
+  sine = sk0/(rt*dnts);
+  zts = atan2(sine,sqrt(DMAX(1.0-sine*sine,0.0)));
+  fts = refi(dnts,rdndrp);
+
+  /*  conditions at the stratosphere limit. */
+  rs = S+HS;
+  pal1Atms(rt,tt,dnt,gamal,rs,&dns,&rdndrs);
+  sine = sk0/(rs*dns);
+  zs = atan2(sine,sqrt(DMAX(1.0-sine*sine,0.0)));
+  fs = refi(dns,rdndrs);
+
+  /*  variable initialization to avoid compiler warning. */
+  reft = 0.0;
+
+  /*  integrate the refraction integral in two parts;  first in the
+   *  troposphere (k=1), then in the stratosphere (k=2). */
+
+  for (k=1; k<=2; k++) {
+
+    /*     initialize previous refraction to ensure at least two iterations. */
+    refold = 1.0;
+
+    /*     start off with 8 strips. */
+    is = 8;
+
+    /*     start z, z range, and start and end values. */
+    if (k==1) {
+      z0 = zobs2;
+      zrange = zt-z0;
+      fb = f0;
+      ff = ft;
+    } else {
+      z0 = zts;
+      zrange = zs-z0;
+      fb = fts;
+      ff = fs;
+    }
+
+    /*     sums of odd and even values. */
+    fo = 0.0;
+    fe = 0.0;
+
+    /*     first time through the loop we have to do every point. */
+    n = 1;
+
+    /*     start of iteration loop (terminates at specified precision). */
+    loop = 1;
+    while (loop) {
+
+      /*        strip width. */
+      h = zrange/((double)is);
+
+      /*        initialize distance from earth centre for quadrature pass. */
+      if (k == 1) {
+        r = r0;
+      } else {
+        r = rt;
+      }
+
+      /*        one pass (no need to compute evens after first time). */
+      for (i=1; i<is; i+=n) {
+
+              /*           sine of observed zenith distance. */
+        sz = sin(z0+h*(double)(i));
+
+        /*           find r (to the nearest metre, maximum four iterations). */
+        if (sz > 1e-20) {
+          w = sk0/sz;
+          rg = r;
+          dr = 1.0e6;
+          j = 0;
+          while ( fabs(dr) > 1.0 && j < 4 ) {
+            j++;
+            if (k==1) {
+              pal1Atmt(r0,tdkok,alpha,gamm2,delm2,
+                       c1,c2,c3,c4,c5,c6,rg,&tg,&dn,&rdndr);
+            } else {
+              pal1Atms(rt,tt,dnt,gamal,rg,&dn,&rdndr);
+            }
+            dr = (rg*dn-w)/(dn+rdndr);
+            rg = rg-dr;
+          }
+          r = rg;
+        }
+
+        /*           find the refractive index and integrand at r. */
+        if (k==1) {
+          pal1Atmt(r0,tdkok,alpha,gamm2,delm2,
+                   c1,c2,c3,c4,c5,c6,r,&t,&dn,&rdndr);
+        } else {
+          pal1Atms(rt,tt,dnt,gamal,r,&dn,&rdndr);
+        }
+        f = refi(dn,rdndr);
+
+        /*           accumulate odd and (first time only) even values. */
+        if (n==1 && i%2 == 0) {
+          fe += f;
+        } else {
+          fo += f;
+        }
+      }
+
+      /*        evaluate the integrand using simpson's rule. */
+      refp = h*(fb+4.0*fo+2.0*fe+ff)/3.0;
+
+      /*        has the required precision been achieved (or can't be)? */
+      if (fabs(refp-refold) > tol && is < ISMAX) {
+
+        /*           no: prepare for next iteration.*/
+
+        /*           save current value for convergence test. */
+        refold = refp;
+
+        /*           double the number of strips. */
+        is += is;
+
+        /*           sum of all current values = sum of next pass's even values. */
+        fe += fo;
+
+        /*           prepare for new odd values. */
+        fo = 0.0;
+
+        /*           skip even values next time. */
+        n = 2;
+      } else {
+
+        /*           yes: save troposphere component and terminate the loop. */
+        if (k==1) reft = refp;
+        loop = 0;
+      }
+    }
+  }
+
+  /*  result. */
+  *ref = reft+refp;
+  if (zobs1 < 0.0) *ref = -(*ref);
+
+}
Index: trunk/FACT++/pal/palRefv.c
===================================================================
--- trunk/FACT++/pal/palRefv.c	(revision 18347)
+++ trunk/FACT++/pal/palRefv.c	(revision 18347)
@@ -0,0 +1,155 @@
+/*
+*+
+*  Name:
+*     palRefv
+
+*  Purpose:
+*     Adjust an unrefracted Cartesian vector to include the effect of atmospheric refraction
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palRefv ( double vu[3], double refa, double refb, double vr[3] );
+
+*  Arguments:
+*     vu[3] = double (Given)
+*        Unrefracted position of the source (Az/El 3-vector)
+*     refa = double (Given)
+*        tan Z coefficient (radian)
+*     refb = double (Given)
+*        tan**3 Z coefficient (radian)
+*     vr[3] = double (Returned)
+*        Refracted position of the source (Az/El 3-vector)
+
+*  Description:
+*     Adjust an unrefracted Cartesian vector to include the effect of
+*     atmospheric refraction, using the simple A tan Z + B tan**3 Z
+*     model.
+
+*  Authors:
+*     TIMJ: Tim Jenness
+*     PTW: Patrick Wallace
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - This routine applies the adjustment for refraction in the
+*     opposite sense to the usual one - it takes an unrefracted
+*     (in vacuo) position and produces an observed (refracted)
+*     position, whereas the A tan Z + B tan**3 Z model strictly
+*     applies to the case where an observed position is to have the
+*     refraction removed.  The unrefracted to refracted case is
+*     harder, and requires an inverted form of the text-book
+*     refraction models;  the algorithm used here is equivalent to
+*     one iteration of the Newton-Raphson method applied to the above
+*     formula.
+*
+*     - Though optimized for speed rather than precision, the present
+*     routine achieves consistency with the refracted-to-unrefracted
+*     A tan Z + B tan**3 Z model at better than 1 microarcsecond within
+*     30 degrees of the zenith and remains within 1 milliarcsecond to
+*     beyond ZD 70 degrees.  The inherent accuracy of the model is, of
+*     course, far worse than this - see the documentation for palRefco
+*     for more information.
+*
+*     - At low elevations (below about 3 degrees) the refraction
+*     correction is held back to prevent arithmetic problems and
+*     wildly wrong results.  For optical/IR wavelengths, over a wide
+*     range of observer heights and corresponding temperatures and
+*     pressures, the following levels of accuracy (arcsec, worst case)
+*     are achieved, relative to numerical integration through a model
+*     atmosphere:
+*
+*              ZD    error
+*
+*              80      0.7
+*              81      1.3
+*              82      2.5
+*              83      5
+*              84     10
+*              85     20
+*              86     55
+*              87    160
+*              88    360
+*              89    640
+*              90   1100
+*              91   1700         } relevant only to
+*              92   2600         } high-elevation sites
+*
+*     The results for radio are slightly worse over most of the range,
+*     becoming significantly worse below ZD=88 and unusable beyond
+*     ZD=90.
+*
+*     - See also the routine palRefz, which performs the adjustment to
+*     the zenith distance rather than in Cartesian Az/El coordinates.
+*     The present routine is faster than palRefz and, except very low down,
+*     is equally accurate for all practical purposes.  However, beyond
+*     about ZD 84 degrees palRefz should be used, and for the utmost
+*     accuracy iterative use of palRefro should be considered.
+
+*  History:
+*     2014-07-15 (TIMJ):
+*        Initial version. A direct copy of the Fortran SLA implementation.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2014 Tim Jenness
+*     Copyright (C) 2004 Patrick Wallace
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+#include <math.h>
+
+void palRefv ( double vu[3], double refa, double refb, double vr[3] ) {
+
+  double x,y,z1,z,zsq,rsq,r,wb,wt,d,cd,f;
+
+  /*  Initial estimate = unrefracted vector */
+  x = vu[0];
+  y = vu[1];
+  z1 = vu[2];
+
+  /*  Keep correction approximately constant below about 3 deg elevation */
+  z = DMAX(z1,0.05);
+
+  /*  One Newton-Raphson iteration */
+  zsq = z*z;
+  rsq = x*x+y*y;
+  r = sqrt(rsq);
+  wb = refb*rsq/zsq;
+  wt = (refa+wb)/(1.0+(refa+3.0*wb)*(zsq+rsq)/zsq);
+  d = wt*r/z;
+  cd = 1.0-d*d/2.0;
+  f = cd*(1.0-wt);
+
+  /*  Post-refraction x,y,z */
+  vr[0] = x*f;
+  vr[1] = y*f;
+  vr[2] = cd*(z+d*r)+(z1-z);
+}
Index: trunk/FACT++/pal/palRefz.c
===================================================================
--- trunk/FACT++/pal/palRefz.c	(revision 18347)
+++ trunk/FACT++/pal/palRefz.c	(revision 18347)
@@ -0,0 +1,191 @@
+/*
+*+
+*  Name:
+*     palRefz
+
+*  Purpose:
+*     Adjust unrefracted zenith distance
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palRefz ( double zu, double refa, double refb, double *zr );
+
+*  Arguments:
+*     zu = double (Given)
+*         Unrefracted zenith distance of the source (radians)
+*     refa = double (Given)
+*         tan Z coefficient (radians)
+*     refb = double (Given)
+*         tan**3 Z coefficient (radian)
+*     zr = double * (Returned)
+*         Refracted zenith distance (radians)
+
+*  Description:
+*     Adjust an unrefracted zenith distance to include the effect of
+*     atmospheric refraction, using the simple A tan Z + B tan**3 Z
+*     model (plus special handling for large ZDs).
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - This routine applies the adjustment for refraction in the
+*     opposite sense to the usual one - it takes an unrefracted
+*     (in vacuo) position and produces an observed (refracted)
+*     position, whereas the A tan Z + B tan**3 Z model strictly
+*     applies to the case where an observed position is to have the
+*     refraction removed.  The unrefracted to refracted case is
+*     harder, and requires an inverted form of the text-book
+*     refraction models;  the formula used here is based on the
+*     Newton-Raphson method.  For the utmost numerical consistency
+*     with the refracted to unrefracted model, two iterations are
+*     carried out, achieving agreement at the 1D-11 arcseconds level
+*     for a ZD of 80 degrees.  The inherent accuracy of the model
+*     is, of course, far worse than this - see the documentation for
+*     palRefco for more information.
+*
+*     - At ZD 83 degrees, the rapidly-worsening A tan Z + B tan^3 Z
+*     model is abandoned and an empirical formula takes over.  For
+*     optical/IR wavelengths, over a wide range of observer heights and
+*     corresponding temperatures and pressures, the following levels of
+*     accuracy (arcsec, worst case) are achieved, relative to numerical
+*     integration through a model atmosphere:
+*
+*              ZR    error
+*
+*              80      0.7
+*              81      1.3
+*              82      2.4
+*              83      4.7
+*              84      6.2
+*              85      6.4
+*              86      8
+*              87     10
+*              88     15
+*              89     30
+*              90     60
+*              91    150         } relevant only to
+*              92    400         } high-elevation sites
+*
+*     For radio wavelengths the errors are typically 50% larger than
+*     the optical figures and by ZD 85 deg are twice as bad, worsening
+*     rapidly below that.  To maintain 1 arcsec accuracy down to ZD=85
+*     at the Green Bank site, Condon (2004) has suggested amplifying
+*     the amount of refraction predicted by palRefz below 10.8 deg
+*     elevation by the factor (1+0.00195*(10.8-E_t)), where E_t is the
+*     unrefracted elevation in degrees.
+*
+*     The high-ZD model is scaled to match the normal model at the
+*     transition point;  there is no glitch.
+*
+*     - Beyond 93 deg zenith distance, the refraction is held at its
+*     93 deg value.
+*
+*     - See also the routine palRefv, which performs the adjustment in
+*     Cartesian Az/El coordinates, and with the emphasis on speed
+*     rather than numerical accuracy.
+
+*  References:
+*     Condon,J.J., Refraction Corrections for the GBT, PTCS/PN/35.2,
+*     NRAO Green Bank, 2004.
+
+*  History:
+*     2012-08-24 (TIMJ):
+*        Initial version, ported directly from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2004 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void palRefz ( double zu, double refa, double refb, double *zr ) {
+
+  /* Constants */
+
+  /* Largest usable ZD (deg) */
+  const double D93 = 93.0;
+
+  /* ZD at which one model hands over to the other (radians) */
+  const double Z83 = 83.0 * PAL__DD2R;
+
+  /* coefficients for high ZD model (used beyond ZD 83 deg) */
+  const double C1 = +0.55445;
+  const double C2 = -0.01133;
+  const double C3 = +0.00202;
+  const double C4 = +0.28385;
+  const double C5 = +0.02390;
+
+  /* High-ZD-model prefiction (deg) for that point */
+  const double REF83 = (C1+C2*7.0+C3*49.0)/(1.0+C4*7.0+C5*49.0);
+
+  double zu1,zl,s,c,t,tsq,tcu,ref,e,e2;
+
+  /*  perform calculations for zu or 83 deg, whichever is smaller */
+  zu1 = DMIN(zu,Z83);
+
+  /*  functions of ZD */
+  zl = zu1;
+  s = sin(zl);
+  c = cos(zl);
+  t = s/c;
+  tsq = t*t;
+  tcu = t*tsq;
+
+  /*  refracted zd (mathematically to better than 1 mas at 70 deg) */
+  zl = zl-(refa*t+refb*tcu)/(1.0+(refa+3.0*refb*tsq)/(c*c));
+
+  /*  further iteration */
+  s = sin(zl);
+  c = cos(zl);
+  t = s/c;
+  tsq = t*t;
+  tcu = t*tsq;
+  ref = zu1-zl+
+    (zl-zu1+refa*t+refb*tcu)/(1.0+(refa+3.0*refb*tsq)/(c*c));
+
+  /*  special handling for large zu */
+  if (zu > zu1) {
+    e = 90.0-DMIN(D93,zu*PAL__DR2D);
+    e2 = e*e;
+    ref = (ref/REF83)*(C1+C2*e+C3*e2)/(1.0+C4*e+C5*e2);
+  }
+
+  /*  return refracted zd */
+  *zr = zu-ref;
+
+}
Index: trunk/FACT++/pal/palRverot.c
===================================================================
--- trunk/FACT++/pal/palRverot.c	(revision 18347)
+++ trunk/FACT++/pal/palRverot.c	(revision 18347)
@@ -0,0 +1,91 @@
+/*
+*+
+*  Name:
+*     palRverot
+
+*  Purpose:
+*     Velocity component in a given direction due to Earth rotation
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palRverot ( double phi, double ra, double da, double st );
+
+*  Arguments:
+*     phi = double (Given)
+*        latitude of observing station (geodetic) (radians)
+*     ra = double (Given)
+*        apparent RA (radians)
+*     da = double (Given)
+*        apparent Dec (radians)
+*     st = double (Given)
+*        Local apparent sidereal time.
+
+*  Returned Value:
+*     palRverot = double
+*        Component of Earth rotation in direction RA,DA (km/s).
+*        The result is +ve when the observatory is receding from the
+*        given point on the sky.
+
+*  Description:
+*     Calculate the velocity component in a given direction due to Earth
+*     rotation.
+*
+*     The simple algorithm used assumes a spherical Earth, of
+*     a radius chosen to give results accurate to about 0.0005 km/s
+*     for observing stations at typical latitudes and heights.  For
+*     applications requiring greater precision, use the routine
+*     palPvobs.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-03-02 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+
+#include <math.h>
+
+double palRverot ( double phi, double ra, double da, double st ) {
+
+  /*  Nominal mean sidereal speed of Earth equator in km/s (the actual
+   *  value is about 0.4651) */
+  const double espeed = 0.4655;
+  return espeed * cos(phi) * sin(st-ra) * cos(da);
+}
Index: trunk/FACT++/pal/palRvgalc.c
===================================================================
--- trunk/FACT++/pal/palRvgalc.c	(revision 18347)
+++ trunk/FACT++/pal/palRvgalc.c	(revision 18347)
@@ -0,0 +1,111 @@
+/*
+*+
+*  Name:
+*     palRvgalc
+
+*  Purpose:
+*     Velocity component in a given direction due to the rotation
+*     of the Galaxy.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palRvgalc( double r2000, double d2000 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 mean RA (radians)
+*     d2000 = double (Given)
+*        J2000.0 mean Dec (radians)
+
+*  Returned Value:
+*     Component of dynamical LSR motion in direction R2000,D2000 (km/s).
+
+*  Description:
+*     This function returns the Component of dynamical LSR motion in
+*     the direction of R2000,D2000. The result is +ve when the dynamical
+*     LSR is receding from the given point on the sky.
+*
+*  Notes:
+*     - The Local Standard of Rest used here is a point in the
+*     vicinity of the Sun which is in a circular orbit around
+*     the Galactic centre.  Sometimes called the "dynamical" LSR,
+*     it is not to be confused with a "kinematical" LSR, which
+*     is the mean standard of rest of star catalogues or stellar
+*     populations.
+*
+*  Reference:
+*     - The orbital speed of 220 km/s used here comes from Kerr &
+*     Lynden-Bell (1986), MNRAS, 221, p1023.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-16 (DSB):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+double palRvgalc( double r2000, double d2000 ){
+
+/* Local Variables: */
+   double vb[ 3 ];
+
+/*
+*  LSR velocity due to Galactic rotation
+*
+*  Speed = 220 km/s
+*  Apex  = L2,B2  90deg, 0deg
+*        = RA,Dec  21 12 01.1  +48 19 47  J2000.0
+*
+*  This is expressed in the form of a J2000.0 x,y,z vector:
+*
+*      VA(1) = X = -SPEED*COS(RA)*COS(DEC)
+*      VA(2) = Y = -SPEED*SIN(RA)*COS(DEC)
+*      VA(3) = Z = -SPEED*SIN(DEC)
+*/
+
+   double va[ 3 ] = { -108.70408, +97.86251, -164.33610 };
+
+/* Convert given J2000 RA,Dec to x,y,z. */
+   eraS2c( r2000, d2000, vb );
+
+/* Compute dot product with LSR motion vector. */
+   return eraPdp( va, vb );
+}
Index: trunk/FACT++/pal/palRvlg.c
===================================================================
--- trunk/FACT++/pal/palRvlg.c	(revision 18347)
+++ trunk/FACT++/pal/palRvlg.c	(revision 18347)
@@ -0,0 +1,106 @@
+/*
+*+
+*  Name:
+*     palRvlg
+
+*  Purpose:
+*     Velocity component in a given direction due to Galactic rotation
+*     and motion of the local group.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palRvlg( double r2000, double d2000 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 mean RA (radians)
+*     d2000 = double (Given)
+*        J2000.0 mean Dec (radians)
+
+*  Returned Value:
+*     Component of SOLAR motion in direction R2000,D2000 (km/s).
+
+*  Description:
+*     This function returns the velocity component in a given
+*     direction due to the combination of the rotation of the
+*     Galaxy and the motion of the Galaxy relative to the mean
+*     motion of the local group. The result is +ve when the Sun
+*     is receding from the given point on the sky.
+*
+*  Reference:
+*     - IAU Trans 1976, 168, p201.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-16 (DSB):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+double palRvlg( double r2000, double d2000 ){
+
+/* Local Variables: */
+   double vb[ 3 ];
+
+/*
+*
+*  Solar velocity due to Galactic rotation and translation
+*
+*  Speed = 300 km/s
+*
+*  Apex  = L2,B2  90deg, 0deg
+*        = RA,Dec  21 12 01.1  +48 19 47  J2000.0
+*
+*  This is expressed in the form of a J2000.0 x,y,z vector:
+*
+*      VA(1) = X = -SPEED*COS(RA)*COS(DEC)
+*      VA(2) = Y = -SPEED*SIN(RA)*COS(DEC)
+*      VA(3) = Z = -SPEED*SIN(DEC)
+*/
+
+   double va[ 3 ] = { -148.23284, +133.44888, -224.09467 };
+
+/* Convert given J2000 RA,Dec to x,y,z. */
+   eraS2c( r2000, d2000, vb );
+
+/* Compute dot product with Solar motion vector. */
+   return eraPdp( va, vb );
+}
Index: trunk/FACT++/pal/palRvlsrd.c
===================================================================
--- trunk/FACT++/pal/palRvlsrd.c	(revision 18347)
+++ trunk/FACT++/pal/palRvlsrd.c	(revision 18347)
@@ -0,0 +1,116 @@
+/*
+*+
+*  Name:
+*     palRvlsrd
+
+*  Purpose:
+*     Velocity component in a given direction due to the Sun's motion
+*     with respect to the dynamical Local Standard of Rest.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palRvlsrd( double r2000, double d2000 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 mean RA (radians)
+*     d2000 = double (Given)
+*        J2000.0 mean Dec (radians)
+
+*  Returned Value:
+*     Component of "peculiar" solar motion in direction R2000,D2000 (km/s).
+
+*  Description:
+*     This function returns the velocity component in a given direction
+*     due to the Sun's motion with respect to the dynamical Local Standard
+*     of Rest. The result is +ve when the Sun is receding from the given
+*     point on the sky.
+
+*  Notes:
+*     - The Local Standard of Rest used here is the "dynamical" LSR,
+*     a point in the vicinity of the Sun which is in a circular orbit
+*     around the Galactic centre.  The Sun's motion with respect to the
+*     dynamical LSR is called the "peculiar" solar motion.
+*     - There is another type of LSR, called a "kinematical" LSR.  A
+*     kinematical LSR is the mean standard of rest of specified star
+*     catalogues or stellar populations, and several slightly different
+*     kinematical LSRs are in use.  The Sun's motion with respect to an
+*     agreed kinematical LSR is known as the "standard" solar motion.
+*     To obtain a radial velocity correction with respect to an adopted
+*     kinematical LSR use the routine palRvlsrk.
+
+*  Reference:
+*     - Delhaye (1965), in "Stars and Stellar Systems", vol 5, p73.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-16 (DSB):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+double palRvlsrd( double r2000, double d2000 ){
+
+/* Local Variables: */
+   double vb[ 3 ];
+
+/*
+*  Peculiar solar motion from Delhaye 1965: in Galactic Cartesian
+*  coordinates (+9,+12,+7) km/s.  This corresponds to about 16.6 km/s
+*  towards Galactic coordinates L2 = 53 deg, B2 = +25 deg, or RA,Dec
+*  17 49 58.7 +28 07 04 J2000.
+*
+*  The solar motion is expressed here in the form of a J2000.0
+*  equatorial Cartesian vector:
+*
+*      VA(1) = X = -SPEED*COS(RA)*COS(DEC)
+*      VA(2) = Y = -SPEED*SIN(RA)*COS(DEC)
+*      VA(3) = Z = -SPEED*SIN(DEC)
+*/
+
+   double va[ 3 ] = { +0.63823, +14.58542, -7.80116 };
+
+/* Convert given J2000 RA,Dec to x,y,z. */
+   eraS2c( r2000, d2000, vb );
+
+/* Compute dot product with Solar motion vector. */
+   return eraPdp( va, vb );
+}
Index: trunk/FACT++/pal/palRvlsrk.c
===================================================================
--- trunk/FACT++/pal/palRvlsrk.c	(revision 18347)
+++ trunk/FACT++/pal/palRvlsrk.c	(revision 18347)
@@ -0,0 +1,116 @@
+/*
+*+
+*  Name:
+*     palRvlsrk
+
+*  Purpose:
+*     Velocity component in a given direction due to the Sun's motion
+*     with respect to an adopted kinematic Local Standard of Rest.
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     double palRvlsrk( double r2000, double d2000 )
+
+*  Arguments:
+*     r2000 = double (Given)
+*        J2000.0 mean RA (radians)
+*     d2000 = double (Given)
+*        J2000.0 mean Dec (radians)
+
+*  Returned Value:
+*     Component of "standard" solar motion in direction R2000,D2000 (km/s).
+
+*  Description:
+*     This function returns the velocity component in a given direction
+*     due to the Sun's motion with respect to an adopted kinematic
+*     Local Standard of Rest. The result is +ve when the Sun is receding
+*     from the given point on the sky.
+
+*  Notes:
+*     - The Local Standard of Rest used here is one of several
+*     "kinematical" LSRs in common use.  A kinematical LSR is the mean
+*     standard of rest of specified star catalogues or stellar
+*     populations.  The Sun's motion with respect to a kinematical LSR
+*     is known as the "standard" solar motion.
+*     - There is another sort of LSR, the "dynamical" LSR, which is a
+*     point in the vicinity of the Sun which is in a circular orbit
+*     around the Galactic centre.  The Sun's motion with respect to
+*     the dynamical LSR is called the "peculiar" solar motion.  To
+*     obtain a radial velocity correction with respect to the
+*     dynamical LSR use the routine palRvlsrd.
+
+*  Reference:
+*     - Delhaye (1965), in "Stars and Stellar Systems", vol 5, p73.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-16 (DSB):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+double palRvlsrk( double r2000, double d2000 ){
+
+/* Local Variables: */
+   double vb[ 3 ];
+
+/*
+*  Standard solar motion (from Methods of Experimental Physics, ed Meeks,
+*  vol 12, part C, sec 6.1.5.2, p281):
+*
+*  20 km/s towards RA 18h Dec +30d (1900).
+*
+*  The solar motion is expressed here in the form of a J2000.0
+*  equatorial Cartesian vector:
+*
+*      VA(1) = X = -SPEED*COS(RA)*COS(DEC)
+*      VA(2) = Y = -SPEED*SIN(RA)*COS(DEC)
+*      VA(3) = Z = -SPEED*SIN(DEC)
+*/
+
+   double va[ 3 ] = { -0.29000, +17.31726, -10.00141 };
+
+/* Convert given J2000 RA,Dec to x,y,z. */
+   eraS2c( r2000, d2000, vb );
+
+/* Compute dot product with Solar motion vector. */
+   return eraPdp( va, vb );
+}
Index: trunk/FACT++/pal/palSubet.c
===================================================================
--- trunk/FACT++/pal/palSubet.c	(revision 18347)
+++ trunk/FACT++/pal/palSubet.c	(revision 18347)
@@ -0,0 +1,112 @@
+/*
+*+
+*  Name:
+*     palSubet
+
+*  Purpose:
+*     Remove the E-terms from a pre IAU 1976 catalogue RA,Dec
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palSubet ( double rc, double dc, double eq,
+*                     double *rm, double *dm );
+
+*  Arguments:
+*     rc = double (Given)
+*        RA with E-terms included (radians)
+*     dc = double (Given)
+*        Dec with E-terms included (radians)
+*     eq = double (Given)
+*        Besselian epoch of mean equator and equinox
+*     rm = double * (Returned)
+*        RA without E-terms (radians)
+*     dm = double * (Returned)
+*        Dec without E-terms (radians)
+
+*  Description:
+*     Remove the E-terms (elliptic component of annual aberration)
+*     from a pre IAU 1976 catalogue RA,Dec to give a mean place.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     Most star positions from pre-1984 optical catalogues (or
+*     derived from astrometry using such stars) embody the
+*     E-terms.  This routine converts such a position to a
+*     formal mean place (allowing, for example, comparison with a
+*     pulsar timing position).
+
+*  See Also:
+*     Explanatory Supplement to the Astronomical Ephemeris,
+*     section 2D, page 48.
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palSubet ( double rc, double dc, double eq, double *rm, double *dm ) {
+  double a[3];   /* The E-terms */
+  double v[3];
+  double f;
+  int i;
+
+  /* Note the preference for IAU routines */
+
+  /* Retrieve the E-terms */
+  palEtrms( eq, a );
+
+  /* Spherical to Cartesian */
+  eraS2c( rc, dc, v );
+
+  /* Include the E-terms */
+  f = 1.0 + eraPdp( v, a );
+  for (i=0; i<3; i++) {
+    v[i] = f*v[i] - a[i];
+  }
+
+  /* Cartesian to spherical */
+  eraC2s( v, rm, dm );
+
+  /* Bring RA into conventional range */
+  *rm = eraAnp( *rm );
+
+}
Index: trunk/FACT++/pal/palSupgal.c
===================================================================
--- trunk/FACT++/pal/palSupgal.c	(revision 18347)
+++ trunk/FACT++/pal/palSupgal.c	(revision 18347)
@@ -0,0 +1,116 @@
+/*
+*+
+*  Name:
+*     palSupgal
+
+*  Purpose:
+*     Convert from supergalactic to galactic coordinates
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palSupgal ( double dsl, double dsb, double *dl, double *db );
+
+*  Arguments:
+*     dsl = double (Given)
+*       Supergalactic longitude.
+*     dsb = double (Given)
+*       Supergalactic latitude.
+*     dl = double * (Returned)
+*       Galactic longitude.
+*     db = double * (Returned)
+*       Galactic latitude.
+
+*  Description:
+*     Transformation from de Vaucouleurs supergalactic coordinates
+*     to IAU 1958 galactic coordinates
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  See Also:
+*     - de Vaucouleurs, de Vaucouleurs, & Corwin, Second Reference
+*       Catalogue of Bright Galaxies, U. Texas, page 8.
+*     - Systems & Applied Sciences Corp., Documentation for the
+*       machine-readable version of the above catalogue,
+*       Contract NAS 5-26490.
+*
+*     (These two references give different values for the galactic
+*     longitude of the supergalactic origin.  Both are wrong;  the
+*     correct value is L2=137.37.)
+
+*  History:
+*     2012-02-12(TIMJ):
+*        Initial version with documentation taken from Fortran SLA
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1995 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "pal1sofa.h"
+
+void palSupgal ( double dsl, double dsb, double *dl, double *db ) {
+
+  double v1[3];
+  double v2[3];
+
+/*
+*  System of supergalactic coordinates:
+*
+*    SGL   SGB        L2     B2      (deg)
+*     -    +90      47.37  +6.32
+*     0     0         -      0
+*
+*  Galactic to supergalactic rotation matrix:
+*/
+  double rmat[3][3] = {
+    { -0.735742574804,+0.677261296414,+0.000000000000 },
+    { -0.074553778365,-0.080991471307,+0.993922590400 },
+    { +0.673145302109,+0.731271165817,+0.110081262225 }
+  };
+
+  /* Spherical to Cartesian */
+  eraS2c( dsl, dsb, v1 );
+
+  /* Supergalactic to galactic */
+  eraTrxp( rmat, v1, v2 );
+
+  /* Cartesian to spherical */
+  eraC2s( v2, dl, db );
+
+  /* Express in conventional ranges */
+  *dl = eraAnp( *dl );
+  *db = eraAnpm( *db );
+
+}
Index: trunk/FACT++/pal/palTest.c
===================================================================
--- trunk/FACT++/pal/palTest.c	(revision 18347)
+++ trunk/FACT++/pal/palTest.c	(revision 18347)
@@ -0,0 +1,2057 @@
+/*
+*+
+*  Name:
+*     palTest
+
+*  Purpose:
+*     Test the PAL library
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Application
+
+*  Description:
+*     Test the PAL library is functioning correctly. Uses some of the SLA test code.
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+*     USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+static int verbose = 1;
+
+/* Support functions to allow to test results.
+   viv and vvd match the SOFA/ERFA implementations */
+
+static void viv(int ival, int ivalok, const char *func, const char *test,
+                int *status)
+/*
+**  - - - -
+**   v i v
+**  - - - -
+**
+**  Validate an integer result.
+**
+**  Internal function used by t_sofa_c program.
+**
+**  Given:
+**     ival     int          value computed by function under test
+**     ivalok   int          correct value
+**     func     char[]       name of function under test
+**     test     char[]       name of individual test
+**
+**  Given and returned:
+**     status   int          set to FALSE if test fails
+**
+**  This revision:  2009 November 4
+*/
+{
+   if (ival != ivalok) {
+      *status = 1;
+      printf("%s failed: %s want %d got %d\n",
+             func, test, ivalok, ival);
+   } else if (verbose) {
+      printf("%s passed: %s want %d got %d\n",
+                    func, test, ivalok, ival);
+   }
+   return;
+}
+
+static void vvd(double val, double valok, double dval,
+                const char *func, const char *test, int *status)
+/*
+**  - - - -
+**   v v d
+**  - - - -
+**
+**  Validate a double result.
+**
+**  Internal function used by t_sofa_c program.
+**
+**  Given:
+**     val      double       value computed by function under test
+**     valok    double       expected value
+**     dval     double       maximum allowable error
+**     func     char[]       name of function under test
+**     test     char[]       name of individual test
+**
+**  Given and returned:
+**     status   int          set to FALSE if test fails
+**
+**  This revision:  2008 June 8
+*/
+{
+   double a, f;   /* absolute and fractional error */
+
+
+   a = val - valok;
+   if (fabs(a) > dval) {
+      f = fabs(valok / a);
+      *status = 1;
+      printf("%s failed: %s want %.20g got %.20g (1/%.3g)\n",
+             func, test, valok, val, f);
+   } else if (verbose) {
+      printf("%s passed: %s want %.20g got %.20g\n",
+             func, test, valok, val);
+   }
+   return;
+}
+
+/* Verify a string */
+static void vcs( const char * val, const char * valok,
+                 const char * func, const char * test,
+                 int *status ) {
+
+  if (strcmp(val, valok) != 0) {
+    *status = 1;
+    printf("%s failed: %s want %s got %s\n",
+           func, test, valok, val );
+  } else if (verbose) {
+    printf("%s passed: %s want %s got %s\n",
+           func, test, valok, val );
+  }
+  return;
+
+}
+
+/* Verify the 3x3 rmat matrix */
+static void
+vrmat( double rmat[3][3], double expected[3][3], const char * func,
+       double dval, int * status ) {
+  int i;
+  char buf[10];
+  for( i = 0; i < 3; i++ ) {
+    int j;
+    for( j = 0; j < 3; j++ ) {
+      sprintf( buf, "%d,%d", i, j );
+      vvd( rmat[i][j], expected[i][j], dval, func, buf, status );
+    }
+  }
+}
+
+/* Verify a vector */
+static void
+vvec( int len, double *vec, double *expected, const char *func,
+      int *status ) {
+  int i;
+  char buf[10];
+  for( i = 0; i < len; i++ ) {
+    sprintf( buf, "%d", i );
+    vvd( vec[i], expected[i], 1e-12, func, buf, status );
+  }
+}
+
+/******************************************************************/
+/*          TEST FUNCTIONS          */
+
+/* Adding E-terms */
+
+static void t_addet( int *status ) {
+  double r1,d1,r2,d2;
+  double rm = 2.;
+  double dm = -1.;
+  double eq = 1975.;
+
+
+  palAddet ( rm, dm, eq, &r1, &d1 );
+  vvd ( r1 - rm, 2.983864874295250e-6, 1e-12, "palAddet",
+	"R", status );
+  vvd ( d1 - dm, 2.379650804185118e-7, 1e-12, "palAddet",
+	"D", status );
+
+  palSubet ( r1, d1, eq, &r2, &d2 );
+  vvd ( r2 - rm, 0, 1e-12, "palSubet", "R", status );
+  vvd ( d2 - dm, 0, 1e-12, "palSubet", "D", status );
+
+}
+
+static void t_afin( int * status ) {
+
+  int j;
+  int i = 1;
+  double d = 0.0;
+  const char * s = "12 34 56.7 |";
+  const char * s2 = "45 00 00.000 ";
+
+  palDafin (s, &i, &d, &j);
+  viv ( i, 12, "palDafin", "I", status );
+  vvd ( d, 0.2196045986911432, 1e-12, "palDafin", "A",
+        status );
+  viv ( j, 0, "palDafin", "J", status );
+
+  i = 1;
+  palDafin (s2, &i, &d, &j);
+  viv ( i, 14, "palDafin", "I", status );
+  vvd ( d, PAL__DPI/4.0, 1e-12, "palDafin", "A",
+        status );
+  viv ( j, 0, "palDafin", "J", status );
+}
+
+/* Altaz */
+
+static void t_altaz( int *status ) {
+  double az, azd, azdd, el, eld, eldd, pa, pad, padd;
+  palAltaz( 0.7, -0.7, -0.65,
+            &az, &azd, &azdd, &el, &eld, &eldd, &pa, &pad, &padd );
+
+  vvd ( az, 4.400560746660174, 1e-12, "palAltaz",
+        "AZ", status );
+  vvd ( azd, -0.2015438937145421, 1e-13, "palAltaz",
+        "AZD", status );
+  vvd ( azdd, -0.4381266949668748, 1e-13, "palAltaz",
+        "AZDD", status );
+  vvd ( el, 1.026646506651396, 1e-12, "palAltaz",
+        "EL", status );
+  vvd ( eld, -0.7576920683826450, 1e-13, "palAltaz",
+        "ELD", status );
+  vvd ( eldd, 0.04922465406857453, 1e-14, "palAltaz",
+        "ELDD", status );
+  vvd ( pa, 1.707639969653937, 1e-12, "palAltaz",
+        "PA", status );
+  vvd ( pad, 0.4717832355365627, 1e-13, "palAltaz",
+        "PAD", status );
+  vvd ( padd, -0.2957914128185515, 1e-13, "palAltaz",
+        "PADD", status );
+}
+
+/* Airmass */
+
+static void t_airmas( int *status ) {
+  vvd ( palAirmas ( 1.2354 ), 3.015698990074724,
+        1e-12, "palAirmas", " ", status );
+}
+
+/* Apparent to mean place */
+
+static void t_amp ( int *status ) {
+  double rm, dm;
+
+  /* Original SLA test is not accurate since palMapqk
+     differs from slaMapqk */
+  palAmp ( 2.345, -1.234, 50100, 1990, &rm, &dm );
+  vvd ( rm, 2.344472180027961, 1e-6, "palAmp", "R",
+        status );
+  vvd ( dm, -1.233573099847705, 1e-7, "palAmp", "D",
+        status );
+
+  /* This is the palMapqk test */
+  palAmp( 1.234, -0.567, 55927.0, 2010.0, &rm, &dm );
+  vvd( rm, 1.2335120411026936349, 1.0E-12, "palAmp", "rm", status );
+  vvd( dm, -0.56702908706930343907, 1.0E-12, "palAmp", "dm", status );
+}
+
+/* Apparent to Observed place */
+
+static void t_aop ( int *status ) {
+
+  int i;
+
+  double rap, dap, date, dut, elongm, phim, hm, xp, yp,
+    tdk, pmb, rh, wl, tlr, aob, zob, hob, dob, rob, aoprms[14];
+
+  dap = -0.1234;
+  date = 51000.1;
+  dut = 25.0;
+  elongm = 2.1;
+  phim = 0.5;
+  hm = 3000.0;
+  xp = -0.5e-6;
+  yp = 1.0e-6;
+  tdk = 280.0;
+  pmb = 550.0;
+  rh = 0.6;
+  tlr = 0.006;
+
+  for (i=1; i<=3; i++) {
+
+    if ( i == 1 ) {
+      rap = 2.7;
+      wl = 0.45;
+    } else if ( i == 2 ) {
+      rap = 2.345;
+    } else {
+      wl = 1.0e6;
+    }
+
+    palAop ( rap, dap, date, dut, elongm, phim, hm, xp, yp,
+             tdk, pmb, rh, wl, tlr, &aob, &zob, &hob, &dob, &rob );
+
+    if ( i == 1 ) {
+      vvd( aob, 1.812817787123283034, 1e-10, "palAop",
+           "lo aob", status );
+      vvd( zob, 1.393860816635714034, 1e-8, "palAop",
+           "lo zob", status );
+      vvd( hob, -1.297808009092456683, 1e-8, "palAop",
+           "lo hob", status );
+      vvd( dob, -0.122967060534561, 1e-8, "palAop",
+           "lo dob", status );
+      vvd( rob, 2.699270287872084, 1e-8, "palAop",
+           "lo rob", status );
+    } else if ( i == 2 ) {
+      vvd( aob, 2.019928026670621442, 1e-10, "palAop",
+           "aob/o", status );
+      vvd( zob, 1.101316172427482466, 1e-10, "palAop",
+           "zob/o", status );
+      vvd( hob, -0.9432923558497740862, 1e-10, "palAop",
+           "hob/o", status );
+      vvd( dob, -0.1232144708194224, 1e-10, "palAop",
+           "dob/o", status );
+      vvd( rob, 2.344754634629428, 1e-10, "palAop",
+           "rob/o", status );
+    } else {
+      vvd( aob, 2.019928026670621442, 1e-10, "palAop",
+           "aob/r", status );
+      vvd( zob, 1.101267532198003760, 1e-10, "palAop",
+           "zob/r", status );
+      vvd( hob, -0.9432533138143315937, 1e-10, "palAop",
+           "hob/r", status );
+      vvd( dob, -0.1231850665614878, 1e-10, "palAop",
+           "dob/r", status );
+      vvd( rob, 2.344715592593984, 1e-10, "palAop",
+           "rob/r", status );
+    }
+  }
+
+  date = 48000.3;
+  wl = 0.45;
+
+  palAoppa ( date, dut, elongm, phim, hm, xp, yp, tdk,
+             pmb, rh, wl, tlr, aoprms );
+  vvd( aoprms[0], 0.4999993892136306, 1e-13, "palAoppa",
+       "0", status );
+  vvd( aoprms[1], 0.4794250025886467, 1e-13, "palAoppa",
+       "1", status );
+  vvd( aoprms[2], 0.8775828547167932, 1e-13, "palAoppa",
+       "2", status );
+  vvd( aoprms[3], 1.363180872136126e-6, 1e-13, "palAoppa",
+       "3", status );
+  vvd( aoprms[4], 3000.0, 1e-10, "palAoppa", "4",
+       status );
+  vvd( aoprms[5], 280.0, 1e-11, "palAoppa", "5",
+       status );
+  vvd( aoprms[6], 550.0, 1e-11, "palAoppa", "6",
+       status );
+  vvd( aoprms[7], 0.6, 1e-13, "palAoppa", "7",
+       status );
+  vvd( aoprms[8], 0.45, 1e-13, "palAoppa", "8",
+       status );
+  vvd( aoprms[9], 0.006, 1e-15, "palAoppa", "9",
+       status );
+  vvd( aoprms[10], 0.0001562803328459898, 1e-13,
+       "palAoppa", "10", status );
+  vvd( aoprms[11], -1.792293660141e-7, 1e-13,
+       "palAoppa", "11", status );
+  vvd( aoprms[12], 2.101874231495843, 1e-13,
+       "palAoppa", "12", status );
+  vvd( aoprms[13], 7.601916802079765, 1e-8,
+       "palAoppa", "13", status );
+
+  palOap ( "r", 1.6, -1.01, date, dut, elongm, phim,
+           hm, xp, yp, tdk, pmb, rh, wl, tlr, &rap, &dap );
+  vvd( rap, 1.601197569844787, 1e-10, "palOap",
+       "rr", status );
+  vvd( dap, -1.012528566544262, 1e-10, "palOap",
+       "rd", status );
+  palOap ( "h", -1.234, 2.34, date, dut, elongm, phim,
+           hm, xp, yp, tdk, pmb, rh, wl, tlr, &rap, &dap );
+  vvd( rap, 5.693087688154886463, 1e-10, "palOap",
+       "hr", status );
+  vvd( dap, 0.8010281167405444, 1e-10, "palOap",
+       "hd", status );
+  palOap ( "a", 6.1, 1.1, date, dut, elongm, phim,
+           hm, xp, yp, tdk, pmb, rh, wl, tlr, &rap, &dap );
+  vvd( rap, 5.894305175192448940, 1e-10, "palOap",
+       "ar", status );
+  vvd( dap, 1.406150707974922, 1e-10, "palOap",
+       "ad", status );
+
+  palOapqk ( "r", 2.1, -0.345, aoprms, &rap, &dap );
+  vvd( rap, 2.10023962776202, 1e-10, "palOapqk",
+       "rr", status );
+  vvd( dap, -0.3452428692888919, 1e-10, "palOapqk",
+       "rd", status );
+  palOapqk ( "h", -0.01, 1.03, aoprms, &rap, &dap );
+  vvd( rap, 1.328731933634564995, 1e-10, "palOapqk",
+       "hr", status );
+  vvd( dap, 1.030091538647746, 1e-10, "palOapqk",
+       "hd", status );
+  palOapqk ( "a", 4.321, 0.987, aoprms, &rap, &dap );
+  vvd( rap, 0.4375507112075065923, 1e-10, "palOapqk",
+       "ar", status );
+  vvd( dap, -0.01520898480744436, 1e-10, "palOapqk",
+       "ad", status );
+
+  palAoppat ( date + PAL__DS2R, aoprms );
+  vvd( aoprms[13], 7.602374979243502, 1e-8, "palAoppat",
+       " ", status );
+}
+
+/* Bearings */
+
+static void t_bear( int *status ) {
+  double a1 = 1.234;
+  double b1 = -0.123;
+  double a2 = 2.345;
+  double b2 = 0.789;
+
+  double d1[3];
+  double d2[3];
+
+  vvd ( palDbear ( a1, b1, a2, b2 ), 0.7045970341781791,
+	1e-12, "palDbear", " ", status );
+  palDcs2c ( a1, b1, d1 );
+  palDcs2c ( a2, b2, d2 );
+
+  vvd ( palDpav ( d1, d2 ), 0.7045970341781791,
+	1e-12, "palDpav", " ", status );
+
+}
+
+/* Calendar to MJD */
+
+static void t_caldj( int *status ) {
+  int j;
+  double djm;
+
+  palCaldj ( 1999, 12, 31, &djm, &j );
+  vvd ( djm, 51543, 0, "palCaldj", " ", status );
+  viv ( j, 0, "palCaldj", "J", status );
+}
+
+/* palDaf2r */
+
+static void t_caf2r( int * status ) {
+  int j;
+  double dr;
+
+  palDaf2r ( 76, 54, 32.1, &dr, &j );
+  vvd ( dr, 1.342313819975276, 1e-12, "palDaf2r",
+        "r", status );
+  viv ( j, 0, "palDaf2r", "j", status );
+}
+
+/* Test palDcc2s routines */
+
+static void t_cc2s( int * status ) {
+  double dv[3] = { 100., -50., 25. };
+  double da, db;
+
+  palDcc2s ( dv, &da, &db );
+  vvd ( da, -0.4636476090008061, 1e-12, "palDcc2s",
+        "A", status );
+  vvd ( db, 0.2199879773954594, 1e-12, "palDcc2s",
+        "B", status );
+}
+
+/* palDd2tf */
+
+static void t_cd2tf( int *status ) {
+  int ihmsf[4];
+  char s;
+
+  palDd2tf ( 4, -0.987654321, &s, ihmsf );
+  viv ( s, '-', "palDd2tf", "S", status );
+  viv ( ihmsf[0], 23, "palDd2tf", "(1)", status );
+  viv ( ihmsf[1], 42, "palDd2tf", "(2)", status );
+  viv ( ihmsf[2], 13, "palDd2tf", "(3)", status );
+  viv ( ihmsf[3], 3333, "palDd2tf", "(4)", status );
+}
+
+/* Calendar to MJD */
+
+static void t_cldj( int *status ) {
+  double d;
+  int j;
+
+  palCldj ( 1899, 12, 31, &d, &j );
+  vvd ( d, 15019, 0, "palCldj", "D", status );
+  viv ( j, 0, "palCldj", "J", status );
+}
+
+/* palDr2af */
+
+static void t_cr2af( int *status ) {
+  char s;
+  int idmsf[4];
+  palDr2af ( 4, 2.345, &s, idmsf );
+  viv ( s, '+', "palDr2af", "S", status );
+  viv ( idmsf[0], 134, "palDr2af", "(1)", status );
+  viv ( idmsf[1], 21, "palDr2af", "(2)", status );
+  viv ( idmsf[2], 30, "palDr2af", "(3)", status );
+  viv ( idmsf[3], 9706, "palDr2af", "(4)", status );
+}
+
+/* palDr2tf */
+
+static void t_cr2tf( int *status ) {
+  char s;
+  int ihmsf[4];
+  palDr2tf ( 4, -3.01234, &s, ihmsf );
+  viv ( s, '-', "palDr2tf", "S", status );
+  viv ( ihmsf[0], 11, "palDr2tf", "(1)", status );
+  viv ( ihmsf[1], 30, "palDr2tf", "(2)", status );
+  viv ( ihmsf[2], 22, "palDr2tf", "(3)", status );
+  viv ( ihmsf[3], 6484, "palDr2tf", "(4)", status );
+}
+
+/* palDtf2d */
+
+static void t_ctf2d( int *status ) {
+  double dd;
+  int j;
+
+  palDtf2d (23, 56, 59.1, &dd, &j);
+  vvd ( dd, 0.99790625, 1e-12, "palDtf2d", "D", status );
+  viv ( j, 0, "palDtf2d", "J", status );
+}
+
+/* palDtf2r */
+
+static void t_ctf2r( int *status ) {
+  double dr;
+  int j;
+
+  palDtf2r (23, 56, 59.1, &dr, &j);
+  vvd ( dr, 6.270029887942679, 1e-12, "palDtf2r",
+        "R", status );
+  viv ( j, 0, "palDtf2r", "J", status );
+}
+
+static void t_dat ( int *status ) {
+  vvd ( palDat ( 43900 ), 18, 0, "palDat",
+        " ", status );
+  vvd ( palDtt ( 40404 ), 39.709746, 1e-12, "palDtt",
+        " ", status );
+  vvd ( palDt ( 500 ), 4686.7, 1e-10, "palDt",
+        "500", status );
+  vvd ( palDt ( 1400 ), 408, 1e-11, "palDt",
+        "1400", status );
+  vvd ( palDt ( 1950 ), 27.99145626, 1e-12, "palDt",
+        "1950", status );
+}
+
+/* Dates */
+
+static void t_djcal( int *status ) {
+  const double djm = 50123.9999;
+  int iy, im, id;
+  int iydmf[4];
+  int j;
+  double f;
+
+  palDjcal ( 4, djm, iydmf, &j );
+  viv ( iydmf[0], 1996, "palDjcal", "Y", status );
+  viv ( iydmf[1], 2, "palDjcal", "M", status );
+  viv ( iydmf[2], 10, "palDjcal", "D", status );
+  viv ( iydmf[3], 9999, "palDjcal", "F", status );
+  viv ( j, 0, "palDjcal", "J", status );
+
+  palDjcl ( djm, &iy, &im, &id, &f, &j );
+  viv ( iy, 1996, "palDjcl", "Y", status );
+  viv ( im, 2, "palDjcl", "M", status );
+  viv ( id, 10, "palDjcl", "D", status );
+  vvd ( f, 0.9999, 1e-7, "palDjcl", "F", status );
+  viv ( j, 0, "palDjcl", "J", status );
+
+}
+
+/* Matrix inversion */
+
+static void t_dmat( int *status ) {
+  int j;
+  int iw[3];
+  double dd;
+  double da[9] = {
+    2.22,     1.6578,     1.380522,
+    1.6578,   1.380522,   1.22548578,
+    1.380522, 1.22548578, 1.1356276122
+  };
+  double dv[3] = {
+    2.28625, 1.7128825, 1.429432225
+  };
+
+  palDmat( 3, da, dv, &dd, &j, iw );
+  vvd ( da[0], 18.02550629769198,
+	1e-10, "palDmat", "a[0]", status );
+  vvd ( da[1], -52.16386644917280607,
+	1e-10, "palDmat", "a[1]", status );
+  vvd ( da[2], 34.37875949717850495,
+	1e-10, "palDmat", "a[2]", status );
+  vvd ( da[3], -52.16386644917280607,
+	1e-10, "palDmat", "a[3]", status );
+  vvd ( da[4], 168.1778099099805627,
+	1e-10, "palDmat", "a[4]", status );
+  vvd ( da[5], -118.0722869694232670,
+	1e-10, "palDmat", "a[5]", status );
+  vvd ( da[6], 34.37875949717850495,
+	1e-10, "palDmat", "a[6]", status );
+  vvd ( da[7], -118.0722869694232670,
+	1e-10, "palDmat", "a[7]", status );
+  vvd ( da[8], 86.50307003740151262,
+	1e-10, "palDmat", "a[8]", status );
+  vvd ( dv[0], 1.002346480763383,
+	1e-12, "palDmat", "v[0]", status );
+  vvd ( dv[1], 0.03285594016974583489,
+	1e-12, "palDmat", "v[1]", status );
+  vvd ( dv[2], 0.004760688414885247309,
+	1e-12, "palDmat", "v[2]", status );
+  vvd ( dd, 0.003658344147359863,
+	1e-12, "palDmat", "D", status );
+  viv ( j, 0, "palDmat", "J", status );
+
+}
+
+/* Test palDe2h and palDh2e routines */
+
+static void t_e2h( int *status ) {
+  double dh, dd, dp, da, de;
+
+  dh = -0.3;
+  dd = -1.1;
+  dp = -0.7;
+
+  palDe2h( dh, dd, dp, &da, &de );
+  vvd( da, 2.820087515852369, 1e-12, "palDe2h",
+       "AZ", status);
+  vvd( de, 1.132711866443304, 1e-12, "palDe2h",
+       "EL", status );
+
+  palDh2e( da, de, dp, &dh, &dd );
+  vvd( dh, -0.3, 1e-12, "palDh2e", "HA", status);
+  vvd( dd, -1.1, 1e-12, "palDh2e", "DEC", status );
+
+}
+
+/* Epochs */
+
+static void t_epb( int *status ) {
+  vvd ( palEpb( 45123 ), 1982.419793168669, 1e-8,
+        "palEpb", " ", status );
+}
+
+static void t_epb2d( int *status ) {
+  vvd ( palEpb2d( 1975.5 ), 42595.5995279655, 1e-7,
+        "palEpb2d", " ", status );
+}
+
+static void t_epco( int *status ) {
+  vvd ( palEpco ( 'B', 'J', 2000 ), 2000.001277513665,
+        1e-7, "palEpco", "BJ", status );
+  vvd ( palEpco ( 'J', 'B', 1950 ), 1949.999790442300,
+        1e-7, "palEpco", "JB", status );
+  vvd ( palEpco ( 'J', 'j', 2000 ), 2000,
+        1e-7, "palEpco", "JJ", status );
+}
+
+static void t_epj( int *status ) {
+  vvd ( palEpj( 42999 ), 1976.603696098563,
+        1e-7, "palEpj", " ", status );
+}
+
+static void t_epj2d( int *status ) {
+  vvd ( palEpj2d( 2010.077 ), 55225.124250,
+        1e-6, "palEpj2d", " ", status );
+}
+
+/* Equation of the equinoxes */
+
+/* Use SOFA/ERFA test because of change in precession model */
+static void t_eqeqx (int *status ) {
+  vvd ( palEqeqx( 53736. ), -0.8834195072043790156e-5,
+        1e-15, "palEqeqx", " ", status );
+}
+
+/* E-terms */
+
+static void t_etrms( int * status ) {
+  double ev[3];
+
+  palEtrms ( 1976.9, ev );
+
+  vvd ( ev[0], -1.621617102537041e-6, 1e-18, "palEtrms",
+	"X", status );
+  vvd ( ev[1], -3.310070088507914e-7, 1e-18, "palEtrms",
+	"Y", status );
+  vvd ( ev[2], -1.435296627515719e-7, 1e-18, "palEtrms",
+	"Z", status );
+}
+
+/* J2000 to Galactic */
+
+static void t_eqgal( int *status ) {
+  double dl, db;
+
+  palEqgal ( 5.67, -1.23, &dl, &db );
+
+  vvd ( dl, 5.612270780904526, 1e-12, "palEqgal",
+	"DL", status );
+  vvd ( db, -0.6800521449061520, 1e-12, "palEqgal",
+	"DB", status );
+}
+
+/* Galactic to J2000 equatorial */
+
+static void t_galeq( int *status ) {
+  double dr, dd;
+
+  palGaleq ( 5.67, -1.23, &dr, &dd );
+
+  vvd ( dr, 0.04729270418071426, 1e-12, "palGaleq",
+	"DR", status );
+  vvd ( dd, -0.7834003666745548, 1e-12, "palGaleq",
+	"DD", status );
+}
+
+/* Galactic to supergalactic */
+static void t_galsup(int *status ) {
+  double dsl, dsb;
+
+  palGalsup ( 6.1, -1.4, &dsl, &dsb );
+
+  vvd ( dsl, 4.567933268859171, 1e-12, "palGalsup",
+	"DSL", status );
+  vvd ( dsb, -0.01862369899731829, 1e-12, "palGalsup",
+	"DSB", status );
+}
+
+/* Geocentric coordinates */
+
+/* This is not from sla_test.f */
+
+static void t_geoc( int *status ) {
+  double r;
+  double z;
+  /* JCMT */
+  const double lat = 19.822838905884 * PAL__DD2R;
+  const double alt = 4120.0;
+  palGeoc( lat, alt, &r, &z );
+
+  /* Note the lower tolerance than normal since the models in SLA
+     differ from the more up to date model in SOFA/ERFA */
+  vvd( r, 4.01502667039618e-05, 1e-10, "palGeoc", "R", status );
+  vvd( z, 1.43762411970295e-05, 1e-10, "palGeoc", "Z", status );
+
+}
+
+/* Galactic to Fk4 */
+
+static void t_ge50 ( int *status ) {
+  double dr, dd;
+  palGe50( 6.1, -1.55, &dr, &dd );
+  vvd ( dr, 0.1966825219934508, 1e-12, "palGe50",
+        "DR", status );
+  vvd ( dd, -0.4924752701678960, 1e-12, "palGe50",
+        "DD", status );
+
+
+}
+
+/* GMST */
+
+/* We use the SOFA/ERFA test values rather than the values from SLA
+   because the precession models have changed */
+
+static void t_gmst( int *status ) {
+  vvd ( palGmst( 53736. ), 1.754174971870091203,
+        1e-12, "palGmst", " ", status );
+
+  vvd ( palGmsta( 53736., 0.0 ), 1.754174971870091203,
+        1e-12, "palGmsta", " ", status );
+}
+
+/* FK5 */
+
+static void t_fk52h ( int *status ) {
+  double r5, d5, dr5, dd5, rh, dh;
+
+  palFk5hz ( 1.234, -0.987, 1980, &rh, &dh );
+  vvd ( rh, 1.234000136713611301, 1e-13, "palFk5hz",
+        "R", status );
+  vvd ( dh, -0.9869999702020807601, 1e-13, "palFk5hz",
+        "D", status );
+  palHfk5z ( rh, dh, 1980, &r5, &d5, &dr5, &dd5 );
+  vvd ( r5, 1.234, 1e-13, "palHfk5z", "R", status );
+  vvd ( d5, -0.987, 1e-13, "palHfk5z", "D", status );
+  vvd ( dr5, 0.000000006822074, 1e-13, "palHfk5z",
+        "DR", status );
+  vvd ( dd5, -0.000000002334012, 1e-13, "palHfk5z",
+        "DD", status );
+
+}
+
+static void t_intin( int *status ) {
+  const char s[] = "  -12345, , -0  2000  +     ";
+  /*                1234567890123456789012345678 */
+  int i = 1;
+  long n = 0;
+  int j;
+
+  palIntin ( s, &i, &n, &j );
+  viv ( i, 10, "palIntin", "I1", status );
+  viv ( n, -12345, "palIntin", "V1", status );
+  viv ( j, -1, "palIntin", "J1", status );
+
+  palIntin ( s, &i, &n, &j );
+  viv ( i, 12, "palIntin", "I2", status );
+  viv ( n, -12345, "palIntin", "V2", status );
+  viv ( j, 1, "palIntin", "J2", status );
+
+  palIntin ( s, &i, &n, &j );
+  viv ( i, 17, "palIntin", "I3", status );
+  viv ( n, 0, "palIntin", "V3", status );
+  viv ( j, -1, "palIntin", "J3", status );
+
+  palIntin ( s, &i, &n, &j );
+  viv ( i, 23, "palIntin", "I4", status );
+  viv ( n, 2000, "palIntin", "V4", status );
+  viv ( j, 0, "palIntin", "J4", status );
+
+  palIntin ( s, &i, &n, &j );
+  viv ( i, 29, "palIntin", "I5", status );
+  viv ( n, 2000, "palIntin", "V5", status );
+  viv ( j, 1, "palIntin", "J5", status ); /* Note that strtol does not care about a + */
+
+}
+
+
+/* Moon */
+
+static void t_moon ( int *status ) {
+  double pv[6];
+
+  double expected1[] = {
+    0.00229161514616454,
+    0.000973912029208393,
+    0.000669931538978146,
+    -3.44709700068209e-09,
+    5.44477533462392e-09,
+    2.11785724844417e-09
+  };
+
+  /* SLA test only include slaMoon so we use the
+     example from SUN/67 */
+  palDmoon( 48634.4687174074, pv );
+  vvec( 6, pv, expected1, "palDmoon", status );
+}
+
+/* Nutation */
+
+static void t_nut( int *status ) {
+  double dpsi, deps, eps0;
+
+  double expected[3][3] = {
+    {  9.999999969492166e-1, 7.166577986249302e-5,  3.107382973077677e-5 },
+    { -7.166503970900504e-5, 9.999999971483732e-1, -2.381965032461830e-5 },
+    { -3.107553669598237e-5, 2.381742334472628e-5,  9.999999992335206818e-1 }
+  };
+
+  double rmatn[3][3];
+
+  /* SLA tests with low precision */
+  palNut( 46012.32, rmatn );
+  vrmat( rmatn, expected, "palNut", 1.0e-3, status );
+
+  /* Use the SOFA/ERFA tests */
+  palNutc( 54388.0, &dpsi, &deps, &eps0 );
+  vvd( eps0, 0.4090749229387258204, 1e-14,
+      "palNutc", "eps0", status);
+
+  palNutc( 53736.0, &dpsi, &deps, &eps0 );
+   vvd(dpsi, -0.9630912025820308797e-5, 1e-13,
+       "palNutc", "dpsi", status);
+   vvd(deps,  0.4063238496887249798e-4, 1e-13,
+       "palNutc", "deps", status);
+}
+
+/* palPrebn */
+
+static void t_prebn( int *status ) {
+  double rmatp[3][3];
+  double prebn_expected[3][3] = {
+    { 9.999257613786738e-1, -1.117444640880939e-2, -4.858341150654265e-3 },
+    { 1.117444639746558e-2,  9.999375635561940e-1, -2.714797892626396e-5 },
+    { 4.858341176745641e-3, -2.714330927085065e-5,  9.999881978224798e-1 },
+  };
+
+  palPrebn ( 1925., 1975., rmatp );
+  vrmat( rmatp, prebn_expected, "palPrebn", 1.0e-12, status );
+}
+
+/* Range */
+
+static void t_range( int *status ) {
+  vvd ( palDrange ( -4 ), 2.283185307179586,
+        1e-12, "palDrange", " ", status );
+}
+
+static void t_ranorm( int *status ) {
+  vvd ( palDranrm ( -0.1 ), 6.183185307179587,
+        1e-12, "palDranrm", "2", status );
+}
+
+/* Separation routines */
+
+static void t_sep( int *status ) {
+  double d1[3] = { 1.0, 0.1, 0.2 };
+  double d2[3] = { -3.0, 1e-3, 0.2 };
+  double ad1, bd1, ad2, bd2;
+
+  palDcc2s( d1, &ad1, &bd1 );
+  palDcc2s( d2, &ad2, &bd2 );
+
+  vvd ( palDsep ( ad1, bd1, ad2, bd2 ),
+        2.8603919190246608, 1e-7, "palDsep", " ", status );
+  vvd ( palDsepv ( d1, d2 ),
+        2.8603919190246608, 1e-7, "palDsepv", " ", status );
+
+}
+
+/* Supergalactic */
+
+static void t_supgal( int *status ) {
+  double dl, db;
+
+  palSupgal ( 6.1, -1.4, &dl, &db );
+
+  vvd ( dl, 3.798775860769474, 1e-12, "palSupgal",
+	"DL", status );
+  vvd ( db, -0.1397070490669407, 1e-12, "palSupgal",
+	"DB", status );
+
+}
+
+/* Test spherical tangent-plane-projection routines */
+static void t_tp( int *status ) {
+
+  int j;
+  double dr0, dd0, dr1, dd1, dx, dy, dr2, dd2, dr01,
+    dd01, dr02, dd02;
+
+  dr0 = 3.1;
+  dd0 = -0.9;
+  dr1 = dr0 + 0.2;
+  dd1 = dd0 - 0.1;
+  palDs2tp( dr1, dd1, dr0, dd0, &dx, &dy, &j );
+  vvd( dx, 0.1086112301590404, 1e-12, "palDs2tp",
+       "x", status );
+  vvd( dy, -0.1095506200711452, 1e-12, "palDs2tp",
+       "y", status );
+  viv( j, 0, "palDs2tp", "j", status );
+
+  palDtp2s( dx, dy, dr0, dd0, &dr2, &dd2 );
+  vvd( dr2 - dr1, 0., 1e-12, "palDtp2s", "r", status );
+  vvd( dd2 - dd1, 0., 1e-12, "palDtp2s", "d", status );
+
+  palDtps2c( dx, dy, dr2, dd2, &dr01, &dd01, &dr02, &dd02, &j );
+  vvd( dr01, 3.1, 1e-12, "palDtps2c", "r1", status);
+  vvd( dd01, -0.9, 1e-12, "palDtps2c", "d1", status);
+  vvd( dr02, 0.3584073464102072, 1e-12, "palDtps2c",
+       "r2", status);
+  vvd( dd02, -2.023361658234722, 1e-12, "palDtps2c",
+       "d2", status );
+  viv( j, 1, "palDtps2c", "n", status );
+
+}
+
+/* Test all the 3-vector and 3x3 matrix routines. */
+
+static void t_vecmat( int * status ) {
+  int i;
+
+  /* palDav2m */
+  double drm1[3][3];
+  double dav[3] = { -0.123, 0.0987, 0.0654 };
+  double dav2m_expected[3][3] = {
+    {  0.9930075842721269,  0.05902743090199868, -0.1022335560329612 },
+    { -0.07113807138648245, 0.9903204657727545,  -0.1191836812279541 },
+    {  0.09420887631983825, 0.1256229973879967,   0.9875948309655174 },
+  };
+
+  /* palDeuler */
+  double drm2[3][3];
+  double deuler_expected[3][3] = {
+    { -0.1681574770810878,  0.1981362273264315,  0.9656423242187410 },
+    { -0.2285369373983370,  0.9450659587140423, -0.2337117924378156 },
+    { -0.9589024617479674, -0.2599853247796050, -0.1136384607117296 } };
+
+  /* palDmxm */
+  double drm[3][3];
+  double dmxm_expected[3][3] = {
+    { -0.09010460088585805,  0.3075993402463796,  0.9472400998581048 },
+    { -0.3161868071070688,   0.8930686362478707, -0.3200848543149236 },
+    { -0.9444083141897035,  -0.3283459407855694,  0.01678926022795169 },
+  };
+
+  /* palDcs2c et al */
+  double dv1[3];
+  double dv2[3];
+  double dv3[3];
+  double dv4[3];
+  double dv5[3];
+  double dv6[3];
+  double dv7[3];
+  double dvm;
+
+  /* palDav2m */
+  palDav2m( dav, drm1 );
+  vrmat( drm1, dav2m_expected, "palDav2m", 1.0e-12, status );
+
+  /* Test palDeuler */
+  palDeuler( "YZY", 2.345, -0.333, 2.222, drm2 );
+  vrmat( drm2, deuler_expected, "palDeuler", 1.0e-12, status );
+
+  /* palDmxm */
+  palDmxm( drm2, drm1, drm );
+  vrmat( drm, dmxm_expected, "palDmxm", 1.0e-12, status );
+
+  /* palDcs2c */
+  palDcs2c( 3.0123, -0.999, dv1 );
+  vvd ( dv1[0], -0.5366267667260525, 1e-12,
+        "palDcs2c", "x", status );
+  vvd ( dv1[1], 0.06977111097651444, 1e-12,
+        "palDcs2c", "y", status );
+  vvd ( dv1[2], -0.8409302618566215, 1e-12,
+        "palDcs2c", "z", status );
+
+  /* palDmxv */
+  palDmxv( drm1, dv1, dv2 );
+  palDmxv( drm2, dv2, dv3 );
+  vvd ( dv3[0], -0.7267487768696160, 1e-12,
+        "palDmxv", "x", status );
+  vvd ( dv3[1], 0.5011537352639822, 1e-12,
+        "palDmxv", "y", status );
+  vvd ( dv3[2], 0.4697671220397141, 1e-12,
+        "palDmxv", "z", status );
+
+  /* palDimxv */
+  palDimxv( drm, dv3, dv4 );
+  vvd ( dv4[0], -0.5366267667260526, 1e-12,
+        "palDimxv", "X", status );
+  vvd ( dv4[1], 0.06977111097651445, 1e-12,
+        "palDimxv", "Y", status );
+  vvd ( dv4[2], -0.8409302618566215, 1e-12,
+        "palDimxv", "Z", status );
+
+  /* palDm2av */
+  palDm2av( drm, dv5 );
+  vvd ( dv5[0], 0.006889040510209034, 1e-12,
+        "palDm2av", "X", status );
+  vvd ( dv5[1], -1.577473205461961, 1e-12,
+        "palDm2av", "Y", status );
+  vvd ( dv5[2], 0.5201843672856759, 1e-12,
+        "palDm2av", "Z", status );
+
+  for (i=0; i<3; i++) {
+    dv5[i] *= 1000.0;
+  }
+
+  /* palDvn */
+  palDvn( dv5, dv6, &dvm );
+  vvd ( dv6[0], 0.004147420704640065, 1e-12,
+        "palDvn", "X", status );
+  vvd ( dv6[1], -0.9496888606842218, 1e-12,
+        "palDvn", "Y", status );
+  vvd ( dv6[2], 0.3131674740355448, 1e-12,
+        "palDvn", "Z", status );
+  vvd ( dvm, 1661.042127339937, 1e-9, "palDvn",
+        "M", status );
+
+  vvd ( palDvdv ( dv6, dv1 ), -0.3318384698006295,
+        1e-12, "palDvn", " ", status );
+
+  /* palDvxv */
+  palDvxv( dv6, dv1, dv7 );
+  vvd ( dv7[0], 0.7767720597123304, 1e-12,
+        "palDvxv", "X", status );
+  vvd ( dv7[1], -0.1645663574562769, 1e-12,
+        "palDvxv", "Y", status );
+  vvd ( dv7[2], -0.5093390925544726, 1e-12,
+        "palDvxv", "Z", status );
+
+}
+
+static void t_ecleq( int *status ) {
+  double dr;
+  double dd;
+  palEcleq( 1.234, -0.123, 43210.0, &dr, &dd );
+  vvd( dr, 1.229910118208851, 1e-5, "palEcleq",
+       "RA", status );
+  vvd( dd, 0.2638461400411088, 1e-5, "palEcleq",
+       "Dec", status );
+}
+
+static void t_ecmat( int *status ) {
+   double rmat[3][3];
+   double expected[3][3] = {
+     { 1.0,                    0.0,                   0.0 },
+     { 0.0, 0.91749307789883549624, 0.3977517467060596168 },
+     { 0.0, -0.3977517467060596168, 0.91749307789883549624 } };
+
+   palEcmat( 55966.46, rmat );
+   vrmat( rmat, expected, "palEcmat", 1.0e-12, status );
+}
+
+static void t_eqecl ( int *status ) {
+  double dl, db;
+  palEqecl ( 0.789, -0.123, 46555, &dl, &db );
+
+  /* Slight changes from SLA for 2006 precession/nutation */
+  vvd ( dl, 0.7036566430349022, 1e-6, "palEqecl",
+        "L", status );
+  vvd ( db, -0.4036047164116848, 1e-6, "palEqecl",
+        "B", status );
+}
+
+static void t_prec( int *status ) {
+   double rmat[3][3];
+   double expected[3][3] = {
+     { 0.9999856154510, -0.0049192906204,    -0.0021376320580 },
+     {  0.0049192906805,  0.9999879002027,    -5.2297405698747e-06 },
+     { 0.0021376319197, -5.2859681191735e-06, 0.9999977152483 } };
+
+   palPrec( 1990.0, 2012.0, rmat );
+   vrmat( rmat, expected, "palPrec", 1.0e-12, status );
+}
+
+static void t_preces( int *status ) {
+  double ra;
+  double dc;
+  ra = 6.28;
+  dc = -1.123;
+  palPreces ( "FK4", 1925, 1950, &ra, &dc );
+  vvd ( ra,  0.002403604864728447, 1e-12, "palPreces",
+        "R", status );
+  vvd ( dc, -1.120570643322045, 1e-12, "palPreces",
+        "D", status );
+
+  /* This is the SLA test but PAL now uses the IAU 2006
+     precession model so we need to loosen the comparison */
+  ra = 0.0123;
+  dc = 1.0987;
+  palPreces ( "FK5", 2050, 1990, &ra, &dc );
+  vvd ( ra, 6.282003602708382, 1e-6, "palPreces",
+        "R", status );
+  vvd ( dc, 1.092870326188383, 1e-6, "palPreces",
+        "D", status );
+
+}
+
+static void t_evp( int *status ) {
+   double dvb[3],dpb[3],dvh[3],dph[3];
+   double vbex[3] = { 1.6957348127008098514e-07,
+                     -9.1093446116039685966e-08,
+                     -3.9528532243991863036e-08 };
+   double pbex[3] = {-0.49771075259730546136,
+                     -0.80273812396332311359,
+                     -0.34851593942866060383  };
+   double vhex[3] = { 1.6964379181455713805e-07,
+                     -9.1147224045727438391e-08,
+                     -3.9553158272334222497e-08 };
+   double phex[3] = { -0.50169124421419830639,
+                      -0.80650980174901798492,
+                      -0.34997162028527262212 };
+
+   double vbex2[3] = {
+     -0.0109187426811683,
+     -0.0124652546173285,
+     -0.0054047731809662
+   };
+   double pbex2[3] = {
+     -0.7714104440491060,
+     +0.5598412061824225,
+     +0.2425996277722475
+   };
+   double vhex2[3] = {
+     -0.0109189182414732,
+     -0.0124718726844084,
+     -0.0054075694180650
+   };
+   double phex2[3] = {
+     -0.7757238809297653,
+     +0.5598052241363390,
+     +0.2426998466481708
+   };
+
+   palEvp( 2010.0, 2012.0, dvb, dpb, dvh, dph );
+
+   vvec( 3, dvb, vbex, "palEvp", status );
+   vvec( 3, dpb, pbex, "palEvp", status );
+   vvec( 3, dvh, vhex, "palEvp", status );
+   vvec( 3, dph, phex, "palEvp", status );
+
+   palEpv ( 53411.52501161, dph, dvh, dpb, dvb );
+
+   vvec( 3, dvb, vbex2, "palEpv", status );
+   vvec( 3, dpb, pbex2, "palEpv", status );
+   vvec( 3, dvh, vhex2, "palEpv", status );
+   vvec( 3, dph, phex2, "palEpv", status );
+
+}
+
+static void t_map( int *status ) {
+  double ra, da;
+  palMap ( 6.123, -0.999, 1.23e-5, -0.987e-5,
+           0.123, 32.1, 1999, 43210.9, &ra, &da );
+
+  /* These are the SLA tests but and they agree to 0.1 arcsec
+     with PAL/SOFA/ERFA. We expect a slight difference from the change
+     to nutation models. */
+  vvd ( ra, 6.117130429775647, 1e-6, "palMap",
+          "RA", status );
+  vvd ( da, -1.000880769038632, 1e-8, "palMap",
+        "DA", status );
+}
+
+static void t_mappa( int *status ) {
+   double amprms[21];
+   double expected[21] = {1.9986310746064646082,
+                          -0.1728200754134739392,
+                          0.88745394651412767839,
+                          0.38472374350184274094,
+                          -0.17245634725219796679,
+                          0.90374808622520386159,
+                          0.3917884696321610738,
+                          2.0075929387510784968e-08,
+                          -9.9464149073251757597e-05,
+                          -1.6125306981057062306e-05,
+                          -6.9897255793245634435e-06,
+                          0.99999999489900059935,
+                          0.99999983777998024959,
+                          -0.00052248206600935195865,
+                          -0.00022683144398381763045,
+                          0.00052248547063364874764,
+                          0.99999986339269864022,
+                          1.4950491424992534218e-05,
+                          0.00022682360163333854623,
+                          -1.5069005133483779417e-05,
+                          0.99999997416198904698};
+
+   palMappa( 2010.0, 55927.0, amprms );
+   vvec( 21, amprms, expected, "palMappa", status );
+}
+
+static void t_mapqkz( int *status ) {
+   double amprms[21],  ra, da;
+   palMappa( 2010.0, 55927.0, amprms );
+   palMapqkz( 1.234, -0.567, amprms, &ra, &da );
+   vvd( ra, 1.2344879748414849807, 1.0E-12, "palMapqkz", "ra", status );
+   vvd( da, -0.56697099554368701746, 1.0E-12, "palMapqkz", "da", status );
+
+   /* Try the same with palMapqk and zero parallax and proper motion */
+   palMapqk( 1.234, -0.567, 0., 0., 0., 0., amprms, &ra, &da );
+   vvd( ra, 1.2344879748414849807, 1.0E-7, "palMapqkz", "ra", status );
+   vvd( da, -0.56697099554368701746, 1.0E-7, "palMapqkz", "da", status );
+
+}
+
+static void t_ampqk( int *status ) {
+   double amprms[21],  rm, dm;
+   palMappa( 2010.0, 55927.0, amprms );
+   palAmpqk( 1.234, -0.567, amprms, &rm, &dm );
+   vvd( rm, 1.2335120411026936349, 1.0E-12, "palAmpqk", "rm", status );
+   vvd( dm, -0.56702908706930343907, 1.0E-12, "palAmpqk", "dm", status );
+}
+
+static void t_fk45z( int *status ) {
+   double r2000, d2000;
+   palFk45z( 1.2, -0.3, 1960.0, &r2000, &d2000 );
+   vvd( r2000, 1.2097812228966762227, 1.0E-12, "palFk45z", "r2000", status );
+   vvd( d2000, -0.29826111711331398935, 1.0E-12, "palFk45z", "d2000", status );
+}
+
+static void t_fk54z( int *status ) {
+   double r1950, d1950, dr1950, dd1950;
+   palFk54z( 1.2, -0.3, 1960.0, &r1950, &d1950, &dr1950, &dd1950 );
+   vvd( r1950, 1.1902221805755279771, 1.0E-12, "palFk54z", "r1950", status );
+   vvd( d1950, -0.30178317645793828472, 1.0E-12, "palFk54z", "d1950", status );
+   vvd( dr1950, -1.7830874775952945507e-08, 1.0E-12, "palFk54z", "dr1950", status );
+   vvd( dd1950, 7.196059425334821089e-09, 1.0E-12, "palFk54z", "dd1950", status );
+}
+
+static void t_fk524( int *status ) {
+  double r1950, d1950, dr1950, dd1950, p1950, v1950;
+  palFk524(4.567, -1.23, -3e-5, 8e-6, 0.29,
+           -35.0, &r1950, &d1950, &dr1950, &dd1950, &p1950, &v1950);
+  vvd(r1950, 4.543778603272084, 1e-12, "palFk524", "r", status);
+  vvd(d1950, -1.229642790187574, 1e-12, "palFk524", "d", status);
+  vvd(dr1950, -2.957873121769244e-5, 1e-17, "palFk524", "dr", status);
+  vvd(dd1950, 8.117725309659079e-6, 1e-17, "palFk524", "dd", status);
+  vvd(p1950, 0.2898494999992917, 1e-12, "palFk524", "p", status);
+  vvd(v1950, -35.026862824252680, 1e-11, "palFk524", "v", status);
+}
+
+static void t_flotin( int * status ) {
+
+  int j;
+  const char * s = "  12.345, , -0 1E3-4 2000  E     ";
+  /*                123456789012345678901234567890123 */
+  int i = 1;
+  double dv = 0.0;
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 10, "palDfltin", "I1", status );
+  vvd ( dv, 12.345, 1e-12, "palDfltin", "V1", status );
+  viv ( j, 0, "palDfltin", "J1", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 12, "palDfltin", "I2", status );
+  vvd ( dv, 12.345, 1e-12, "palDfltin", "V2", status );
+  viv ( j, 1, "palDfltin", "J2", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 16, "palDfltin", "I3", status );
+  vvd ( dv, 0, 0, "palDfltin", "V3", status );
+  viv ( j, -1, "palDfltin", "J3", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 19, "palDfltin", "I4", status );
+  vvd ( dv, 1000, 0, "palDfltin", "V4", status );
+  viv ( j, 0, "palDfltin", "J4", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 22, "palDfltin", "I5", status );
+  vvd ( dv, -4, 0, "palDfltin", "V5", status );
+  viv ( j, -1, "palDfltin", "J5", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 28, "palDfltin", "I6", status );
+  vvd ( dv, 2000, 0, "palDfltin", "V6", status );
+  viv ( j, 0, "palDfltin", "J6", status );
+
+  palDfltin ( s, &i, &dv, &j );
+  viv ( i, 34, "palDfltin", "I7", status );
+  vvd ( dv, 2000, 0, "palDfltin", "V7", status );
+  viv ( j, 1, "palDfltin", "J7", status ); /* differs from slaDfltin */
+
+  /* Now test overflow and underflow */
+  i = 1;
+  palDfltin( " 1D600 ", &i, &dv, &j );
+  viv ( i, 8, "palDfltin", "I8", status );
+  vvd ( dv, HUGE_VAL, 0, "palDfltin", "V8", status );
+  viv ( j, 2, "palDfltin", "J8", status );
+
+}
+
+static void t_obs( int * status ) {
+
+  char shortname[11];
+  char longname[41];
+  double w, p, h;
+  int lstat;
+
+  lstat = palObs( 0, "MMT", shortname, sizeof(shortname),
+                  longname, sizeof(longname), &w, &p, &h );
+  vcs ( shortname, "MMT", "palObs", "1/C", status );
+  vcs ( longname, "MMT 6.5m, Mt Hopkins", "palObs", "1/NAME",
+        status );
+  vvd ( w, 1.935300584055477, 1e-8, "palObs",
+        "1/W", status );
+  vvd ( p, 0.5530735081550342238, 1e-10, "palObs",
+        "1/P", status );
+  vvd ( h, 2608, 1e-10, "palObs",
+        "1/H", status );
+  viv( lstat, 0, "palObs", "retval", status );
+
+  lstat = palObs ( 61, NULL, shortname, sizeof(shortname),
+                   longname, sizeof(longname), &w, &p, &h );
+  vcs ( shortname, "KECK1", "palObs", "2/C", status );
+  vcs ( longname, "Keck 10m Telescope #1", "palObs",
+        "2/NAME", status );
+  vvd ( w, 2.713545757918895, 1e-8, "palObs",
+        "2/W", status );
+  vvd ( p, 0.3460280563536619, 1e-8, "palObs",
+        "2/P", status );
+  vvd ( h, 4160, 1e-10, "palObs",
+        "2/H", status );
+  viv( lstat, 0, "palObs", "retval", status );
+
+  lstat = palObs ( 83, NULL, shortname, sizeof(shortname),
+                   longname, sizeof(longname), &w, &p, &h );
+  vcs ( shortname, "MAGELLAN2", "palObs", "3/C", status );
+  vcs ( longname, "Magellan 2, 6.5m, Las Campanas",
+        "palObs", "3/NAME", status );
+  vvd ( w, 1.233819305534497, 1e-8, "palObs",
+        "3/W", status );
+  vvd ( p, -0.506389344359954, 1e-8, "palObs",
+        "3/P", status );
+  vvd ( h, 2408, 1e-10, "palObs",
+        "3/H", status );
+  viv( lstat, 0, "palObs", "retval", status );
+
+  /* the first argument here should be 1 greater than the number of items
+   * in const struct telData defined in palObs.c
+   */
+  lstat = palObs ( 86, NULL, shortname, sizeof(shortname),
+                   longname, sizeof(longname), &w, &p, &h );
+  vcs ( longname, "?", "palObs", "4/NAME", status );
+  viv( lstat, -1, "palObs", "retval", status );
+
+  lstat = palObs ( 0, "MISSING", shortname, sizeof(shortname),
+                   longname, sizeof(longname), &w, &p, &h );
+  vcs ( longname, "?", "palObs", "5/NAME", status );
+  viv( lstat, -1, "palObs", "retval", status );
+
+  lstat = palObs( 0, "mmt", shortname, sizeof(shortname),
+                  longname, sizeof(longname), &w, &p, &h );
+  vcs ( shortname, "MMT", "palObs", "6/C", status );
+  vcs ( longname, "MMT 6.5m, Mt Hopkins", "palObs", "6/NAME",
+        status );
+  vvd ( w, 1.935300584055477, 1e-8, "palObs",
+        "6/W", status );
+  vvd ( p, 0.5530735081550342238, 1e-10, "palObs",
+        "6/P", status );
+  vvd ( h, 2608, 1e-10, "palObs",
+        "6/H", status );
+  viv( lstat, 0, "palObs", "retval", status );
+
+}
+
+static void t_pa( int *status ) {
+  vvd ( palPa ( -1.567, 1.5123, 0.987 ),
+        -1.486288540423851, 1e-12, "palPa", " ", status );
+  vvd ( palPa ( 0, 0.789, 0.789 ),
+        0, 0, "palPa", "zenith", status );
+}
+
+static void t_pcd( int *status ) {
+  double disco, x, y;
+  disco = 178.585;
+  x = 0.0123;
+  y = -0.00987;
+
+  palPcd ( disco, &x, &y );
+  vvd ( x, 0.01284630845735895, 1e-14, "palPcd", "x", status );
+  vvd ( y, -0.01030837922553926, 1e-14, "palPcd", "y", status );
+
+  palUnpcd ( disco, &x, &y );
+  vvd ( x, 0.0123, 1e-14, "palUnpcd", "x", status );
+  vvd ( y, -0.00987, 1e-14, "palUnpcd", "y,", status );
+
+  /* Now negative disco round trip */
+  disco = -0.3333333;
+  x = 0.0123;
+  y = -0.00987;
+  palPcd ( disco, &x, &y );
+  palUnpcd ( disco, &x, &y );
+  vvd ( x, 0.0123, 1e-14, "palUnpcd", "x", status );
+  vvd ( y, -0.00987, 1e-14, "palUnpcd", "y,", status );
+}
+
+static void t_planet( int * status ) {
+  int j;
+  double pv[6];
+  double u[13];
+  double expected1[6] = { 0., 0., 0., 0., 0., 0. };
+  double expectedue1[13] = {
+     1.000878908362435284,  -0.3336263027874777288,  50000.,
+     2.840425801310305210,   0.1264380368035014224, -0.2287711835229143197,
+    -0.01301062595106185195, 0.5657102158104651697,  0.2189745287281794885,
+     2.852427310959998500,  -0.01552349065435120900,
+     50000., 0.0
+  };
+  double expectedue2[13] = {
+    1.00006, -4.856142884511782, 50000., 0.3, -0.2,
+    0.1,  -0.4520378601821727,  0.4018114312730424,
+    -.3515850023639121, 0.3741657386773941,
+    -0.2511321445456515, 50000., 0.
+  };
+  double expectedue3[13] = {
+    1.000000000000000,
+    -0.3329769417028020949,
+    50100.,
+    2.638884303608524597,
+    1.070994304747824305,
+    0.1544112080167568589,
+    -0.2188240619161439344,
+    0.5207557453451906385,
+    0.2217782439275216936,
+    2.852118859689216658,
+    0.01452010174371893229,
+    50100.,
+    0.
+  };
+  double expectedpv[6] = {
+    0.07944764084631667011, -0.04118141077419014775,
+    0.002915180702063625400, -0.6890132370721108608e-6,
+    0.4326690733487621457e-6, -0.1763249096254134306e-6,
+  };
+  double expectedpv2[6] = {
+    1.947628959288897677,
+    -1.013736058752235271,
+    -0.3536409947732733647,
+    2.742247411571786194e-8,
+    1.170467244079075911e-7,
+    3.709878268217564005e-8
+  };
+
+  double ra,dec,diam, r;
+  int jform;
+  double epoch, orbinc, anode, perih, aorq, e, aorl,
+    dm;
+
+  /* palEl2ue */
+  palEl2ue ( 50000, 1, 49000, 0.1, 2, 0.2,
+             3, 0.05, 3, 0.003312, u, &j );
+  vvec( 13, u, expectedue1, "palEl2ue", status );
+  viv ( j, 0, "palEl2ue", "J", status );
+
+  /* palPertel */
+  palPertel ( 2, 43000., 43200., 43000.,
+              0.2, 3, 4, 5, 0.02, 6,
+              &epoch, &orbinc, &anode, &perih, &aorq, &e, &aorl, &j );
+  vvd ( epoch, 43200., 1e-10, "palPertel",
+        "EPOCH", status );
+  vvd ( orbinc, 0.1995661466545422381, 1e-7, "palPertel",
+        "ORBINC", status );
+  vvd ( anode, 2.998052737821591215, 1e-7, "palPertel",
+        "ANODE", status );
+  vvd ( perih, 4.009516448441143636, 1e-6, "palPertel",
+        "PERIH", status );
+  vvd ( aorq, 5.014216294790922323, 1e-7, "palPertel",
+        "AORQ", status );
+  vvd ( e, 0.02281386258309823607, 1e-7, "palPertel",
+        "E", status );
+  vvd ( aorl, 0.01735248648779583748, 1e-6, "palPertel",
+        "AORL", status );
+  viv ( j, 0, "palPertel", "J", status );
+
+  /* palPertue */
+  palPertue ( 50100, u, &j );
+  vvec( 13, u, expectedue3, "palPertue", status );
+  viv ( j, 0, "palPertue", "J", status );
+
+  /* palPlanel */
+  palPlanel ( 50600, 2, 50500, 0.1, 3, 5,
+	      2, 0.3, 4, 0, pv, &j );
+  vvec( 6, pv, expectedpv2, "palPlanel", status );
+  viv ( j, 0, "palPlanel", "J", status );
+
+  /* palPlanet */
+
+  palPlanet( 1e6, 0, pv, &j );
+  vvec( 6, pv, expected1, "palPlanet 1", status );
+  viv ( j, -1, "palPlanet", "J 1", status );
+
+  palPlanet( 1e6, 9, pv, &j);
+  viv ( j, -1, "palPlanet", "J 2", status );
+
+  palPlanet ( -320000, 3, pv, &j );
+  vvd ( pv[0], 0.9308038666827242603, 1e-11, "palPlanet",
+        "pv[0] 3", status );
+  vvd ( pv[1], 0.3258319040252137618, 1e-11, "palPlanet",
+        "pv[1] 3", status );
+  vvd ( pv[2], 0.1422794544477122021, 1e-11, "palPlanet",
+        "pv[2] 3", status );
+  vvd ( pv[3], -7.441503423889371696e-8, 1e-17, "palPlanet",
+        "pv[3] 3", status );
+  vvd ( pv[4], 1.699734557528650689e-7, 1e-17, "palPlanet",
+        "pv[4] 3", status );
+  vvd ( pv[5], 7.415505123001430864e-8, 1e-17, "palPlanet",
+        "pv[5] 3", status );
+  viv ( j, 1, "palPlanet", "J 3", status );
+
+  palPlanet ( 43999.9, 1, pv, &j );
+  vvd ( pv[0], 0.2945293959257422246, 1e-11, "palPlanet",
+        "pv[0] 4", status );
+  vvd ( pv[1], -0.2452204176601052181, 1e-11, "palPlanet",
+        "pv[1] 4", status );
+  vvd ( pv[2], -0.1615427700571978643, 1e-11, "palPlanet",
+        "pv[2] 4", status );
+  vvd ( pv[3], 1.636421147459047057e-7, 1e-18, "palPlanet",
+        "pv[3] 4", status );
+  vvd ( pv[4], 2.252949422574889753e-7, 1e-18, "palPlanet",
+        "pv[4] 4", status );
+  vvd ( pv[5], 1.033542799062371839e-7, 1e-18, "palPlanet",
+        "pv[5] 4", status );
+  viv ( j, 0, "palPlanet", "J 4", status );
+
+  /* palPlante test would go here */
+
+  palPlante ( 50600., -1.23, 0.456, 2, 50500.,
+	      0.1, 3., 5., 2., 0.3, 4.,
+	      0., &ra, &dec, &r, &j );
+  vvd ( ra, 6.222958101333794007, 1e-6, "palPlante",
+	"RA", status );
+  vvd ( dec, 0.01142220305739771601, 1e-6, "palPlante",
+	"DEC", status );
+  vvd ( r, 2.288902494080167624, 1e-8, "palPlante",
+	"R", status );
+  viv ( j, 0, "palPlante", "J", status );
+
+  u[0] = 1.0005;
+  u[1] = -0.3;
+  u[2] = 55000.;
+  u[3] = 2.8;
+  u[4] = 0.1;
+  u[5] = -0.2;
+  u[6] = -0.01;
+  u[7] = 0.5;
+  u[8] = 0.22;
+  u[9] = 2.8;
+  u[10] = -0.015;
+  u[11] = 55001.;
+  u[12] = 0;
+
+  /* palPlantu */
+
+  palPlantu ( 55001., -1.23, 0.456, u, &ra, &dec, &r, &j );
+  vvd ( ra, 0.3531814831241686647, 1e-6, "palPlantu",
+	"RA", status );
+  vvd ( dec, 0.06940344580567131328, 1e-6, "palPlantu",
+	"DEC", status );
+  vvd ( r, 3.031687170873274464, 1e-8, "palPlantu",
+	"R", status );
+  viv ( j, 0, "palPlantu", "J", status );
+
+  /* palPv2el */
+
+  pv[0] = 0.3;
+  pv[1] = -0.2;
+  pv[2] = 0.1;
+  pv[3] = -0.9e-7;
+  pv[4] = 0.8e-7;
+  pv[5] = -0.7e-7;
+
+  palPv2el ( pv, 50000, 0.00006, 1,
+             &jform, &epoch, &orbinc, &anode, &perih,
+             &aorq, &e, &aorl, &dm, &j );
+  viv ( jform, 1, "palPv2el", "JFORM", status );
+  vvd ( epoch, 50000, 1e-10, "palPv2el",
+        "EPOCH", status );
+  vvd ( orbinc, 1.52099895268912, 1e-12, "palPv2el",
+        "ORBINC", status );
+  vvd ( anode, 2.720503180538650, 1e-12, "palPv2el",
+        "ANODE", status );
+  vvd ( perih, 2.194081512031836, 1e-12, "palPv2el",
+        "PERIH", status );
+  vvd ( aorq, 0.2059371035373771, 1e-12, "palPv2el",
+        "AORQ", status );
+  vvd ( e, 0.9866822985810528, 1e-12, "palPv2el",
+        "E", status );
+  vvd ( aorl, 0.2012758344836794, 1e-12, "palPv2el",
+        "AORL", status );
+  vvd ( dm, 0.1840740507951820, 1e-12, "palPv2el",
+        "DM", status );
+  viv ( j, 0, "palPv2el", "J", status );
+
+  /* palPv2ue */
+  palPv2ue ( pv, 50000., 0.00006, u, &j );
+  vvec( 13, u, expectedue2, "palPv2ue", status );
+  viv ( j, 0, "palPv2ue", "J", status );
+
+  /* Planets */
+  palRdplan ( 40999.9, 0, 0.1, -0.9, &ra, &dec, &diam );
+  vvd ( ra, 5.772270359389275837, 1e-6, "palRdplan",
+        "ra 0", status );
+  vvd ( dec, -0.2089207338795416192, 1e-7, "palRdplan",
+        "dec 0", status );
+  vvd ( diam, 9.415338935229717875e-3, 1e-10, "palRdplan",
+        "diam 0", status );
+  palRdplan ( 41999.9, 1, 1.1, -0.9, &ra, &dec, &diam );
+  vvd ( ra, 3.866363420052936653, 1e-6, "palRdplan",
+        "ra 1", status );
+  vvd ( dec, -0.2594430577550113130, 1e-7, "palRdplan",
+        "dec 1", status );
+  vvd ( diam, 4.638468996795023071e-5, 1e-14, "palRdplan",
+        "diam 1", status );
+  palRdplan ( 42999.9, 2, 2.1, 0.9, &ra, &dec, &diam );
+  vvd ( ra, 2.695383203184077378, 1e-6, "palRdplan",
+        "ra 2", status );
+  vvd ( dec, 0.2124044506294805126, 1e-7, "palRdplan",
+        "dec 2", status );
+  vvd ( diam, 4.892222838681000389e-5, 1e-14, "palRdplan",
+        "diam 2", status );
+  palRdplan ( 43999.9, 3, 3.1, 0.9, &ra, &dec, &diam );
+  vvd ( ra, 2.908326678461540165, 1e-7, "palRdplan",
+        "ra 3", status );
+  vvd ( dec, 0.08729783126905579385, 1e-7, "palRdplan",
+        "dec 3", status );
+  vvd ( diam, 8.581305866034962476e-3, 1e-7, "palRdplan",
+        "diam 3", status );
+  palRdplan ( 44999.9, 4, -0.1, 1.1, &ra, &dec, &diam );
+  vvd ( ra, 3.429840787472851721, 1e-6, "palRdplan",
+        "ra 4", status );
+  vvd ( dec, -0.06979851055261161013, 1e-7, "palRdplan",
+        "dec 4", status );
+  vvd ( diam, 4.540536678439300199e-5, 1e-14, "palRdplan",
+        "diam 4", status );
+  palRdplan ( 45999.9, 5, -1.1, 0.1, &ra, &dec, &diam );
+  vvd ( ra, 4.864669466449422548, 1e-6, "palRdplan",
+        "ra 5", status );
+  vvd ( dec, -0.4077714497908953354, 1e-7, "palRdplan",
+        "dec 5", status );
+  vvd ( diam, 1.727945579027815576e-4, 1e-14, "palRdplan",
+        "diam 5", status );
+  palRdplan ( 46999.9, 6, -2.1, -0.1, &ra, &dec, &diam );
+  vvd ( ra, 4.432929829176388766, 1e-6, "palRdplan",
+        "ra 6", status );
+  vvd ( dec, -0.3682820877854730530, 1e-7, "palRdplan",
+        "dec 6", status );
+  vvd ( diam, 8.670829016099083311e-5, 1e-14, "palRdplan",
+        "diam 6", status );
+  palRdplan ( 47999.9, 7, -3.1, -1.1, &ra, &dec, &diam );
+  vvd ( ra, 4.894972492286818487, 1e-6, "palRdplan",
+        "ra 7", status );
+  vvd ( dec, -0.4084068901053653125, 1e-7, "palRdplan",
+        "dec 7", status );
+  vvd ( diam, 1.793916783975974163e-5, 1e-14, "palRdplan",
+        "diam 7", status );
+  palRdplan ( 48999.9, 8, 0, 0, &ra, &dec, &diam );
+  vvd ( ra, 5.066050284760144000, 1e-6, "palRdplan",
+        "ra 8", status );
+  vvd ( dec, -0.3744690779683850609, 1e-7, "palRdplan",
+        "dec 8", status );
+  vvd ( diam, 1.062210086082700563e-5, 1e-14, "palRdplan",
+        "diam 8", status );
+
+  /* palUe2el */
+  palUe2el ( u, 1, &jform, &epoch, &orbinc, &anode, &perih,
+             &aorq, &e, &aorl, &dm, &j );
+  viv ( jform, 1, "palUe2el", "JFORM", status );
+  vvd ( epoch, 50000.00000000000, 1e-10, "palUe2el",
+        "EPOCH", status );
+  vvd ( orbinc, 1.520998952689120, 1e-12, "palUe2el",
+        "ORBINC", status );
+  vvd ( anode, 2.720503180538650, 1e-12, "palUe2el",
+        "ANODE", status );
+  vvd ( perih, 2.194081512031836, 1e-12, "palUe2el",
+        "PERIH", status );
+  vvd ( aorq, 0.2059371035373771, 1e-12, "palUe2el",
+        "AORQ", status );
+  vvd ( e, 0.9866822985810528, 1e-12, "palUe2el",
+        "E", status );
+  vvd ( aorl, 0.2012758344836794, 1e-12, "palUe2el",
+        "AORL", status );
+  viv ( j, 0, "palUe2el", "J", status );
+
+  /* palUe2pv */
+  palUe2pv( 50010., u, pv, &j );
+
+  /* Update the final two elements of the expecte UE array */
+  expectedue2[11] = 50010.;
+  expectedue2[12] = 0.7194308220038886856;
+
+  vvec( 13, u, expectedue2, "palUe2pv", status );
+  vvec( 6, pv, expectedpv, "palUe2pv", status );
+  viv ( j, 0, "palUe2pv", "J", status );
+
+}
+
+static void t_pm( int * status ) {
+  double ra2, dec2;
+  double ra1, dec1, pmr1, pmd1, px1, rv1;
+
+  ra1 = 5.43;
+  dec1 = -0.87;
+  pmr1 = -0.33e-5;
+  pmd1 = 0.77e-5;
+  px1 = 0.7;
+  rv1 = 50.3*365.2422/365.25;
+
+  palPm ( ra1, dec1, pmr1, pmd1, px1, rv1,
+          1899, 1943,
+          &ra2, &dec2 );
+  vvd ( ra2, 5.429855087793875, 1e-10, "palPm",
+        "R", status );
+  vvd ( dec2, -0.8696617307805072, 1e-10, "palPm",
+        "D", status );
+
+  /* SOFA/ERFA test */
+  ra1 =   0.01686756;
+  dec1 = -1.093989828;
+  pmr1 = -1.78323516e-5;
+  pmd1 =  2.336024047e-6;
+  px1 =   0.74723;
+  rv1 = -21.6;
+
+  palPm(ra1, dec1, pmr1, pmd1, px1, rv1,
+        palEpj(50083.0), palEpj(53736.0),
+        &ra2, &dec2);
+  vvd(ra2, 0.01668919069414242368, 1e-13,
+      "palPm", "ra", status);
+  vvd(dec2, -1.093966454217127879, 1e-13,
+      "palPm", "dec", status);
+
+
+}
+
+static void t_polmo( int *status ) {
+  double elong, phi, daz;
+
+  palPolmo( 0.7, -0.5, 1.0e-6, -2.0e-6, &elong, &phi, &daz );
+  vvd(elong, 0.7000004837322044, 1.0e-12, "palPolmo", "elong", status );
+  vvd(phi, -0.4999979467222241, 1.0e-12, "palPolmo", "phi", status );
+  vvd(daz, 1.008982781275728e-6, 1.0e-12, "palPolmo", "daz", status );
+}
+
+static void t_pvobs( int *status ) {
+   double pv[6];
+   double expected[6] = { -4.7683600138836167813e-06,
+                           1.0419056712717953176e-05,
+                           4.099831053320363277e-05,
+                          -7.5976959740661272483e-10,
+                          -3.4771429582640930371e-10,
+                           0.0};
+   palPvobs( 1.3, 10000.0, 2.0, pv );
+   vvec( 6, pv, expected, "palPvobs", status );
+}
+
+static void t_rv( int *status ) {
+  vvd ( palRverot ( -0.777, 5.67, -0.3, 3.19 ),
+        -0.1948098355075913, 1e-6,
+        "palRverot", " ", status );
+  vvd ( palRvgalc ( 1.11E0, -0.99E0 ),
+        158.9630759840254, 1e-3, "palRvgalc", " ", status );
+  vvd ( palRvlg ( 3.97E0, 1.09E0 ),
+        -197.818762175363, 1e-3, "palRvlg", " ", status );
+  vvd ( palRvlsrd ( 6.01E0, 0.1E0 ),
+        -4.082811335150567, 1e-4, "palRvlsrd", " ", status );
+  vvd ( palRvlsrk ( 6.01E0, 0.1E0 ),
+        -5.925180579830265, 1e-4, "palRvlsrk", " ", status );
+}
+
+static void t_rvgalc( int *status ) {
+   double rv;
+   rv = palRvgalc( 2.7, -1.0 );
+   vvd( rv, 213.98084425751144977, 1.0E-12, "palRvgalc", "rv", status );
+}
+
+static void t_rvlg( int *status ) {
+   double rv;
+   rv = palRvlg( 2.7, -1.0 );
+   vvd( rv, 291.79205281252404802, 1.0E-12, "palRvlg", "rv", status );
+}
+
+static void t_rvlsrd( int *status ) {
+   double rv;
+   rv = palRvlsrd( 2.7, -1.0 );
+   vvd( rv, 9.620674692097630043, 1.0E-12, "palRvlsrd", "rv", status );
+}
+
+static void t_rvlsrk( int *status ) {
+   double rv;
+   rv = palRvlsrk( 2.7, -1.0 );
+   vvd( rv, 12.556356851411955233, 1.0E-12, "palRvlsrk", "rv", status );
+}
+
+static void t_refco( int *status ) {
+  double phpa, tc, rh, wl, refa, refb;
+  phpa = 800.0;
+  tc = 10.0 + 273.15; /* SLA uses kelvin */
+  rh = 0.9;
+  wl = 0.4;
+  palRefcoq(tc, phpa, rh, wl, &refa, &refb);
+  vvd(refa, 0.2264949956241415009e-3, 1e-15,
+      "palRefcoq", "refa", status);
+  vvd(refb, -0.2598658261729343970e-6, 1e-18,
+      "palRefcoq", "refb", status);
+}
+
+static void t_ref( int *status ) {
+  double ref, refa, refb, refa2, refb2, vu[3], vr[3], zr;
+
+  palRefro( 1.4, 3456.7, 280, 678.9, 0.9, 0.55,
+            -0.3, 0.006, 1e-9, &ref );
+  vvd( ref, 0.00106715763018568, 1e-12, "palRefro",
+       "o", status );
+
+  palRefro( 1.4, 3456.7, 280, 678.9, 0.9, 1000,
+            -0.3, 0.006, 1e-9, &ref );
+  vvd( ref, 0.001296416185295403, 1e-12, "palRefro",
+       "r", status );
+
+  palRefcoq( 275.9, 709.3, 0.9, 101, &refa, &refb );
+  vvd( refa, 2.324736903790639e-4, 1e-12, "palRefcoq",
+       "a/r", status );
+  vvd( refb, -2.442884551059e-7, 1e-15, "palRefcoq",
+       "b/r", status );
+
+  palRefco( 2111.1, 275.9, 709.3, 0.9, 101,
+            -1.03, 0.0067, 1e-12, &refa, &refb );
+  vvd( refa, 2.324673985217244e-4, 1e-12, "palRefco",
+       "a/r", status );
+  vvd( refb, -2.265040682496e-7, 1e-15, "palRefco",
+       "b/r", status );
+
+  palRefcoq( 275.9, 709.3, 0.9, 0.77, &refa, &refb );
+  vvd( refa, 2.007406521596588e-4, 1e-12, "palRefcoq",
+       "a", status );
+  vvd( refb, -2.264210092590e-7, 1e-15, "palRefcoq",
+       "b", status );
+
+  palRefco( 2111.1, 275.9, 709.3, 0.9, 0.77,
+            -1.03, 0.0067, 1e-12, &refa, &refb );
+  vvd( refa, 2.007202720084551e-4, 1e-12, "palRefco",
+       "a", status );
+  vvd( refb, -2.223037748876e-7, 1e-15, "palRefco",
+       "b", status );
+
+  palAtmdsp ( 275.9, 709.3, 0.9, 0.77,
+              refa, refb, 0.5, &refa2, &refb2 );
+  vvd ( refa2, 2.034523658888048e-4, 1e-12, "palAtmdsp",
+        "a", status );
+  vvd ( refb2, -2.250855362179e-7, 1e-15, "palAtmdsp",
+        "b", status );
+
+  palDcs2c ( 0.345, 0.456, vu );
+  palRefv ( vu, refa, refb, vr );
+  vvd ( vr[0], 0.8447487047790478, 1e-12, "palRefv",
+        "x1", status );
+  vvd ( vr[1], 0.3035794890562339, 1e-12, "palRefv",
+        "y1", status );
+  vvd ( vr[2], 0.4407256738589851, 1e-12, "palRefv",
+        "z1", status );
+
+  palDcs2c ( 3.7, 0.03, vu );
+  palRefv ( vu, refa, refb, vr );
+  vvd ( vr[0], -0.8476187691681673, 1e-12, "palRefv",
+        "x2", status );
+  vvd ( vr[1], -0.5295354802804889, 1e-12, "palRefv",
+        "y2", status );
+  vvd ( vr[2], 0.0322914582168426, 1e-12, "palRefv",
+        "z2", status );
+
+  palRefz ( 0.567, refa, refb, &zr );
+    vvd ( zr, 0.566872285910534, 1e-12, "palRefz",
+          "hi el", status );
+
+  palRefz ( 1.55, refa, refb, &zr );
+  vvd ( zr, 1.545697350690958, 1e-12, "palRefz",
+        "lo el", status );
+
+
+
+}
+
+static void t_vers( int *status ) {
+  char verstring[32];
+
+  int ver = palVers( verstring, sizeof(verstring));
+  printf("PAL Version %s (%d)\n", verstring, ver);
+  if ( ver < 6000 ) {
+    *status = 1; /* palVers introduced at v0.6.0 */
+  }
+}
+
+/**********************************************************************/
+
+int main (void) {
+
+  /* Use the SLA and SOFA/ERFA conventions */
+  int status = 0; /* Unix and SAE convention */
+
+  t_addet(&status);
+  t_afin(&status);
+  t_altaz(&status);
+  t_ampqk(&status);
+  t_aop(&status);
+  t_airmas(&status);
+  t_amp(&status);
+  t_bear(&status);
+  t_caf2r(&status);
+  t_caldj(&status);
+  t_cc2s(&status);
+  t_cd2tf(&status);
+  t_cldj(&status);
+  t_cr2af(&status);
+  t_cr2tf(&status);
+  t_ctf2d(&status);
+  t_ctf2r(&status);
+  t_dat(&status);
+  t_djcal(&status);
+  t_dmat(&status);
+  t_epb(&status);
+  t_epb2d(&status);
+  t_epco(&status);
+  t_epj(&status);
+  t_epj2d(&status);
+  t_eqecl(&status);
+  t_eqeqx(&status);
+  t_etrms(&status);
+  t_eqgal(&status);
+  t_evp(&status);
+  t_fk45z(&status);
+  t_fk54z(&status);
+  t_fk524(&status);
+  t_flotin(&status);
+  t_galeq(&status);
+  t_galsup(&status);
+  t_ge50(&status);
+  t_geoc(&status);
+  t_gmst(&status);
+  t_fk52h(&status);
+  t_intin(&status);
+  t_prec(&status);
+  t_preces(&status);
+  t_ecleq(&status);
+  t_ecmat(&status);
+  t_e2h(&status);
+  t_map(&status);
+  t_mappa(&status);
+  t_mapqkz(&status);
+  t_moon(&status);
+  t_nut(&status);
+  t_obs(&status);
+  t_pa(&status);
+  t_pcd(&status);
+  t_planet(&status);
+  t_pm(&status);
+  t_polmo(&status);
+  t_prebn(&status);
+  t_pvobs(&status);
+  t_range(&status);
+  t_ranorm(&status);
+  t_ref(&status);
+  t_refco(&status);
+  t_rv(&status);
+  t_rvgalc(&status);
+  t_rvlg(&status);
+  t_rvlsrd(&status);
+  t_rvlsrk(&status);
+  t_sep(&status);
+  t_supgal(&status);
+  t_tp(&status);
+  t_vecmat(&status);
+  t_vers(&status);
+  return status;
+}
+
Index: trunk/FACT++/pal/palUe2el.c
===================================================================
--- trunk/FACT++/pal/palUe2el.c	(revision 18347)
+++ trunk/FACT++/pal/palUe2el.c	(revision 18347)
@@ -0,0 +1,234 @@
+/*
+*+
+*  Name:
+*     palUe2el
+
+*  Purpose:
+*     Universal elements to heliocentric osculating elements
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palUe2el ( const double u[13], int jformr,
+*                     int *jform, double *epoch, double *orbinc,
+*                     double *anode, double *perih, double *aorq, double *e,
+*                     double *aorl, double *dm, int *jstat );
+
+*  Arguments:
+*     u = const double [13] (Given)
+*        Universal orbital elements (Note 1)
+*            (0)  combined mass (M+m)
+*            (1)  total energy of the orbit (alpha)
+*            (2)  reference (osculating) epoch (t0)
+*          (3-5)  position at reference epoch (r0)
+*          (6-8)  velocity at reference epoch (v0)
+*            (9)  heliocentric distance at reference epoch
+*           (10)  r0.v0
+*           (11)  date (t)
+*           (12)  universal eccentric anomaly (psi) of date, approx
+*     jformr = int (Given)
+*        Requested element set (1-3; Note 3)
+*     jform = int * (Returned)
+*        Element set actually returned (1-3; Note 4)
+*     epoch = double * (Returned)
+*        Epoch of elements (TT MJD)
+*     orbinc = double * (Returned)
+*        inclination (radians)
+*     anode = double * (Returned)
+*        longitude of the ascending node (radians)
+*     perih = double * (Returned)
+*        longitude or argument of perihelion (radians)
+*     aorq = double * (Returned)
+*        mean distance or perihelion distance (AU)
+*     e = double * (Returned)
+*        eccentricity
+*     aorl = double * (Returned)
+*        mean anomaly or longitude (radians, JFORM=1,2 only)
+*     dm = double * (Returned)
+*        daily motion (radians, JFORM=1 only)
+*     jstat = int * (Returned)
+*        status:  0 = OK
+*                -1 = illegal combined mass
+*                -2 = illegal JFORMR
+*                -3 = position/velocity out of range
+
+*  Description:
+*     Transform universal elements into conventional heliocentric
+*     osculating elements.
+
+*  Authors:
+*     PTW: Patrick T. Wallace
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference 2).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - The universal elements are with respect to the mean equator and
+*       equinox of epoch J2000.  The orbital elements produced are with
+*       respect to the J2000 ecliptic and mean equinox.
+*     - Three different element-format options are supported:
+*
+*        Option JFORM=1, suitable for the major planets:
+*
+*        EPOCH  = epoch of elements (TT MJD)
+*        ORBINC = inclination i (radians)
+*        ANODE  = longitude of the ascending node, big omega (radians)
+*        PERIH  = longitude of perihelion, curly pi (radians)
+*        AORQ   = mean distance, a (AU)
+*        E      = eccentricity, e
+*        AORL   = mean longitude L (radians)
+*        DM     = daily motion (radians)
+*
+*        Option JFORM=2, suitable for minor planets:
+*
+*        EPOCH  = epoch of elements (TT MJD)
+*        ORBINC = inclination i (radians)
+*        ANODE  = longitude of the ascending node, big omega (radians)
+*        PERIH  = argument of perihelion, little omega (radians)
+*        AORQ   = mean distance, a (AU)
+*        E      = eccentricity, e
+*        AORL   = mean anomaly M (radians)
+*
+*        Option JFORM=3, suitable for comets:
+*
+*        EPOCH  = epoch of perihelion (TT MJD)
+*        ORBINC = inclination i (radians)
+*        ANODE  = longitude of the ascending node, big omega (radians)
+*        PERIH  = argument of perihelion, little omega (radians)
+*        AORQ   = perihelion distance, q (AU)
+*        E      = eccentricity, e
+*
+*     - It may not be possible to generate elements in the form
+*       requested through JFORMR.  The caller is notified of the form
+*       of elements actually returned by means of the JFORM argument:
+*
+*        JFORMR   JFORM     meaning
+*
+*          1        1       OK - elements are in the requested format
+*          1        2       never happens
+*          1        3       orbit not elliptical
+*
+*          2        1       never happens
+*          2        2       OK - elements are in the requested format
+*          2        3       orbit not elliptical
+*
+*          3        1       never happens
+*          3        2       never happens
+*          3        3       OK - elements are in the requested format
+*
+*     - The arguments returned for each value of JFORM (cf Note 6: JFORM
+*       may not be the same as JFORMR) are as follows:
+*
+*         JFORM         1              2              3
+*         EPOCH         t0             t0             T
+*         ORBINC        i              i              i
+*         ANODE         Omega          Omega          Omega
+*         PERIH         curly pi       omega          omega
+*         AORQ          a              a              q
+*         E             e              e              e
+*         AORL          L              M              -
+*         DM            n              -              -
+*
+*     where:
+*
+*         t0           is the epoch of the elements (MJD, TT)
+*         T              "    epoch of perihelion (MJD, TT)
+*         i              "    inclination (radians)
+*         Omega          "    longitude of the ascending node (radians)
+*         curly pi       "    longitude of perihelion (radians)
+*         omega          "    argument of perihelion (radians)
+*         a              "    mean distance (AU)
+*         q              "    perihelion distance (AU)
+*         e              "    eccentricity
+*         L              "    longitude (radians, 0-2pi)
+*         M              "    mean anomaly (radians, 0-2pi)
+*         n              "    daily motion (radians)
+*         -             means no value is set
+*
+*     - At very small inclinations, the longitude of the ascending node
+*       ANODE becomes indeterminate and under some circumstances may be
+*       set arbitrarily to zero.  Similarly, if the orbit is close to
+*       circular, the true anomaly becomes indeterminate and under some
+*       circumstances may be set arbitrarily to zero.  In such cases,
+*       the other elements are automatically adjusted to compensate,
+*       and so the elements remain a valid description of the orbit.
+
+*  See Also:
+*     - Sterne, Theodore E., "An Introduction to Celestial Mechanics",
+*       Interscience Publishers Inc., 1960.  Section 6.7, p199.
+*     - Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-09 (TIMJ):
+*        Initial version
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 1999 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include "pal.h"
+#include "palmac.h"
+
+void palUe2el ( const double u[], int jformr,
+                int *jform, double *epoch, double *orbinc,
+                double *anode, double *perih, double *aorq, double *e,
+                double *aorl, double *dm, int *jstat ) {
+
+  /*  Canonical days to seconds */
+  const double CD2S = PAL__GCON / PAL__SPD;
+
+  int i;
+  double pmass, date, pv[6];
+
+  /* Unpack the universal elements */
+  pmass = u[0] - 1.0;
+  date = u[2];
+  for (i=0; i<3; i++) {
+    pv[i] = u[i+3];
+    pv[i+3] = u[i+6] * CD2S;
+  }
+
+  /* Convert the position and velocity etc into conventional elements */
+  palPv2el( pv, date, pmass, jformr, jform, epoch, orbinc, anode,
+            perih, aorq, e, aorl, dm, jstat );
+}
Index: trunk/FACT++/pal/palUe2pv.c
===================================================================
--- trunk/FACT++/pal/palUe2pv.c	(revision 18347)
+++ trunk/FACT++/pal/palUe2pv.c	(revision 18347)
@@ -0,0 +1,263 @@
+/*
+*+
+*  Name:
+*     palUe2pv
+
+*  Purpose:
+*     Heliocentric position and velocity of a planet, asteroid or comet, from universal elements
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     void palUe2pv( double date, double u[13], double pv[6], int *jstat );
+
+*  Arguments:
+*     date = double (Given)
+*        TT Modified Julian date (JD-2400000.5).
+*     u = double [13] (Given & Returned)
+*        Universal orbital elements (updated, see note 1)
+*        given    (0)   combined mass (M+m)
+*          "      (1)   total energy of the orbit (alpha)
+*          "      (2)   reference (osculating) epoch (t0)
+*          "    (3-5)   position at reference epoch (r0)
+*          "    (6-8)   velocity at reference epoch (v0)
+*          "      (9)   heliocentric distance at reference epoch
+*          "     (10)   r0.v0
+*       returned (11)   date (t)
+*          "     (12)   universal eccentric anomaly (psi) of date
+*     pv = double [6] (Returned)
+*       Position (AU) and velocity (AU/s)
+*     jstat = int * (Returned)
+*       status:  0 = OK
+*               -1 = radius vector zero
+*               -2 = failed to converge
+
+*  Description:
+*     Heliocentric position and velocity of a planet, asteroid or comet,
+*     starting from orbital elements in the "universal variables" form.
+
+*  Authors:
+*     PTW: Pat Wallace (STFC)
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The "universal" elements are those which define the orbit for the
+*       purposes of the method of universal variables (see reference).
+*       They consist of the combined mass of the two bodies, an epoch,
+*       and the position and velocity vectors (arbitrary reference frame)
+*       at that epoch.  The parameter set used here includes also various
+*       quantities that can, in fact, be derived from the other
+*       information.  This approach is taken to avoiding unnecessary
+*       computation and loss of accuracy.  The supplementary quantities
+*       are (i) alpha, which is proportional to the total energy of the
+*       orbit, (ii) the heliocentric distance at epoch, (iii) the
+*       outwards component of the velocity at the given epoch, (iv) an
+*       estimate of psi, the "universal eccentric anomaly" at a given
+*       date and (v) that date.
+*     - The companion routine is palEl2ue.  This takes the conventional
+*       orbital elements and transforms them into the set of numbers
+*       needed by the present routine.  A single prediction requires one
+*       one call to palEl2ue followed by one call to the present routine;
+*       for convenience, the two calls are packaged as the routine
+*       palPlanel.  Multiple predictions may be made by again
+*       calling palEl2ue once, but then calling the present routine
+*       multiple times, which is faster than multiple calls to palPlanel.
+*     - It is not obligatory to use palEl2ue to obtain the parameters.
+*       However, it should be noted that because palEl2ue performs its
+*       own validation, no checks on the contents of the array U are made
+*       by the present routine.
+*     - DATE is the instant for which the prediction is required.  It is
+*       in the TT timescale (formerly Ephemeris Time, ET) and is a
+*       Modified Julian Date (JD-2400000.5).
+*     - The universal elements supplied in the array U are in canonical
+*       units (solar masses, AU and canonical days).  The position and
+*       velocity are not sensitive to the choice of reference frame.  The
+*       palEl2ue routine in fact produces coordinates with respect to the
+*       J2000 equator and equinox.
+*     - The algorithm was originally adapted from the EPHSLA program of
+*       D.H.P.Jones (private communication, 1996).  The method is based
+*       on Stumpff's Universal Variables.
+*     - Reference:  Everhart, E. & Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+
+*  History:
+*     2012-03-09 (TIMJ):
+*        Initial version cloned from SLA/F.
+*        Adapted with permission from the Fortran SLALIB library.
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2005 Rutherford Appleton Laboratory
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program; if not, write to the Free Software
+*     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+*     MA 02110-1301, USA.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+void palUe2pv( double date, double u[13], double pv[6], int *jstat ) {
+
+  /*  Canonical days to seconds */
+  const double CD2S = PAL__GCON / PAL__SPD;
+
+  /*  Test value for solution and maximum number of iterations */
+  const double TEST = 1e-13;
+  const int NITMAX = 25;
+
+  int I, NIT, N;
+  double CM,ALPHA,T0,P0[3],V0[3],R0,SIGMA0,T,PSI,DT,W,
+    TOL,PSJ,PSJ2,BETA,S0,S1,S2,S3,
+    FF,R,F,G,FD,GD;
+
+  double PLAST = 0.0;
+  double FLAST = 0.0;
+
+  /*  Unpack the parameters. */
+  CM = u[0];
+  ALPHA = u[1];
+  T0 = u[2];
+  for (I=0; I<3; I++) {
+    P0[I] = u[I+3];
+    V0[I] = u[I+6];
+  }
+  R0 = u[9];
+  SIGMA0 = u[10];
+  T = u[11];
+  PSI = u[12];
+
+  /*  Approximately update the universal eccentric anomaly. */
+  PSI = PSI+(date-T)*PAL__GCON/R0;
+
+  /*  Time from reference epoch to date (in Canonical Days: a canonical
+   *  day is 58.1324409... days, defined as 1/PAL__GCON). */
+  DT = (date-T0)*PAL__GCON;
+
+  /*  Refine the universal eccentric anomaly, psi. */
+  NIT = 1;
+  W = 1.0;
+  TOL = 0.0;
+  while (fabs(W) >= TOL) {
+
+    /*     Form half angles until BETA small enough. */
+    N = 0;
+    PSJ = PSI;
+    PSJ2 = PSJ*PSJ;
+    BETA = ALPHA*PSJ2;
+    while (fabs(BETA) > 0.7) {
+      N = N+1;
+      BETA = BETA/4.0;
+      PSJ = PSJ/2.0;
+      PSJ2 = PSJ2/4.0;
+    }
+
+    /*     Calculate Universal Variables S0,S1,S2,S3 by nested series. */
+    S3 = PSJ*PSJ2*((((((BETA/210.0+1.0)
+                       *BETA/156.0+1.0)
+                      *BETA/110.0+1.0)
+                     *BETA/72.0+1.0)
+                    *BETA/42.0+1.0)
+                   *BETA/20.0+1.0)/6.0;
+    S2 = PSJ2*((((((BETA/182.0+1.0)
+                   *BETA/132.0+1.0)
+                  *BETA/90.0+1.0)
+                 *BETA/56.0+1.0)
+                *BETA/30.0+1.0)
+               *BETA/12.0+1.0)/2.0;
+    S1 = PSJ+ALPHA*S3;
+    S0 = 1.0+ALPHA*S2;
+
+    /*     Undo the angle-halving. */
+    TOL = TEST;
+    while (N > 0) {
+      S3 = 2.0*(S0*S3+PSJ*S2);
+      S2 = 2.0*S1*S1;
+      S1 = 2.0*S0*S1;
+      S0 = 2.0*S0*S0-1.0;
+      PSJ = PSJ+PSJ;
+      TOL += TOL;
+      N--;
+    }
+
+    /*     Values of F and F' corresponding to the current value of psi. */
+    FF = R0*S1+SIGMA0*S2+CM*S3-DT;
+    R = R0*S0+SIGMA0*S1+CM*S2;
+
+    /*     If first iteration, create dummy "last F". */
+    if ( NIT == 1) FLAST = FF;
+
+    /*     Check for sign change. */
+    if ( FF*FLAST < 0.0 ) {
+
+      /*        Sign change:  get psi adjustment using secant method. */
+      W = FF*(PLAST-PSI)/(FLAST-FF);
+    } else {
+
+      /*        No sign change:  use Newton-Raphson method instead. */
+      if (R == 0.0) {
+        /* Null radius vector */
+        *jstat = -1;
+        return;
+      }
+      W = FF/R;
+    }
+
+    /*     Save the last psi and F values. */
+    PLAST = PSI;
+    FLAST = FF;
+
+    /*     Apply the Newton-Raphson or secant adjustment to psi. */
+    PSI = PSI-W;
+
+    /*     Next iteration, unless too many already. */
+    if (NIT > NITMAX) {
+      *jstat = -2; /* Failed to converge */
+      return;
+    }
+    NIT++;
+  }
+
+  /*  Project the position and velocity vectors (scaling velocity to AU/s). */
+  W = CM*S2;
+  F = 1.0-W/R0;
+  G = DT-CM*S3;
+  FD = -CM*S1/(R0*R);
+  GD = 1.0-W/R;
+  for (I=0; I<3; I++) {
+    pv[I] = P0[I]*F+V0[I]*G;
+    pv[I+3] = CD2S*(P0[I]*FD+V0[I]*GD);
+  }
+
+  /*  Update the parameters to allow speedy prediction of PSI next time. */
+  u[11] = date;
+  u[12] = PSI;
+
+  /*  OK exit. */
+  *jstat = 0;
+  return;
+}
Index: trunk/FACT++/pal/palUnpcd.c
===================================================================
--- trunk/FACT++/pal/palUnpcd.c	(revision 18347)
+++ trunk/FACT++/pal/palUnpcd.c	(revision 18347)
@@ -0,0 +1,176 @@
+/*
+*+
+*  Name:
+*     palUnpcd
+
+*  Purpose:
+*     Remove pincushion/barrel distortion
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     palUnpcd( double disco, double * x, double * y );
+
+*  Arguments:
+*     disco = double (Given)
+*        Pincushion/barrel distortion coefficient.
+*     x = double * (Given & Returned)
+*        On input the distorted X coordinate, on output
+*        the tangent-plane X coordinate.
+*     y = double * (Given & Returned)
+*        On input the distorted Y coordinate, on output
+*        the tangent-plane Y coordinate.
+
+*  Description:
+*     Remove pincushion/barrel distortion from a distorted [x,y] to give
+*     tangent-plane [x,y].
+
+*  Authors:
+*     PTW: Pat Wallace (RAL)
+*     TIMJ: Tim Jenness
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - The distortion is of the form RP = R*(1+C*R^2), where R is
+*       the radial distance from the tangent point, C is the DISCO
+*       argument, and RP is the radial distance in the presence of
+*       the distortion.
+*
+*     - For pincushion distortion, C is +ve;  for barrel distortion,
+*       C is -ve.
+*
+*     - For X,Y in "radians" - units of one projection radius,
+*       which in the case of a photograph is the focal length of
+*       the camera - the following DISCO values apply:
+*
+*           Geometry          DISCO
+*
+*           astrograph         0.0
+*           Schmidt           -0.3333
+*           AAT PF doublet  +147.069
+*           AAT PF triplet  +178.585
+*           AAT f/8          +21.20
+*           JKT f/8          +13.32
+*
+*     - The present routine is a rigorous inverse of the companion
+*       routine palPcd.  The expression for RP in Note 1 is rewritten
+*       in the form x^3+a*x+b=0 and solved by standard techniques.
+*
+*     - Cases where the cubic has multiple real roots can sometimes
+*       occur, corresponding to extreme instances of barrel distortion
+*       where up to three different undistorted [X,Y]s all produce the
+*       same distorted [X,Y].  However, only one solution is returned,
+*       the one that produces the smallest change in [X,Y].
+
+*  See Also:
+*     palPcd
+
+*  History:
+*     2000-09-03 (PTW):
+*        SLALIB implementation.
+*     2015-01-01 (TIMJ):
+*        Initial version
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2000 Rutherford Appleton Laboratory.
+*     Copyright (C) 2015 Tim Jenness
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <math.h>
+
+#include "pal.h"
+#include "palmac.h"
+
+/* copysign is C99 */
+#if HAVE_COPYSIGN
+# define COPYSIGN copysign
+#else
+# define COPYSIGN(a,b) DSIGN(a,b)
+#endif
+
+void palUnpcd( double disco, double * x, double *y ) {
+
+  const double THIRD = 1.0/3.0;
+
+  double rp,q,r,d,w,s,t,f,c,t3,f1,f2,f3,w1,w2,w3;
+  double c2;
+
+  /*  Distance of the point from the origin. */
+  rp = sqrt( (*x)*(*x)+(*y)*(*y));
+
+  /*  If zero, or if no distortion, no action is necessary. */
+  if (rp != 0.0 && disco != 0.0) {
+
+    /*     Begin algebraic solution. */
+    q = 1.0/(3.0*disco);
+    r = rp/(2.0*disco);
+    w = q*q*q+r*r;
+
+    /* Continue if one real root, or three of which only one is positive. */
+    if (w > 0.0) {
+
+      d = sqrt(w);
+      w = r+d;
+      s = COPYSIGN(pow(fabs(w),THIRD),w);
+      w = r-d;
+      t = COPYSIGN(pow(fabs(w),THIRD),w);
+      f = s+t;
+
+    } else {
+      /* Three different real roots:  use geometrical method instead. */
+      w = 2.0/sqrt(-3.0*disco);
+      c = 4.0*rp/(disco*w*w*w);
+      c2 = c*c;
+      s = sqrt(1.0-DMIN(c2,1.0));
+      t3 = atan2(s,c);
+
+      /* The three solutions. */
+      f1 = w*cos((PAL__D2PI-t3)/3.0);
+      f2 = w*cos((t3)/3.0);
+      f3 = w*cos((PAL__D2PI+t3)/3.0);
+
+      /* Pick the one that moves [X,Y] least. */
+      w1 = fabs(f1-rp);
+      w2 = fabs(f2-rp);
+      w3 = fabs(f3-rp);
+      if (w1 < w2) {
+        f = ( w1 < w3 ? f1 : f3 );
+      } else {
+        f = ( w2 < w3 ? f2 : f3 );
+      }
+    }
+
+    /* Remove the distortion. */
+    f = f/rp;
+    *x *= f;
+    *y *= f;
+  }
+}
Index: trunk/FACT++/pal/palVers.c
===================================================================
--- trunk/FACT++/pal/palVers.c	(revision 18347)
+++ trunk/FACT++/pal/palVers.c	(revision 18347)
@@ -0,0 +1,92 @@
+/*
+*+
+*  Name:
+*     palVers
+
+*  Purpose:
+*     Obtain PAL version number
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Library routine
+
+*  Invocation:
+*     int palVers( char *verstring, size_t verlen );
+
+*  Arguments:
+*     verstring = char * (Returned)
+*        Buffer to receive version string of the form "A.B.C". Can be NULL.
+*     verlen = size_t (Given)
+*        Allocated size of "verstring" including nul. Version string
+*        will be truncated if it does not fit in buffer.
+
+*  Returned Value:
+*     vernum = int (Returned)
+*        Version number as an integer.
+
+*  Description:
+*     Retrieve the PAL version number as a string in the form "A.B.C"
+*     and as an integer (major*1e6+minor*1e3+release).
+
+*  Authors:
+*     TIMJ: Tim Jenness (Cornell)
+*     {enter_new_authors_here}
+
+*  Notes:
+*     - Note that this API does not match the slaVers API.
+
+*  History:
+*     2014-08-27 (TIMJ):
+*        Initial version
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2014 Cornell University
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software; you can redistribute it and/or
+*     modify it under the terms of the GNU General Public License as
+*     published by the Free Software Foundation; either version 3 of
+*     the License, or (at your option) any later version.
+*
+*     This program is distributed in the hope that it will be
+*     useful, but WITHOUT ANY WARRANTY; without even the implied
+*     warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+*     PURPOSE. See the GNU General Public License for more details.
+*
+*     You should have received a copy of the GNU General Public License
+*     along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_BSD_STRING_H
+#include <bsd/string.h>
+#endif
+
+#include <string.h>
+
+/* This version is just a straight copy without putting ellipsis on the end. */
+static void my__strlcpy( char * dest, const char * src, size_t size ) {
+# if HAVE_STRLCPY
+  strlcpy( dest, src, size );
+# else
+  strncpy( dest, src, size );
+  dest[size-1] = '\0';
+# endif
+}
+
+int
+palVers( char *verstring, size_t verlen ) {
+  if (verstring) my__strlcpy( verstring, PACKAGE_VERSION, verlen );
+  return PACKAGE_VERSION_INTEGER;
+}
Index: trunk/FACT++/pal/palmac.h
===================================================================
--- trunk/FACT++/pal/palmac.h	(revision 18347)
+++ trunk/FACT++/pal/palmac.h	(revision 18347)
@@ -0,0 +1,136 @@
+#ifndef PALMACDEF
+#define PALMACDEF
+
+/*
+*+
+*  Name:
+*     palmac.h
+
+*  Purpose:
+*     Macros used by the PAL library
+
+*  Language:
+*     Starlink ANSI C
+
+*  Type of Module:
+*     Include file
+
+*  Description:
+*     A collection of useful macros provided and used by the PAL library
+
+*  Authors:
+*     TIMJ: Tim Jenness (JAC, Hawaii)
+*     DSB: David Berry (JAC, Hawaii)
+*     {enter_new_authors_here}
+
+*  Notes:
+*
+
+*  History:
+*     2012-02-08 (TIMJ):
+*        Initial version.
+*        Adapted with permission from the Fortran SLALIB library.
+*     2012-04-13 (DSB):
+*        Added PAL__DR2H and PAL__DR2S
+*     {enter_further_changes_here}
+
+*  Copyright:
+*     Copyright (C) 2012 Science and Technology Facilities Council.
+*     All Rights Reserved.
+
+*  Licence:
+*     This program is free software: you can redistribute it and/or
+*     modify it under the terms of the GNU Lesser General Public
+*     License as published by the Free Software Foundation, either
+*     version 3 of the License, or (at your option) any later
+*     version.
+*
+*     This program is distributed in the hope that it will be useful,
+*     but WITHOUT ANY WARRANTY; without even the implied warranty of
+*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+*     GNU Lesser General Public License for more details.
+*
+*     You should have received a copy of the GNU Lesser General
+*     License along with this program.  If not, see
+*     <http://www.gnu.org/licenses/>.
+
+*  Bugs:
+*     {note_any_bugs_here}
+*-
+*/
+
+/* Pi */
+static const double PAL__DPI = 3.1415926535897932384626433832795028841971693993751;
+
+/* 2Pi */
+static const double PAL__D2PI = 6.2831853071795864769252867665590057683943387987502;
+
+/* pi/2:  90 degrees in radians */
+static const double PAL__DPIBY2 = 1.5707963267948966192313216916397514420985846996876;
+
+/* pi/180:  degrees to radians */
+static const double PAL__DD2R = 0.017453292519943295769236907684886127134428718885417;
+
+/* Radians to arcseconds */
+static const double PAL__DR2AS = 2.0626480624709635515647335733077861319665970087963e5;
+
+/* Arcseconds to radians */
+static const double PAL__DAS2R = 4.8481368110953599358991410235794797595635330237270e-6;
+
+/* Radians to degrees */
+static const double PAL__DR2D = 57.295779513082320876798154814105170332405472466564;
+
+/* Hours to radians */
+static const double PAL__DH2R = 0.26179938779914943653855361527329190701643078328126;
+
+/* Radians to hours */
+static const double PAL__DR2H = 3.8197186342054880584532103209403446888270314977709;
+
+/* Radians to seconds of time */
+static const double PAL__DR2S = 1.3750987083139757010431557155385240879777313391975e4;
+
+/* Seconds of time to radians */
+static const double PAL__DS2R = 7.272205216643039903848712e-5;
+
+/* Start of SLA modified Julian date epoch */
+static const double PAL__MJD0 = 2400000.5;
+
+/* Light time for 1 AU (sec) */
+static const double PAL__CR = 499.004782;
+
+/* Seconds per day */
+static const double PAL__SPD = 86400.0;
+
+/* Km per sec to AU per tropical century
+   = 86400 * 36524.2198782 / 149597870 */
+static const double PAL__VF = 21.095;
+
+/*  Radians per year to arcsec per century. This needs to be a macro since it
+    is an expression including other constants. */
+#define PAL__PMF (100.0*60.0*60.0*360.0/PAL__D2PI);
+
+/* Mean sidereal rate - the rotational angular velocity of Earth
+   in radians/sec from IERS Conventions (2003). */
+static const double PAL__SR = 7.2921150e-5;
+
+/*  Gaussian gravitational constant (exact) */
+static const double PAL__GCON = 0.01720209895;
+
+/* DINT(A) - truncate to nearest whole number towards zero (double) */
+#define DINT(A) ((A)<0.0?ceil(A):floor(A))
+
+/* DNINT(A) - round to nearest whole number (double) */
+#define DNINT(A) ((A)<0.0?ceil((A)-0.5):floor((A)+0.5))
+
+/* DMAX(A,B) - return maximum value - evaluates arguments multiple times */
+#define DMAX(A,B) ((A) > (B) ? (A) : (B) )
+
+/* DMIN(A,B) - return minimum value - evaluates arguments multiple times */
+#define DMIN(A,B) ((A) < (B) ? (A) : (B) )
+
+/* We actually prefer to use C99 copysign() but we define this here as a backup
+   but it will not detect -0.0 so is not useful for palDfltin. */
+/* DSIGN(A,B) - magnitude of A with sign of B (double) */
+#define DSIGN(A,B) ((B)<0.0?-fabs(A):fabs(A))
+
+#endif
Index: trunk/FACT++/pal/sofa-porting-guide.txt
===================================================================
--- trunk/FACT++/pal/sofa-porting-guide.txt	(revision 18347)
+++ trunk/FACT++/pal/sofa-porting-guide.txt	(revision 18347)
@@ -0,0 +1,42 @@
+Some SLA routines migrate directly to SOFA. Simple PAL wrappers are
+made available using the SLA name but new code should use the SOFA
+variant directly. The PAL routines should not be called internally
+by other PAL routines.
+
+Daf2r  => Af2a
+Dav2m  => Rv2m
+Dcc2s  => C2s
+Dcs2c  => S2c
+Dd2tf  => D2tf
+Dimxv  => Trxp
+Djcl   => Jd2cal
+Dmxm   => Rxr
+Dmxv   => Rxp
+Dm2av  => Rm2v
+Dranrm => Anp
+Drange => Anpm
+Dsep   => Seps
+Dsepv  => Sepp
+Dtf2d  => Tf2d
+Dtf2r  => Tf2a
+Dvdv   => Pdp
+Dvn    => Pn
+Dvxv   => Pxp
+Epb    => Epb
+Epb2d  => Epb2jd
+Epj    => Epj
+Epj2d  => Epj2jd
+Eqeqx  => Ee06a
+Fk5hz  => Fk5hz
+Gmst   => Gmst06
+Hfk5z  => Hfk5z
+
+
+Some SLA routines are close to the same but have different arguments
+so a PAL routine is provided although it is probably best to port software
+to the SOFA variant:
+
+slaDat =>palDat => iauDat
+
+slaGeoc has different arguments and uses the WGS84 model. The code is not
+quite one-to-one.
Index: trunk/FACT++/pal/sun267.tex
===================================================================
--- trunk/FACT++/pal/sun267.tex	(revision 18347)
+++ trunk/FACT++/pal/sun267.tex	(revision 18347)
@@ -0,0 +1,8810 @@
+\documentclass[twoside,11pt,nolof]{starlink}
+
+% ? Specify used packages
+% ? End of specify used packages
+
+% -----------------------------------------------------------------------------
+% ? Document identification
+% Fixed part
+\stardoccategory  {Starlink User Note}
+\stardocinitials  {SUN}
+\stardocsource    {sun\stardocnumber}
+\stardoccopyright{%
+Copyright \copyright\ 2012 Science and Technology Facilities
+  Council.\\ Copyright \copyright\ 2014 Cornell University.\\
+Copyright \copyright\ 2015 Tim Jenness}
+
+% Variable part - replace [xxx] as appropriate.
+\stardocnumber    {267.3}
+\stardocauthors   {Tim Jenness}
+\stardocdate      {2015 January 1}
+\stardoctitle     {PAL --- Positional Astronomy Library}
+\stardocversion   {0.9.0}
+\stardocmanual    {Programmer's Manual}
+\stardocabstract  {%
+PAL provides a subset of the Fortran SLALIB library but written in C
+using the SLALIB C API. Where possible the PAL routines are
+implemented using the C SOFA/ERFA library. It is provided with a GPLv3 license.
+}
+% ? End of document identification
+% -----------------------------------------------------------------------------
+
+\begin{document}
+\scfrontmatter
+
+% ? Main text
+
+\section{Introduction}
+
+This library provides a C library designed as a API-compatible
+replacement for the C SLALIB library (SUN/67) and uses a GPL licence so is
+freely redistributable. Where possible the functions call equivalent
+SOFA routines (Hohenkerk, C., 2011, Scholarpedia, \textbf{6}, \emph{11404})\footnote{or equivalent ERFA routines.}
+and use current IAU 2006 standards. This means that any
+functions that rely on nutation or precession will return slightly
+different answers to the SLA functions.
+
+\section{Citing PAL}
+
+If you use PAL in your work please consider citing it. The description paper
+for PAL is: \emph{PAL: A Positional Astronomy Library}, Jenness, T. \& Berry, D. S.,
+in \emph{Astronomical Data Anaysis Software and Systems XXII}, Friedel, D. N. (ed),
+ASP Conf.\ Ser. \textbf{475}, p307.
+
+\clearpage
+\appendix
+\section{\label{APP:SPEC}Function Descriptions}
+
+By default PAL is set up to use the ERFA variant of SOFA. ERFA is an
+approved redistribution of the SOFA code using a BSD-license and
+renamed function calls. Whereas SOFA routines have a \texttt{iau} prefix
+the ERFA equivalents have a \texttt{era} prefix. The PAL build script
+will try to detect which of ERFA and SOFA is available. Wherever SOFA
+is mentioned in this document the ERFA equivalent can be substituted.
+
+ERFA can be obtained from \htmladdnormallink{https://github.com/liberfa/erfa}.
+
+\subsection{SOFA Mappings}
+
+The following table lists PAL/SLA functions that have direct
+replacements in SOFA. Whilst these routines are implemented in the PAL
+library using SOFA new code should probably call SOFA directly.
+
+\begin{tabbing}
+\hspace*{2cm}\=\hspace*{3cm}\= \kill
+SLA/PAL \>  SOFA \\
+\texttt{palCldj} \> \texttt{iauCal2jd} \\
+\texttt{palDbear} \> \texttt{iauPas} \\
+\texttt{palDaf2r} \> \texttt{iauAf2a} \\
+\texttt{palDav2m} \>  \texttt{iauRv2m} \\
+\texttt{palDcc2s} \>  \texttt{iauC2s} \\
+\texttt{palDcs2c} \> \texttt{iauS2c} \\
+\texttt{palDd2tf} \> \texttt{iauD2tf}\\
+\texttt{palDimxv} \> \texttt{iauTrxp}\\
+\texttt{palDm2av} \> \texttt{iauRm2v}\\
+\texttt{palDjcl} \> \texttt{iauJd2cal}\\
+\texttt{palDmxm} \> \texttt{iauRxr}\\
+\texttt{palDmxv} \> \texttt{iauRxp}\\
+\texttt{palDpav} \> \texttt{iauPap}\\
+\texttt{palDr2af} \> \texttt{iauA2af}\\
+\texttt{palDr2tf} \> \texttt{iauA2tf}\\
+\texttt{palDranrm} \> \texttt{iauAnp}\\
+\texttt{palDsep} \> \texttt{iauSeps}\\
+\texttt{palDsepv} \> \texttt{iauSepp}\\
+\texttt{palDtf2d} \> \texttt{iauTf2d}\\
+\texttt{palDtf2r} \> \texttt{iauTf2a}\\
+\texttt{palDvdv} \> \texttt{iauPdp}\\
+\texttt{palDvn} \> \texttt{iauPn}\\
+\texttt{palDvxv} \> \texttt{iauPxp}\\
+\texttt{palEpb} \> \texttt{iauEpb}\\
+\texttt{palEpb2d} \> \texttt{iauEpb2d}\\
+\texttt{palEpj} \> \texttt{iauEpj}\\
+\texttt{palEpj2d} \> \texttt{iauEpj2jd}\\
+\texttt{palEqeqx} \> \texttt{iauEe06a}\\
+\texttt{palFk5hz} \> \texttt{iauFk5hz} \textit{also calls iauEpj2jd}\\
+\texttt{palGmst} \> \texttt{iauGmst06}\\
+\texttt{palGmsta} \> \texttt{iauGmst06}\\
+\texttt{palHfk5z} \> \texttt{iauHfk5z} \textit{also calls iauEpj2jd}\\
+\texttt{palRefcoq} \> \texttt{iauRefco}\\
+\end{tabbing}
+
+\sstroutine{
+   palCldj
+}{
+   Gregorian Calendar to Modified Julian Date
+}{
+   \sstdescription{
+      Gregorian calendar to Modified Julian Date.
+   }
+   \sstinvocation{
+      palCldj( int iy, int im, int id, double $*$djm, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         iy = int (Given)
+      }{
+         Year in Gregorian calendar
+      }
+      \sstsubsection{
+         im = int (Given)
+      }{
+         Month in Gregorian calendar
+      }
+      \sstsubsection{
+         id = int (Given)
+      }{
+         Day in Gregorian calendar
+      }
+      \sstsubsection{
+         djm = double $*$ (Returned)
+      }{
+         Modified Julian Date (JD-2400000.5) for 0 hrs
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         status: 0 = OK, 1 = bad year (MJD not computed),
+         2 = bad month (MJD not computed), 3 = bad day (MJD computed).
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraCal2jd(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDbear
+}{
+   Bearing (position angle) of one point on a sphere relative to another
+}{
+   \sstdescription{
+      Bearing (position angle) of one point in a sphere relative to another.
+   }
+   \sstinvocation{
+      pa = palDbear( double a1, double b1, double a2, double b2 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         a1 = double (Given)
+      }{
+         Longitude of point A (e.g. RA) in radians.
+      }
+      \sstsubsection{
+         a2 = double (Given)
+      }{
+         Latitude of point A (e.g. Dec) in radians.
+      }
+      \sstsubsection{
+         b1 = double (Given)
+      }{
+         Longitude of point B in radians.
+      }
+      \sstsubsection{
+         b2 = double (Given)
+      }{
+         Latitude of point B in radians.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         The result is the bearing (position angle), in radians, of point
+      }{
+      }
+      \sstsubsection{
+         A2,B2 as seen from point A1,B1.  It is in the range $+$/- pi.  If
+      }{
+      }
+      \sstsubsection{
+         A2,B2 is due east of A1,B1 the bearing is $+$pi/2.  Zero is returned
+      }{
+      }
+      \sstsubsection{
+         if the two points are coincident.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraPas(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDaf2r
+}{
+   Convert degrees, arcminutes, arcseconds to radians
+}{
+   \sstdescription{
+      Convert degrees, arcminutes, arcseconds to radians.
+   }
+   \sstinvocation{
+      palDaf2r( int ideg, int iamin, double asec, double $*$rad, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ideg = int (Given)
+      }{
+         Degrees.
+      }
+      \sstsubsection{
+         iamin = int (Given)
+      }{
+         Arcminutes.
+      }
+      \sstsubsection{
+         iasec = double (Given)
+      }{
+         Arcseconds.
+      }
+      \sstsubsection{
+         rad = double $*$ (Returned)
+      }{
+         Angle in radians.
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         Status: 0 = OK, 1 = {\tt "}ideg{\tt "} out of range 0-359,
+                 2 = {\tt "}iamin{\tt "} outside of range 0-59,
+                 2 = {\tt "}asec{\tt "} outside range 0-59.99999
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraAf2a(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDav2m
+}{
+   Form the rotation matrix corresponding to a given axial vector
+}{
+   \sstdescription{
+      A rotation matrix describes a rotation about some arbitrary axis,
+      called the Euler axis.  The {\tt "}axial vector{\tt "} supplied to this routine
+      has the same direction as the Euler axis, and its magnitude is the
+      amount of rotation in radians.
+   }
+   \sstinvocation{
+      palDav2m( double axvec[3], double rmat[3][3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         axvec = double [3] (Given)
+      }{
+         Axial vector (radians)
+      }
+      \sstsubsection{
+         rmat = double [3][3] (Returned)
+      }{
+         Rotation matrix.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraRv2m(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDcc2s
+}{
+   Cartesian to spherical coordinates
+}{
+   \sstdescription{
+      The spherical coordinates are longitude ($+$ve anticlockwise looking
+      from the $+$ve latitude pole) and latitude.  The Cartesian coordinates
+      are right handed, with the x axis at zero longitude and latitude, and
+      the z axis at the $+$ve latitude pole.
+   }
+   \sstinvocation{
+      palDcc2s( double v[3], double $*$a, double $*$b );
+   }
+   \sstarguments{
+      \sstsubsection{
+         v = double [3] (Given)
+      }{
+         x, y, z vector.
+      }
+      \sstsubsection{
+         a = double $*$ (Returned)
+      }{
+         Spherical coordinate (radians)
+      }
+      \sstsubsection{
+         b = double $*$ (Returned)
+      }{
+         Spherical coordinate (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraC2s(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDcs2c
+}{
+   Spherical coordinates to direction cosines
+}{
+   \sstdescription{
+      The spherical coordinates are longitude ($+$ve anticlockwise looking
+      from the $+$ve latitude pole) and latitude.  The Cartesian coordinates
+      are right handed, with the x axis at zero longitude and latitude, and
+      the z axis at the $+$ve latitude pole.
+   }
+   \sstinvocation{
+      palDcs2c( double a, double b, double v[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         a = double (Given)
+      }{
+         Spherical coordinate in radians (ra, long etc).
+      }
+      \sstsubsection{
+         b = double (Given)
+      }{
+         Spherical coordinate in radians (dec, lat etc).
+      }
+      \sstsubsection{
+         v = double [3] (Returned)
+      }{
+         x, y, z vector
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraS2c(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDd2tf
+}{
+   Convert an interval in days into hours, minutes, seconds
+}{
+   \sstdescription{
+      Convert and interval in days into hours, minutes, seconds.
+   }
+   \sstinvocation{
+      palDd2tf( int ndp, double days, char $*$sign, int ihmsf[4] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ndp = int (Given)
+      }{
+         Number of decimal places of seconds
+      }
+      \sstsubsection{
+         days = double (Given)
+      }{
+         Interval in days
+      }
+      \sstsubsection{
+         sign = char $*$ (Returned)
+      }{
+         {\tt '}$+${\tt '} or {\tt '}-{\tt '} (single character, not string)
+      }
+      \sstsubsection{
+         ihmsf = int [4] (Returned)
+      }{
+         Hours, minutes, seconds, fraction
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraD2tf(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDimxv
+}{
+   Perform the 3-D backward unitary transformation
+}{
+   \sstdescription{
+      Perform the 3-D backward unitary transformation.
+   }
+   \sstinvocation{
+      palDimxv( double dm[3][3], double va[3], double vb[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dm = double [3][3] (Given)
+      }{
+         Matrix
+      }
+      \sstsubsection{
+         va = double [3] (Given)
+      }{
+         vector
+      }
+      \sstsubsection{
+         vb = double [3] (Returned)
+      }{
+         Result vector
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraTrxp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDm2av
+}{
+   From a rotation matrix, determine the corresponding axial vector
+}{
+   \sstdescription{
+      A rotation matrix describes a rotation about some arbitrary axis,
+      called the Euler axis.  The {\tt "}axial vector{\tt "} returned by this routine
+      has the same direction as the Euler axis, and its magnitude is the
+      amount of rotation in radians.  (The magnitude and direction can be
+      separated by means of the routine palDvn.)
+   }
+   \sstinvocation{
+      palDm2av( double rmat[3][3], double axvec[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rmat = double [3][3] (Given)
+      }{
+         Rotation matrix
+      }
+      \sstsubsection{
+         axvec = double [3] (Returned)
+      }{
+         Axial vector (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraRm2v(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDjcl
+}{
+   Modified Julian Date to Gregorian year, month, day and fraction of day
+}{
+   \sstdescription{
+      Modified Julian Date to Gregorian year, month, day and fraction of day.
+   }
+   \sstinvocation{
+      palDjcl( double djm, int $*$iy, int $*$im, int $*$id, double $*$fd, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         djm = double (Given)
+      }{
+         modified Julian Date (JD-2400000.5)
+      }
+      \sstsubsection{
+         iy = int $*$ (Returned)
+      }{
+         year
+      }
+      \sstsubsection{
+         im = int $*$ (Returned)
+      }{
+         month
+      }
+      \sstsubsection{
+         id = int $*$ (Returned)
+      }{
+         day
+      }
+      \sstsubsection{
+         fd = double $*$ (Returned)
+      }{
+         Fraction of day.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraJd2cal(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDmxm
+}{
+   Product of two 3x3 matrices
+}{
+   \sstdescription{
+      Product of two 3x3 matrices.
+   }
+   \sstinvocation{
+      palDmxm( double a[3][3], double b[3][3], double c[3][3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         a = double [3][3] (Given)
+      }{
+         Matrix
+      }
+      \sstsubsection{
+         b = double [3][3] (Given)
+      }{
+         Matrix
+      }
+      \sstsubsection{
+         c = double [3][3] (Returned)
+      }{
+         Matrix result
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraRxr(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDmxv
+}{
+   Performs the 3-D forward unitary transformation
+}{
+   \sstdescription{
+      Performs the 3-D forward unitary transformation.
+   }
+   \sstinvocation{
+      palDmxv( double dm[3][3], double va[3], double vb[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dm = double [3][3] (Given)
+      }{
+         matrix
+      }
+      \sstsubsection{
+         va = double [3] (Given)
+      }{
+         vector
+      }
+      \sstsubsection{
+         dp = double [3] (Returned)
+      }{
+         result vector
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraRxp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDpav
+}{
+   Position angle of one celestial direction with respect to another
+}{
+   \sstdescription{
+      Position angle of one celestial direction with respect to another.
+   }
+   \sstinvocation{
+      pa = palDpav( double v1[3], double v2[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         v1 = double [3] (Given)
+      }{
+         direction cosines of one point.
+      }
+      \sstsubsection{
+         v2 = double [3] (Given)
+      }{
+         direction cosines of the other point.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         The result is the bearing (position angle), in radians, of point
+      }{
+      }
+      \sstsubsection{
+         V2 with respect to point V1.  It is in the range $+$/- pi.  The
+      }{
+      }
+      \sstsubsection{
+         sense is such that if V2 is a small distance east of V1, the
+      }{
+      }
+      \sstsubsection{
+         bearing is about $+$pi/2.  Zero is returned if the two points
+      }{
+      }
+      \sstsubsection{
+         are coincident.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The coordinate frames correspond to RA,Dec, Long,Lat etc.
+
+         \sstitem
+         Uses eraPap(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDr2af
+}{
+   Convert an angle in radians to degrees, arcminutes, arcseconds
+}{
+   \sstdescription{
+      Convert an angle in radians to degrees, arcminutes, arcseconds.
+   }
+   \sstinvocation{
+      palDr2af( int ndp, double angle, char $*$sign, int idmsf[4] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ndp = int (Given)
+      }{
+         number of decimal places of arcseconds
+      }
+      \sstsubsection{
+         angle = double (Given)
+      }{
+         angle in radians
+      }
+      \sstsubsection{
+         sign = char $*$ (Returned)
+      }{
+         {\tt '}$+${\tt '} or {\tt '}-{\tt '} (single character)
+      }
+      \sstsubsection{
+         idmsf = int [4] (Returned)
+      }{
+         Degrees, arcminutes, arcseconds, fraction
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraA2af(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDr2tf
+}{
+   Convert an angle in radians to hours, minutes, seconds
+}{
+   \sstdescription{
+      Convert an angle in radians to hours, minutes, seconds.
+   }
+   \sstinvocation{
+      palDr2tf ( int ndp, double angle, char $*$sign, int ihmsf[4] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ndp = int (Given)
+      }{
+         number of decimal places of arcseconds
+      }
+      \sstsubsection{
+         angle = double (Given)
+      }{
+         angle in radians
+      }
+      \sstsubsection{
+         sign = char $*$ (Returned)
+      }{
+         {\tt '}$+${\tt '} or {\tt '}-{\tt '} (single character)
+      }
+      \sstsubsection{
+         idmsf = int [4] (Returned)
+      }{
+         Hours, minutes, seconds, fraction
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraA2tf(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDranrm
+}{
+   Normalize angle into range 0-2 pi
+}{
+   \sstdescription{
+      Normalize angle into range 0-2 pi.
+   }
+   \sstinvocation{
+      norm = palDranrm( double angle );
+   }
+   \sstarguments{
+      \sstsubsection{
+         angle = double (Given)
+      }{
+         angle in radians
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Angle expressed in the range 0-2 pi
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraAnp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDsep
+}{
+   Angle between two points on a sphere
+}{
+   \sstdescription{
+      Angle between two points on a sphere.
+   }
+   \sstinvocation{
+      ang = palDsep( double a1, double b1, double a2, double b2 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         a1 = double (Given)
+      }{
+         Spherical coordinate of one point (radians)
+      }
+      \sstsubsection{
+         b1 = double (Given)
+      }{
+         Spherical coordinate of one point (radians)
+      }
+      \sstsubsection{
+         a2 = double (Given)
+      }{
+         Spherical coordinate of other point (radians)
+      }
+      \sstsubsection{
+         b2 = double (Given)
+      }{
+         Spherical coordinate of other point (radians)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Angle, in radians, between the two points. Always positive.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The spherical coordinates are [RA,Dec], [Long,Lat] etc, in radians.
+
+         \sstitem
+         Uses eraSeps(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDsepv
+}{
+   Angle between two vectors
+}{
+   \sstdescription{
+      Angle between two vectors.
+   }
+   \sstinvocation{
+      ang = palDsepv( double v1[3], double v2[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         v1 = double [3] (Given)
+      }{
+         First vector
+      }
+      \sstsubsection{
+         v2 = double [3] (Given)
+      }{
+         Second vector
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Angle, in radians, between the two points. Always positive.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraSepp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDtf2d
+}{
+   Convert hours, minutes, seconds to days
+}{
+   \sstdescription{
+      Convert hours, minutes, seconds to days.
+   }
+   \sstinvocation{
+      palDtf2d( int ihour, int imin, double sec, double $*$days, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ihour = int (Given)
+      }{
+         Hours
+      }
+      \sstsubsection{
+         imin = int (Given)
+      }{
+         Minutes
+      }
+      \sstsubsection{
+         sec = double (Given)
+      }{
+         Seconds
+      }
+      \sstsubsection{
+         days = double $*$ (Returned)
+      }{
+         Interval in days
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         status: 0 = ok, 1 = ihour outside range 0-23,
+         2 = imin outside range 0-59, 3 = sec outside range 0-59.999...
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraTf2d(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDtf2r
+}{
+   Convert hours, minutes, seconds to radians
+}{
+   \sstdescription{
+      Convert hours, minutes, seconds to radians.
+   }
+   \sstinvocation{
+      palDtf2r( int ihour, int imin, double sec, double $*$rad, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ihour = int (Given)
+      }{
+         Hours
+      }
+      \sstsubsection{
+         imin = int (Given)
+      }{
+         Minutes
+      }
+      \sstsubsection{
+         sec = double (Given)
+      }{
+         Seconds
+      }
+      \sstsubsection{
+         days = double $*$ (Returned)
+      }{
+         Angle in radians
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         status: 0 = ok, 1 = ihour outside range 0-23,
+         2 = imin outside range 0-59, 3 = sec outside range 0-59.999...
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraTf2a(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDvdv
+}{
+   Scalar product of two 3-vectors
+}{
+   \sstdescription{
+      Scalar product of two 3-vectors.
+   }
+   \sstinvocation{
+      prod = palDvdv ( double va[3], double vb[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         va = double [3] (Given)
+      }{
+         First vector
+      }
+      \sstsubsection{
+         vb = double [3] (Given)
+      }{
+         Second vector
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Scalar product va.vb
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraPdp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDvn
+}{
+   Normalizes a 3-vector also giving the modulus
+}{
+   \sstdescription{
+      Normalizes a 3-vector also giving the modulus.
+   }
+   \sstinvocation{
+      palDvn( double v[3], double uv[3], double $*$vm );
+   }
+   \sstarguments{
+      \sstsubsection{
+         v = double [3] (Given)
+      }{
+         vector
+      }
+      \sstsubsection{
+         uv = double [3] (Returned)
+      }{
+         unit vector in direction of {\tt "}v{\tt "}
+      }
+      \sstsubsection{
+         vm = double $*$ (Returned)
+      }{
+         modulus of {\tt "}v{\tt "}
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraPn(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palDvxv
+}{
+   Vector product of two 3-vectors
+}{
+   \sstdescription{
+      Vector product of two 3-vectors.
+   }
+   \sstinvocation{
+      palDvxv( double va[3], double vb[3], double vc[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         va = double [3] (Given)
+      }{
+         First vector
+      }
+      \sstsubsection{
+         vb = double [3] (Given)
+      }{
+         Second vector
+      }
+      \sstsubsection{
+         vc = double [3] (Returned)
+      }{
+         Result vector
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraPxp(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palEpb
+}{
+   Conversion of modified Julian Data to Besselian Epoch
+}{
+   \sstdescription{
+      Conversion of modified Julian Data to Besselian Epoch.
+   }
+   \sstinvocation{
+      epb = palEpb ( double date );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Modified Julian Date (JD - 2400000.5)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Besselian epoch.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEpb(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palEpb2d
+}{
+   Conversion of Besselian Epoch to Modified Julian Date
+}{
+   \sstdescription{
+      Conversion of Besselian Epoch to Modified Julian Date.
+   }
+   \sstinvocation{
+      mjd = palEpb2d ( double epb );
+   }
+   \sstarguments{
+      \sstsubsection{
+         epb = double (Given)
+      }{
+         Besselian Epoch
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Modified Julian Date (JD - 2400000.5)
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEpb2jd(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palEpj
+}{
+   Conversion of Modified Julian Date to Julian Epoch
+}{
+   \sstdescription{
+      Conversion of Modified Julian Date to Julian Epoch.
+   }
+   \sstinvocation{
+      epj = palEpj ( double date );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Modified Julian Date (JD - 2400000.5)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         The Julian Epoch.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEpj(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palEpj2d
+}{
+   Conversion of Julian Epoch to Modified Julian Date
+}{
+   \sstdescription{
+      Conversion of Julian Epoch to Modified Julian Date.
+   }
+   \sstinvocation{
+      mjd = palEpj2d ( double epj );
+   }
+   \sstarguments{
+      \sstsubsection{
+         epj = double (Given)
+      }{
+         Julian Epoch.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Modified Julian Date (JD - 2400000.5)
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEpj2d(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palEqeqx
+}{
+   Equation of the equinoxes (IAU 2000/2006)
+}{
+   \sstdescription{
+      Equation of the equinoxes (IAU 2000/2006).
+   }
+   \sstinvocation{
+      palEqeqx( double date );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as Modified Julian Date (JD-400000.5)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEe06a(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palFk5hz
+}{
+   Transform an FK5 (J2000) star position into the frame of the
+   Hipparcos catalogue
+}{
+   \sstdescription{
+      Transform an FK5 (J2000) star position into the frame of the
+      Hipparcos catalogue.
+   }
+   \sstinvocation{
+      palFk5hz ( double r5, double d5, double epoch,
+                 double $*$rh, double $*$dh );
+   }
+   \sstarguments{
+      \sstsubsection{
+         r5 = double (Given)
+      }{
+         FK5 RA (radians), equinox J2000, epoch {\tt "}epoch{\tt "}
+      }
+      \sstsubsection{
+         d5 = double (Given)
+      }{
+         FK5 dec (radians), equinox J2000, epoch {\tt "}epoch{\tt "}
+      }
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Julian epoch
+      }
+      \sstsubsection{
+         rh = double $*$ (Returned)
+      }{
+         RA (radians)
+      }
+      \sstsubsection{
+         dh = double $*$ (Returned)
+      }{
+         Dec (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Assumes zero Hipparcos proper motion.
+
+         \sstitem
+         Uses eraEpj2jd() and eraFk5hz.
+           See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palGmst
+}{
+   Greenwich mean sidereal time (consistent with IAU 2006 precession)
+}{
+   \sstdescription{
+      Greenwich mean sidereal time (consistent with IAU 2006 precession).
+   }
+   \sstinvocation{
+      mst = palGmst ( double ut1 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ut1 = double (Given)
+      }{
+         Universal time (UT1) expressed as modified Julian Date (JD-2400000.5)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Greenwich mean sidereal time
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraGmst06(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palGmsta
+}{
+   Greenwich mean sidereal time (consistent with IAU 2006 precession)
+}{
+   \sstdescription{
+      Greenwich mean sidereal time (consistent with IAU 2006 precession).
+   }
+   \sstinvocation{
+      mst = palGmsta ( double date, double ut1 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         UT1 date (MJD: integer part of JD-2400000.5)
+      }
+      \sstsubsection{
+         ut1 = double (Given)
+      }{
+         UT1 time (fraction of a day)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Greenwich mean sidereal time (in range 0 to 2 pi)
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         For best accuracy use eraGmst06() directly.
+
+         \sstitem
+         Uses eraGmst06(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palHfk5z
+}{
+   Hipparcos star position to FK5 J2000
+}{
+   \sstdescription{
+      Transform a Hipparcos star position into FK5 J2000, assuming
+      zero Hipparcos proper motion.
+   }
+   \sstinvocation{
+      palHfk5z( double rh, double dh, double epoch,
+                double $*$r5, double $*$d5, double $*$dr5, double $*$dd5 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Hipparcos RA (radians)
+      }
+      \sstsubsection{
+         dh = double (Given)
+      }{
+         Hipparcos Dec (radians)
+      }
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Julian epoch (TDB)
+      }
+      \sstsubsection{
+         r5 = double $*$ (Returned)
+      }{
+         RA (radians, FK5, equinox J2000, epoch {\tt "}epoch{\tt "})
+      }
+      \sstsubsection{
+         d5 = double $*$ (Returned)
+      }{
+         Dec (radians, FK5, equinox J2000, epoch {\tt "}epoch{\tt "})
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraEpj2jd and eraHfk5z(). See SOFA/ERFA documentation for details.
+      }
+   }
+}
+\sstroutine{
+   palRefcoq
+}{
+   Determine the constants A and B in the atmospheric refraction model
+}{
+   \sstdescription{
+      Determine the constants A and B in the atmospheric refraction
+      model dZ = A tan Z $+$ B tan$*$$*$3 Z.  This is a fast alternative
+      to the palRefco routine.
+
+      Z is the {\tt "}observed{\tt "} zenith distance (i.e. affected by refraction)
+      and dZ is what to add to Z to give the {\tt "}topocentric{\tt "} (i.e. in vacuo)
+      zenith distance.
+   }
+   \sstinvocation{
+      palRefcoq( double tdk, double pmb, double rh, double wl,
+                 double $*$refa, double $*$refb );
+   }
+   \sstarguments{
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Ambient temperature at the observer (K)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Pressure at the observer (millibar)
+      }
+      \sstsubsection{
+         rh =  double (Given)
+      }{
+         Relative humidity at the observer (range 0-1)
+      }
+      \sstsubsection{
+         wl =  double (Given)
+      }{
+         Effective wavelength of the source (micrometre).
+         Radio refraction is chosen by specifying wl $>$ 100 micrometres.
+      }
+      \sstsubsection{
+         refa = double $*$ (Returned)
+      }{
+         tan Z coefficient (radian)
+      }
+      \sstsubsection{
+         refb = double $*$ (Returned)
+      }{
+         tan$*$$*$3 Z coefficient (radian)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraRefco(). See SOFA/ERFA documentation for details.
+
+         \sstitem
+         Note that the SOFA/ERFA routine uses different order of
+           of arguments and uses deg C rather than K.
+      }
+   }
+}
+
+
+\subsection{More complex functions}
+
+These functions do not have a simple equivalent in SOFA so are
+reimplemented either completely standalone or using multiple
+SOFA functions.
+
+%% Regenerate everything after this from the prologues using SST by
+%% running "make palsun.tex". We do not build this automatically as
+%% there is no particular need for an SST dependency.
+
+%% Some manual tweaking is required after creating the SST tex.
+
+\sstroutine{
+   palAddet
+}{
+   Add the E-terms to a pre IAU 1976 mean place
+}{
+   \sstdescription{
+      Add the E-terms (elliptic component of annual aberration)
+      to a pre IAU 1976 mean place to conform to the old
+      catalogue convention.
+   }
+   \sstinvocation{
+      void palAddet ( double rm, double dm, double eq,
+                      double $*$rc, double $*$dc );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rm = double (Given)
+      }{
+         RA without E-terms (radians)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         Dec without E-terms (radians)
+      }
+      \sstsubsection{
+         eq = double (Given)
+      }{
+         Besselian epoch of mean equator and equinox
+      }
+      \sstsubsection{
+         rc = double $*$ (Returned)
+      }{
+         RA with E-terms included (radians)
+      }
+      \sstsubsection{
+         dc = double $*$ (Returned)
+      }{
+         Dec with E-terms included (radians)
+      }
+   }
+   \sstnotes{
+      Most star positions from pre-1984 optical catalogues (or
+      derived from astrometry using such stars) embody the
+      E-terms.  If it is necessary to convert a formal mean
+      place (for example a pulsar timing position) to one
+      consistent with such a star catalogue, then the RA,Dec
+      should be adjusted using this routine.
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Explanatory Supplement to the Astronomical Ephemeris,
+      section 2D, page 48.
+   }
+}
+\sstroutine{
+   palAirmas
+}{
+   Air mass at given zenith distance
+}{
+   \sstdescription{
+      Calculates the airmass at the observed zenith distance.
+   }
+   \sstinvocation{
+      double palAirmas( double zd );
+   }
+   \sstarguments{
+      \sstsubsection{
+         zd = double (Given)
+      }{
+         Observed zenith distance (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The {\tt "}observed{\tt "} zenith distance referred to above means {\tt "}as
+           affected by refraction{\tt "}.
+
+         \sstitem
+         Uses Hardie{\tt '}s (1962) polynomial fit to Bemporad{\tt '}s data for
+           the relative air mass, X, in units of thickness at the zenith
+           as tabulated by Schoenberg (1929). This is adequate for all
+           normal needs as it is accurate to better than 0.1\% up to X =
+           6.8 and better than 1\% up to X = 10. Bemporad{\tt '}s tabulated
+           values are unlikely to be trustworthy to such accuracy
+           because of variations in density, pressure and other
+           conditions in the atmosphere from those assumed in his work.
+
+         \sstitem
+         The sign of the ZD is ignored.
+
+         \sstitem
+         At zenith distances greater than about ZD = 87 degrees the
+           air mass is held constant to avoid arithmetic overflows.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Hardie, R.H., 1962, in {\tt "}Astronomical Techniques{\tt "}
+             ed. W.A. Hiltner, University of Chicago Press, p180.
+
+         \sstitem
+         Schoenberg, E., 1929, Hdb. d. Ap.,
+             Berlin, Julius Springer, 2, 268.
+      }
+   }
+}
+\sstroutine{
+   palAmp
+}{
+   Convert star RA,Dec from geocentric apparaent to mean place
+}{
+   \sstdescription{
+      Convert star RA,Dec from geocentric apparent to mean place. The
+      mean coordinate system is close to ICRS. See palAmpqk for details.
+   }
+   \sstinvocation{
+      void palAmp ( double ra, double da, double date, double eq,
+                    double $*$rm, double $*$dm );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ra = double (Given)
+      }{
+         Apparent RA (radians)
+      }
+      \sstsubsection{
+         dec = double (Given)
+      }{
+         Apparent Dec (radians)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB for apparent place (JD-2400000.5)
+      }
+      \sstsubsection{
+         eq = double (Given)
+      }{
+         Equinox: Julian epoch of mean place.
+      }
+      \sstsubsection{
+         rm = double $*$ (Returned)
+      }{
+         Mean RA (radians)
+      }
+      \sstsubsection{
+         dm = double $*$ (Returned)
+      }{
+         Mean Dec (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         See palMappa and palAmpqk for details.
+      }
+   }
+}
+\sstroutine{
+   palAmpqk
+}{
+   Convert star RA,Dec from geocentric apparent to mean place
+}{
+   \sstdescription{
+      Convert star RA,Dec from geocentric apparent to mean place. The {\tt "}mean{\tt "}
+      coordinate system is in fact close to ICRS. Use of this function
+      is appropriate when efficiency is important and where many star
+      positions are all to be transformed for one epoch and equinox.  The
+      star-independent parameters can be obtained by calling the palMappa
+      function.
+   }
+   \sstinvocation{
+      void palAmpqk ( double ra, double da, double amprms[21],
+                      double $*$rm, double $*$dm )
+   }
+   \sstarguments{
+      \sstsubsection{
+         ra = double (Given)
+      }{
+         Apparent RA (radians).
+      }
+      \sstsubsection{
+         da = double (Given)
+      }{
+         Apparent Dec (radians).
+      }
+      \sstsubsection{
+         amprms = double[21] (Given)
+      }{
+         Star-independent mean-to-apparent parameters (see palMappa):
+         (0)      time interval for proper motion (Julian years)
+         (1-3)    barycentric position of the Earth (AU)
+         (4-6)    not used
+         (7)      not used
+         (8-10)   abv: barycentric Earth velocity in units of c
+         (11)     sqrt(1-v$*$v) where v=modulus(abv)
+         (12-20)  precession/nutation (3,3) matrix
+      }
+      \sstsubsection{
+         rm = double (Returned)
+      }{
+         Mean RA (radians).
+      }
+      \sstsubsection{
+         dm = double (Returned)
+      }{
+         Mean Dec (radians).
+      }
+   }
+}
+\sstroutine{
+   palAop
+}{
+   Apparent to observed place
+}{
+   \sstdescription{
+      Apparent to observed place for sources distant from the solar system.
+   }
+   \sstinvocation{
+      void palAop ( double rap, double dap, double date, double dut,
+                    double elongm, double phim, double hm, double xp,
+                    double yp, double tdk, double pmb, double rh,
+                    double wl, double tlr,
+                    double $*$aob, double $*$zob, double $*$hob,
+                    double $*$dob, double $*$rob );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rap = double (Given)
+      }{
+         Geocentric apparent right ascension
+      }
+      \sstsubsection{
+         dap = double (Given)
+      }{
+         Geocentirc apparent declination
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         UTC date/time (Modified Julian Date, JD-2400000.5)
+      }
+      \sstsubsection{
+         dut = double (Given)
+      }{
+         delta UT: UT1-UTC (UTC seconds)
+      }
+      \sstsubsection{
+         elongm = double (Given)
+      }{
+         Mean longitude of the observer (radians, east $+$ve)
+      }
+      \sstsubsection{
+         phim = double (Given)
+      }{
+         Mean geodetic latitude of the observer (radians)
+      }
+      \sstsubsection{
+         hm = double (Given)
+      }{
+         Observer{\tt '}s height above sea level (metres)
+      }
+      \sstsubsection{
+         xp = double (Given)
+      }{
+         Polar motion x-coordinates (radians)
+      }
+      \sstsubsection{
+         yp = double (Given)
+      }{
+         Polar motion y-coordinates (radians)
+      }
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Local ambient temperature (K; std=273.15)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Local atmospheric pressure (mb; std=1013.25)
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Local relative humidity (in the range 0.0-1.0)
+      }
+      \sstsubsection{
+         wl = double (Given)
+      }{
+         Effective wavelength (micron, e.g. 0.55)
+      }
+      \sstsubsection{
+         tlr = double (Given)
+      }{
+         Tropospheric laps rate (K/metre, e.g. 0.0065)
+      }
+      \sstsubsection{
+         aob = double $*$ (Returned)
+      }{
+         Observed azimuth (radians: N=0; E=90)
+      }
+      \sstsubsection{
+         zob = double $*$ (Returned)
+      }{
+         Observed zenith distance (radians)
+      }
+      \sstsubsection{
+         hob = double $*$ (Returned)
+      }{
+         Observed Hour Angle (radians)
+      }
+      \sstsubsection{
+         dob = double $*$ (Returned)
+      }{
+         Observed Declination (radians)
+      }
+      \sstsubsection{
+         rob = double $*$ (Returned)
+      }{
+         Observed Right Ascension (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         This routine returns zenith distance rather than elevation
+           in order to reflect the fact that no allowance is made for
+           depression of the horizon.
+
+         \sstitem
+         The accuracy of the result is limited by the corrections for
+           refraction.  Providing the meteorological parameters are
+           known accurately and there are no gross local effects, the
+           predicted apparent RA,Dec should be within about 0.1 arcsec
+           for a zenith distance of less than 70 degrees.  Even at a
+           topocentric zenith distance of 90 degrees, the accuracy in
+           elevation should be better than 1 arcmin;  useful results
+           are available for a further 3 degrees, beyond which the
+           palRefro routine returns a fixed value of the refraction.
+           The complementary routines palAop (or palAopqk) and palOap
+           (or palOapqk) are self-consistent to better than 1 micro-
+           arcsecond all over the celestial sphere.
+
+         \sstitem
+         It is advisable to take great care with units, as even
+           unlikely values of the input parameters are accepted and
+           processed in accordance with the models used.
+
+         \sstitem
+         {\tt "}Apparent{\tt "} place means the geocentric apparent right ascension
+           and declination, which is obtained from a catalogue mean place
+           by allowing for space motion, parallax, precession, nutation,
+           annual aberration, and the Sun{\tt '}s gravitational lens effect.  For
+           star positions in the FK5 system (i.e. J2000), these effects can
+           be applied by means of the palMap etc routines.  Starting from
+           other mean place systems, additional transformations will be
+           needed;  for example, FK4 (i.e. B1950) mean places would first
+           have to be converted to FK5, which can be done with the
+           palFk425 etc routines.
+
+         \sstitem
+         {\tt "}Observed{\tt "} Az,El means the position that would be seen by a
+           perfect theodolite located at the observer.  This is obtained
+           from the geocentric apparent RA,Dec by allowing for Earth
+           orientation and diurnal aberration, rotating from equator
+           to horizon coordinates, and then adjusting for refraction.
+           The HA,Dec is obtained by rotating back into equatorial
+           coordinates, using the geodetic latitude corrected for polar
+           motion, and is the position that would be seen by a perfect
+           equatorial located at the observer and with its polar axis
+           aligned to the Earth{\tt '}s axis of rotation (n.b. not to the
+           refracted pole).  Finally, the RA is obtained by subtracting
+           the HA from the local apparent ST.
+
+         \sstitem
+         To predict the required setting of a real telescope, the
+           observed place produced by this routine would have to be
+           adjusted for the tilt of the azimuth or polar axis of the
+           mounting (with appropriate corrections for mount flexures),
+           for non-perpendicularity between the mounting axes, for the
+           position of the rotator axis and the pointing axis relative
+           to it, for tube flexure, for gear and encoder errors, and
+           finally for encoder zero points.  Some telescopes would, of
+           course, exhibit other properties which would need to be
+           accounted for at the appropriate point in the sequence.
+
+         \sstitem
+         This routine takes time to execute, due mainly to the
+           rigorous integration used to evaluate the refraction.
+           For processing multiple stars for one location and time,
+           call palAoppa once followed by one call per star to palAopqk.
+           Where a range of times within a limited period of a few hours
+           is involved, and the highest precision is not required, call
+           palAoppa once, followed by a call to palAoppat each time the
+           time changes, followed by one call per star to palAopqk.
+
+         \sstitem
+         The DATE argument is UTC expressed as an MJD.  This is,
+           strictly speaking, wrong, because of leap seconds.  However,
+           as long as the delta UT and the UTC are consistent there
+           are no difficulties, except during a leap second.  In this
+           case, the start of the 61st second of the final minute should
+           begin a new MJD day and the old pre-leap delta UT should
+           continue to be used.  As the 61st second completes, the MJD
+           should revert to the start of the day as, simultaneously,
+           the delta UTC changes by one second to its post-leap new value.
+
+         \sstitem
+         The delta UT (UT1-UTC) is tabulated in IERS circulars and
+           elsewhere.  It increases by exactly one second at the end of
+           each UTC leap second, introduced in order to keep delta UT
+           within $+$/- 0.9 seconds.
+
+         \sstitem
+         IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+           The longitude required by the present routine is east-positive,
+           in accordance with geographical convention (and right-handed).
+           In particular, note that the longitudes returned by the
+           palObs routine are west-positive, following astronomical
+           usage, and must be reversed in sign before use in the present
+           routine.
+
+         \sstitem
+         The polar coordinates XP,YP can be obtained from IERS
+           circulars and equivalent publications.  The maximum amplitude
+           is about 0.3 arcseconds.  If XP,YP values are unavailable,
+           use XP=YP=0.0.  See page B60 of the 1988 Astronomical Almanac
+           for a definition of the two angles.
+
+         \sstitem
+         The height above sea level of the observing station, HM,
+           can be obtained from the Astronomical Almanac (Section J
+           in the 1988 edition), or via the routine palObs.  If P,
+           the pressure in millibars, is available, an adequate
+           estimate of HM can be obtained from the expression
+
+      }
+              HM $\sim$ -29.3$*$TSL$*$LOG(P/1013.25).
+
+        where TSL is the approximate sea-level air temperature in K
+        (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+        section 52).  Similarly, if the pressure P is not known,
+        it can be estimated from the height of the observing
+        station, HM, as follows:
+
+              P $\sim$ 1013.25$*$EXP(-HM/(29.3$*$TSL)).
+
+        Note, however, that the refraction is nearly proportional to the
+        pressure and that an accurate P value is important for precise
+        work.
+
+      \sstitemlist{
+
+         \sstitem
+         The azimuths etc produced by the present routine are with
+           respect to the celestial pole.  Corrections to the terrestrial
+           pole can be computed using palPolmo.
+      }
+   }
+}
+\sstroutine{
+   palAoppa
+}{
+   Precompute apparent to observed place parameters
+}{
+   \sstdescription{
+      Precompute apparent to observed place parameters required by palAopqk
+      and palOapqk.
+   }
+   \sstinvocation{
+      void palAoppa ( double date, double dut, double elongm, double phim,
+                      double hm, double xp, double yp, double tdk, double pmb,
+                      double rh, double wl, double tlr, double aoprms[14] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         UTC date/time (modified Julian Date, JD-2400000.5)
+      }
+      \sstsubsection{
+         dut = double (Given)
+      }{
+         delta UT:  UT1-UTC (UTC seconds)
+      }
+      \sstsubsection{
+         elongm = double (Given)
+      }{
+         mean longitude of the observer (radians, east $+$ve)
+      }
+      \sstsubsection{
+         phim = double (Given)
+      }{
+         mean geodetic latitude of the observer (radians)
+      }
+      \sstsubsection{
+         hm = double (Given)
+      }{
+         observer{\tt '}s height above sea level (metres)
+      }
+      \sstsubsection{
+         xp = double (Given)
+      }{
+         polar motion x-coordinate (radians)
+      }
+      \sstsubsection{
+         yp = double (Given)
+      }{
+         polar motion y-coordinate (radians)
+      }
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         local ambient temperature (K; std=273.15)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         local atmospheric pressure (mb; std=1013.25)
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         local relative humidity (in the range 0.0-1.0)
+      }
+      \sstsubsection{
+         wl = double (Given)
+      }{
+         effective wavelength (micron, e.g. 0.55)
+      }
+      \sstsubsection{
+         tlr = double (Given)
+      }{
+         tropospheric lapse rate (K/metre, e.g. 0.0065)
+      }
+      \sstsubsection{
+         aoprms = double [14] (Returned)
+      }{
+         Star-independent apparent-to-observed parameters
+
+          (0)      geodetic latitude (radians)
+          (1,2)    sine and cosine of geodetic latitude
+          (3)      magnitude of diurnal aberration vector
+          (4)      height (hm)
+          (5)      ambient temperature (tdk)
+          (6)      pressure (pmb)
+          (7)      relative humidity (rh)
+          (8)      wavelength (wl)
+          (9)     lapse rate (tlr)
+          (10,11)  refraction constants A and B (radians)
+          (12)     longitude $+$ eqn of equinoxes $+$ sidereal DUT (radians)
+          (13)     local apparent sidereal time (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         It is advisable to take great care with units, as even
+           unlikely values of the input parameters are accepted and
+           processed in accordance with the models used.
+
+         \sstitem
+         The DATE argument is UTC expressed as an MJD.  This is,
+           strictly speaking, improper, because of leap seconds.  However,
+           as long as the delta UT and the UTC are consistent there
+           are no difficulties, except during a leap second.  In this
+           case, the start of the 61st second of the final minute should
+           begin a new MJD day and the old pre-leap delta UT should
+           continue to be used.  As the 61st second completes, the MJD
+           should revert to the start of the day as, simultaneously,
+           the delta UTC changes by one second to its post-leap new value.
+
+         \sstitem
+         The delta UT (UT1-UTC) is tabulated in IERS circulars and
+           elsewhere.  It increases by exactly one second at the end of
+           each UTC leap second, introduced in order to keep delta UT
+           within $+$/- 0.9 seconds.
+
+         \sstitem
+         IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+           The longitude required by the present routine is east-positive,
+           in accordance with geographical convention (and right-handed).
+           In particular, note that the longitudes returned by the
+           palObs routine are west-positive, following astronomical
+           usage, and must be reversed in sign before use in the present
+           routine.
+
+         \sstitem
+         The polar coordinates XP,YP can be obtained from IERS
+           circulars and equivalent publications.  The maximum amplitude
+           is about 0.3 arcseconds.  If XP,YP values are unavailable,
+           use XP=YP=0.0.  See page B60 of the 1988 Astronomical Almanac
+           for a definition of the two angles.
+
+         \sstitem
+         The height above sea level of the observing station, HM,
+           can be obtained from the Astronomical Almanac (Section J
+           in the 1988 edition), or via the routine palObs.  If P,
+           the pressure in millibars, is available, an adequate
+           estimate of HM can be obtained from the expression
+
+      }
+              HM $\sim$ -29.3$*$TSL$*$log(P/1013.25).
+
+        where TSL is the approximate sea-level air temperature in K
+        (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+        section 52).  Similarly, if the pressure P is not known,
+        it can be estimated from the height of the observing
+        station, HM, as follows:
+
+              P $\sim$ 1013.25$*$exp(-HM/(29.3$*$TSL)).
+
+        Note, however, that the refraction is nearly proportional to the
+        pressure and that an accurate P value is important for precise
+        work.
+
+      \sstitemlist{
+
+         \sstitem
+         Repeated, computationally-expensive, calls to palAoppa for
+           times that are very close together can be avoided by calling
+           palAoppa just once and then using palAoppat for the subsequent
+           times.  Fresh calls to palAoppa will be needed only when
+           changes in the precession have grown to unacceptable levels or
+           when anything affecting the refraction has changed.
+      }
+   }
+}
+\sstroutine{
+   palAoppat
+}{
+   Recompute sidereal time to support apparent to observed place
+}{
+   \sstdescription{
+      This routine recomputes the sidereal time in the apparent to
+      observed place star-independent parameter block.
+   }
+   \sstinvocation{
+      void palAoppat( double date, double aoprms[14] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         UTC date/time (modified Julian Date, JD-2400000.5)
+         (see palAoppa description for comments on leap seconds)
+      }
+      \sstsubsection{
+         aoprms = double[14] (Given \& Returned)
+      }{
+         Star-independent apparent-to-observed parameters. Updated
+         by this routine. Requires element 12 to be the longitude $+$
+         eqn of equinoxes $+$ sidereal DUT and fills in element 13
+         with the local apparent sidereal time (in radians).
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         See palAoppa for more information.
+
+         \sstitem
+         The star-independent parameters are not treated as an opaque
+           struct in order to retain compatibility with SLA.
+      }
+   }
+}
+\sstroutine{
+   palAopqk
+}{
+   Quick apparent to observed place
+}{
+   \sstdescription{
+      Quick apparent to observed place.
+   }
+   \sstinvocation{
+      void palAopqk ( double rap, double dap, const double aoprms[14],
+                      double $*$aob, double $*$zob, double $*$hob,
+                      double $*$dob, double $*$rob );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rap = double (Given)
+      }{
+         Geocentric apparent right ascension
+      }
+      \sstsubsection{
+         dap = double (Given)
+      }{
+         Geocentric apparent declination
+      }
+      \sstsubsection{
+         aoprms = const double [14] (Given)
+      }{
+         Star-independent apparent-to-observed parameters.
+
+          [0]      geodetic latitude (radians)
+          [1,2]    sine and cosine of geodetic latitude
+          [3]      magnitude of diurnal aberration vector
+          [4]      height (HM)
+          [5]      ambient temperature (T)
+          [6]      pressure (P)
+          [7]      relative humidity (RH)
+          [8]      wavelength (WL)
+          [9]      lapse rate (TLR)
+          [10,11]  refraction constants A and B (radians)
+          [12]     longitude $+$ eqn of equinoxes $+$ sidereal DUT (radians)
+          [13]     local apparent sidereal time (radians)
+      }
+      \sstsubsection{
+         aob = double $*$ (Returned)
+      }{
+         Observed azimuth (radians: N=0,E=90)
+      }
+      \sstsubsection{
+         zob = double $*$ (Returned)
+      }{
+         Observed zenith distance (radians)
+      }
+      \sstsubsection{
+         hob = double $*$ (Returned)
+      }{
+         Observed Hour Angle (radians)
+      }
+      \sstsubsection{
+         dob = double $*$ (Returned)
+      }{
+         Observed Declination (radians)
+      }
+      \sstsubsection{
+         rob = double $*$ (Returned)
+      }{
+         Observed Right Ascension (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         This routine returns zenith distance rather than elevation
+           in order to reflect the fact that no allowance is made for
+           depression of the horizon.
+
+         \sstitem
+         The accuracy of the result is limited by the corrections for
+           refraction.  Providing the meteorological parameters are
+           known accurately and there are no gross local effects, the
+           observed RA,Dec predicted by this routine should be within
+           about 0.1 arcsec for a zenith distance of less than 70 degrees.
+           Even at a topocentric zenith distance of 90 degrees, the
+           accuracy in elevation should be better than 1 arcmin;  useful
+           results are available for a further 3 degrees, beyond which
+           the palRefro routine returns a fixed value of the refraction.
+           The complementary routines palAop (or palAopqk) and palOap
+           (or palOapqk) are self-consistent to better than 1 micro-
+           arcsecond all over the celestial sphere.
+
+         \sstitem
+         It is advisable to take great care with units, as even
+           unlikely values of the input parameters are accepted and
+           processed in accordance with the models used.
+
+         \sstitem
+         {\tt "}Apparent{\tt "} place means the geocentric apparent right ascension
+           and declination, which is obtained from a catalogue mean place
+           by allowing for space motion, parallax, precession, nutation,
+           annual aberration, and the Sun{\tt '}s gravitational lens effect.  For
+           star positions in the FK5 system (i.e. J2000), these effects can
+           be applied by means of the palMap etc routines.  Starting from
+           other mean place systems, additional transformations will be
+           needed;  for example, FK4 (i.e. B1950) mean places would first
+           have to be converted to FK5, which can be done with the
+           palFk425 etc routines.
+
+         \sstitem
+         {\tt "}Observed{\tt "} Az,El means the position that would be seen by a
+           perfect theodolite located at the observer.  This is obtained
+           from the geocentric apparent RA,Dec by allowing for Earth
+           orientation and diurnal aberration, rotating from equator
+           to horizon coordinates, and then adjusting for refraction.
+           The HA,Dec is obtained by rotating back into equatorial
+           coordinates, using the geodetic latitude corrected for polar
+           motion, and is the position that would be seen by a perfect
+           equatorial located at the observer and with its polar axis
+           aligned to the Earth{\tt '}s axis of rotation (n.b. not to the
+           refracted pole).  Finally, the RA is obtained by subtracting
+           the HA from the local apparent ST.
+
+         \sstitem
+         To predict the required setting of a real telescope, the
+           observed place produced by this routine would have to be
+           adjusted for the tilt of the azimuth or polar axis of the
+           mounting (with appropriate corrections for mount flexures),
+           for non-perpendicularity between the mounting axes, for the
+           position of the rotator axis and the pointing axis relative
+           to it, for tube flexure, for gear and encoder errors, and
+           finally for encoder zero points.  Some telescopes would, of
+           course, exhibit other properties which would need to be
+           accounted for at the appropriate point in the sequence.
+
+         \sstitem
+         The star-independent apparent-to-observed-place parameters
+           in AOPRMS may be computed by means of the palAoppa routine.
+           If nothing has changed significantly except the time, the
+           palAoppat routine may be used to perform the requisite
+           partial recomputation of AOPRMS.
+
+         \sstitem
+         At zenith distances beyond about 76 degrees, the need for
+           special care with the corrections for refraction causes a
+           marked increase in execution time.  Moreover, the effect
+           gets worse with increasing zenith distance.  Adroit
+           programming in the calling application may allow the
+           problem to be reduced.  Prepare an alternative AOPRMS array,
+           computed for zero air-pressure;  this will disable the
+           refraction corrections and cause rapid execution.  Using
+           this AOPRMS array, a preliminary call to the present routine
+           will, depending on the application, produce a rough position
+           which may be enough to establish whether the full, slow
+           calculation (using the real AOPRMS array) is worthwhile.
+           For example, there would be no need for the full calculation
+           if the preliminary call had already established that the
+           source was well below the elevation limits for a particular
+           telescope.
+
+         \sstitem
+         The azimuths etc produced by the present routine are with
+           respect to the celestial pole.  Corrections to the terrestrial
+           pole can be computed using palPolmo.
+      }
+   }
+}
+\sstroutine{
+   palAtmdsp
+}{
+   Apply atmospheric-dispersion adjustments to refraction coefficients
+}{
+   \sstdescription{
+      Apply atmospheric-dispersion adjustments to refraction coefficients.
+   }
+   \sstinvocation{
+      void palAtmdsp( double tdk, double pmb, double rh, double wl1,
+                      double a1, double b1, double wl2, double $*$a2, double $*$b2 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Ambient temperature, K
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Ambient pressure, millibars
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Ambient relative humidity, 0-1
+      }
+      \sstsubsection{
+         wl1 = double (Given)
+      }{
+         Reference wavelength, micrometre (0.4 recommended)
+      }
+      \sstsubsection{
+         a1 = double (Given)
+      }{
+         Refraction coefficient A for wavelength wl1 (radians)
+      }
+      \sstsubsection{
+         b1 = double (Given)
+      }{
+         Refraction coefficient B for wavelength wl1 (radians)
+      }
+      \sstsubsection{
+         wl2 = double (Given)
+      }{
+         Wavelength for which adjusted A,B required
+      }
+      \sstsubsection{
+         a2 = double $*$ (Returned)
+      }{
+         Refraction coefficient A for wavelength WL2 (radians)
+      }
+      \sstsubsection{
+         b2 = double $*$ (Returned)
+      }{
+         Refraction coefficient B for wavelength WL2 (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         To use this routine, first call palRefco specifying WL1 as the
+         wavelength.  This yields refraction coefficients A1,B1, correct
+         for that wavelength.  Subsequently, calls to palAtmdsp specifying
+         different wavelengths will produce new, slightly adjusted
+         refraction coefficients which apply to the specified wavelength.
+
+         \sstitem
+         Most of the atmospheric dispersion happens between 0.7 micrometre
+         and the UV atmospheric cutoff, and the effect increases strongly
+         towards the UV end.  For this reason a blue reference wavelength
+         is recommended, for example 0.4 micrometres.
+
+         \sstitem
+         The accuracy, for this set of conditions:
+
+      }
+         height above sea level    2000 m
+                       latitude    29 deg
+                       pressure    793 mb
+                    temperature    17 degC
+                       humidity    50\%
+                     lapse rate    0.0065 degC/m
+           reference wavelength    0.4 micrometre
+                 star elevation    15 deg
+
+      is about 2.5 mas RMS between 0.3 and 1.0 micrometres, and stays
+      within 4 mas for the whole range longward of 0.3 micrometres
+      (compared with a total dispersion from 0.3 to 20.0 micrometres
+      of about 11 arcsec).  These errors are typical for ordinary
+      conditions and the given elevation;  in extreme conditions values
+      a few times this size may occur, while at higher elevations the
+      errors become much smaller.
+
+      \sstitemlist{
+
+         \sstitem
+         If either wavelength exceeds 100 micrometres, the radio case
+         is assumed and the returned refraction coefficients are the
+         same as the given ones.  Note that radio refraction coefficients
+         cannot be turned into optical values using this routine, nor
+         vice versa.
+
+         \sstitem
+         The algorithm consists of calculation of the refractivity of the
+         air at the observer for the two wavelengths, using the methods
+         of the palRefro routine, and then scaling of the two refraction
+         coefficients according to classical refraction theory.  This
+         amounts to scaling the A coefficient in proportion to (n-1) and
+         the B coefficient almost in the same ratio (see R.M.Green,
+         {\tt "}Spherical Astronomy{\tt "}, Cambridge University Press, 1985).
+      }
+   }
+}
+\sstroutine{
+   palCaldj
+}{
+   Gregorian Calendar to Modified Julian Date
+}{
+   \sstdescription{
+      Modified Julian Date to Gregorian Calendar with special
+      behaviour for 2-digit years relating to 1950 to 2049.
+   }
+   \sstinvocation{
+      void palCaldj ( int iy, int im, int id, double $*$djm, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         iy = int (Given)
+      }{
+         Year in the Gregorian calendar
+      }
+      \sstsubsection{
+         im = int (Given)
+      }{
+         Month in the Gergorian calendar
+      }
+      \sstsubsection{
+         id = int (Given)
+      }{
+         Day in the Gregorian calendar
+      }
+      \sstsubsection{
+         djm = double $*$ (Returned)
+      }{
+         Modified Julian Date (JD-2400000.5) for 0 hrs
+      }
+      \sstsubsection{
+         j = status (Returned)
+      }{
+         0 = OK. See eraCal2jd for other values.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraCal2jd
+
+         \sstitem
+         Unlike eraCal2jd this routine treats the years 0-100 as
+           referring to the end of the 20th Century and beginning of
+           the 21st Century. If this behaviour is not acceptable
+           use the SOFA/ERFA routine directly or palCldj.
+           Acceptable years are 00-49, interpreted as 2000-2049,
+                                50-99,     {\tt "}       {\tt "}  1950-1999,
+                                all others, interpreted literally.
+
+         \sstitem
+         Unlike SLA this routine will work with negative years.
+      }
+   }
+}
+\sstroutine{
+   palDafin
+}{
+   Sexagesimal character string to angle
+}{
+   \sstdescription{
+      Extracts an angle from a sexagesimal string with degrees, arcmin,
+      arcsec fields using space or comma delimiters.
+   }
+   \sstinvocation{
+      void palDafin ( const char $*$string, int $*$ipos, double $*$a, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         string = const char $*$ (Given)
+      }{
+         String containing deg, arcmin, arcsec fields
+      }
+      \sstsubsection{
+         ipos = int $*$ (Given \& Returned)
+      }{
+         Position to start decoding {\tt "}string{\tt "}. First character
+         is position 1 for compatibility with SLA. After
+         calling this routine {\tt "}iptr{\tt "} will be positioned after
+         the sexagesimal string.
+      }
+      \sstsubsection{
+         a = double $*$ (Returned)
+      }{
+         Angle in radians.
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         status:  0 = OK
+                 $+$1 = default, A unchanged
+         \sstitemlist{
+
+            \sstitem
+                    1 = bad degrees      )
+
+            \sstitem
+                    2 = bad arcminutes   )  (note 3)
+
+            \sstitem
+                    3 = bad arcseconds   )
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The first three {\tt "}fields{\tt "} in STRING are degrees, arcminutes,
+           arcseconds, separated by spaces or commas.  The degrees field
+           may be signed, but not the others.  The decoding is carried
+           out by the palDfltin routine and is free-format.
+
+         \sstitem
+         Successive fields may be absent, defaulting to zero.  For
+           zero status, the only combinations allowed are degrees alone,
+           degrees and arcminutes, and all three fields present.  If all
+           three fields are omitted, a status of $+$1 is returned and A is
+           unchanged.  In all other cases A is changed.
+
+         \sstitem
+         Range checking:
+
+      }
+            The degrees field is not range checked.  However, it is
+            expected to be integral unless the other two fields are absent.
+
+            The arcminutes field is expected to be 0-59, and integral if
+            the arcseconds field is present.  If the arcseconds field
+            is absent, the arcminutes is expected to be 0-59.9999...
+
+            The arcseconds field is expected to be 0-59.9999...
+
+      \sstitemlist{
+
+         \sstitem
+         Decoding continues even when a check has failed.  Under these
+           circumstances the field takes the supplied value, defaulting
+           to zero, and the result A is computed and returned.
+
+         \sstitem
+         Further fields after the three expected ones are not treated
+           as an error.  The pointer IPOS is left in the correct state
+           for further decoding with the present routine or with palDfltin
+           etc. See the example, above.
+
+         \sstitem
+         If STRING contains hours, minutes, seconds instead of degrees
+           etc, or if the required units are turns (or days) instead of
+           radians, the result A should be multiplied as follows:
+
+      }
+            for        to obtain    multiply
+            STRING     A in         A by
+
+            d {\tt '} {\tt "}      radians      1       =  1.0
+            d {\tt '} {\tt "}      turns        1/2pi   =  0.1591549430918953358
+            h m s      radians      15      =  15.0
+            h m s      days         15/2pi  =  2.3873241463784300365
+   }
+   \sstdiytopic{
+      Example
+   }{
+      argument    before                           after
+
+      STRING      {\tt '}-57 17 44.806  12 34 56.7{\tt '}      unchanged
+      IPTR        1                                16 (points to 12...)
+      A           ?                                -1.00000D0
+      J           ?                                0
+   }
+}
+\sstroutine{
+   palDe2h
+}{
+   Equatorial to horizon coordinates: HA,Dec to Az,E
+}{
+   \sstdescription{
+      Convert equatorial to horizon coordinates.
+   }
+   \sstinvocation{
+      palDe2h( double ha, double dec, double phi, double $*$ az, double $*$ el );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ha = double $*$ (Given)
+      }{
+         Hour angle (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Given)
+      }{
+         Declination (radians)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observatory latitude (radians)
+      }
+      \sstsubsection{
+         az = double $*$ (Returned)
+      }{
+         Azimuth (radians)
+      }
+      \sstsubsection{
+         el = double $*$ (Returned)
+      }{
+         Elevation (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         All the arguments are angles in radians.
+
+         \sstitem
+         Azimuth is returned in the range 0-2pi;  north is zero,
+           and east is $+$pi/2.  Elevation is returned in the range
+           $+$/-pi/2.
+
+         \sstitem
+         The latitude must be geodetic.  In critical applications,
+           corrections for polar motion should be applied.
+
+         \sstitem
+         In some applications it will be important to specify the
+           correct type of hour angle and declination in order to
+           produce the required type of azimuth and elevation.  In
+           particular, it may be important to distinguish between
+           elevation as affected by refraction, which would
+           require the {\tt "}observed{\tt "} HA,Dec, and the elevation
+           in vacuo, which would require the {\tt "}topocentric{\tt "} HA,Dec.
+           If the effects of diurnal aberration can be neglected, the
+           {\tt "}apparent{\tt "} HA,Dec may be used instead of the topocentric
+           HA,Dec.
+
+         \sstitem
+         No range checking of arguments is carried out.
+
+         \sstitem
+         In applications which involve many such calculations, rather
+           than calling the present routine it will be more efficient to
+           use inline code, having previously computed fixed terms such
+           as sine and cosine of latitude, and (for tracking a star)
+           sine and cosine of declination.
+      }
+   }
+}
+\sstroutine{
+   palDeuler
+}{
+   Form a rotation matrix from the Euler angles
+}{
+   \sstdescription{
+      A rotation is positive when the reference frame rotates
+      anticlockwise as seen looking towards the origin from the
+      positive region of the specified axis.
+
+      The characters of ORDER define which axes the three successive
+      rotations are about.  A typical value is {\tt '}ZXZ{\tt '}, indicating that
+      RMAT is to become the direction cosine matrix corresponding to
+      rotations of the reference frame through PHI radians about the
+      old Z-axis, followed by THETA radians about the resulting X-axis,
+      then PSI radians about the resulting Z-axis.
+
+      The axis names can be any of the following, in any order or
+      combination:  X, Y, Z, uppercase or lowercase, 1, 2, 3.  Normal
+      axis labelling/numbering conventions apply;  the xyz (=123)
+      triad is right-handed.  Thus, the {\tt '}ZXZ{\tt '} example given above
+      could be written {\tt '}zxz{\tt '} or {\tt '}313{\tt '} (or even {\tt '}ZxZ{\tt '} or {\tt '}3xZ{\tt '}).  ORDER
+      is terminated by length or by the first unrecognized character.
+
+      Fewer than three rotations are acceptable, in which case the later
+      angle arguments are ignored.  If all rotations are zero, the
+      identity matrix is produced.
+   }
+   \sstinvocation{
+      void palDeuler ( const char $*$order, double phi, double theta, double psi,
+                       double rmat[3][3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         order = const char[] (Given)
+      }{
+         Specifies about which axes the rotation occurs
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         1st rotation (radians)
+      }
+      \sstsubsection{
+         theta = double (Given)
+      }{
+         2nd rotation (radians)
+      }
+      \sstsubsection{
+         psi = double (Given)
+      }{
+         3rd rotation (radians)
+      }
+      \sstsubsection{
+         rmat = double[3][3] (Given \& Returned)
+      }{
+         Rotation matrix
+      }
+   }
+}
+\sstroutine{
+   palDfltin
+}{
+   Convert free-format input into double precision floating point
+}{
+   \sstdescription{
+      Extracts a number from an input string starting at the specified
+      index.
+   }
+   \sstinvocation{
+      void palDfltin( const char $*$ string, int $*$nstrt,
+                      double $*$dreslt, int $*$jflag );
+   }
+   \sstarguments{
+      \sstsubsection{
+         string = const char $*$ (Given)
+      }{
+         String containing number to be decoded.
+      }
+      \sstsubsection{
+         nstrt = int $*$ (Given and Returned)
+      }{
+         Character number indicating where decoding should start.
+         On output its value is updated to be the location of the
+         possible next value. For compatibility with SLA the first
+         character is index 1.
+      }
+      \sstsubsection{
+         dreslt = double $*$ (Returned)
+      }{
+         Result. Not updated when jflag=1.
+      }
+      \sstsubsection{
+         jflag = int $*$ (Returned)
+      }{
+         status: -1 = -OK, 0 = $+$OK, 1 = null, 2 = error
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses the strtod() system call to do the parsing. This may lead to
+           subtle differences when compared to the SLA/F parsing.
+
+         \sstitem
+         All {\tt "}D{\tt "} characters are converted to {\tt "}E{\tt "} to handle fortran exponents.
+
+         \sstitem
+         Commas are recognized as a special case and are skipped if one happens
+           to be the next character when updating nstrt. Additionally the output
+           nstrt position will skip past any trailing space.
+
+         \sstitem
+         If no number can be found flag will be set to 1.
+
+         \sstitem
+         If the number overflows or underflows jflag will be set to 2. For overflow
+           the returned result will have the value HUGE\_VAL, for underflow it
+           will have the value 0.0.
+
+         \sstitem
+         For compatiblity with SLA/F -0 will be returned as {\tt "}0{\tt "} with jflag == -1.
+
+         \sstitem
+         Unlike slaDfltin a standalone {\tt "}E{\tt "} will return status 1 (could not find
+           a number) rather than 2 (bad number).
+      }
+   }
+   \sstimplementationstatus{
+      \sstitemlist{
+
+         \sstitem
+         The code is more robust if the C99 copysign() function is available.
+         This can recognize the -0.0 values returned by strtod. If copysign() is
+         missing we try to scan the string looking for minus signs.
+      }
+   }
+}
+\sstroutine{
+   palDh2e
+}{
+   Horizon to equatorial coordinates: Az,El to HA,Dec
+}{
+   \sstdescription{
+      Convert horizon to equatorial coordinates.
+   }
+   \sstinvocation{
+      palDh2e( double az, double el, double phi, double $*$ ha, double $*$ dec );
+   }
+   \sstarguments{
+      \sstsubsection{
+         az = double (Given)
+      }{
+         Azimuth (radians)
+      }
+      \sstsubsection{
+         el = double (Given)
+      }{
+         Elevation (radians)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observatory latitude (radians)
+      }
+      \sstsubsection{
+         ha = double $*$ (Returned)
+      }{
+         Hour angle (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Declination (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         All the arguments are angles in radians.
+
+         \sstitem
+         The sign convention for azimuth is north zero, east $+$pi/2.
+
+         \sstitem
+         HA is returned in the range $+$/-pi.  Declination is returned
+           in the range $+$/-pi/2.
+
+         \sstitem
+         The latitude is (in principle) geodetic.  In critical
+           applications, corrections for polar motion should be applied.
+
+         \sstitem
+         In some applications it will be important to specify the
+           correct type of elevation in order to produce the required
+           type of HA,Dec.  In particular, it may be important to
+           distinguish between the elevation as affected by refraction,
+           which will yield the {\tt "}observed{\tt "} HA,Dec, and the elevation
+           in vacuo, which will yield the {\tt "}topocentric{\tt "} HA,Dec.  If the
+           effects of diurnal aberration can be neglected, the
+           topocentric HA,Dec may be used as an approximation to the
+           {\tt "}apparent{\tt "} HA,Dec.
+
+         \sstitem
+         No range checking of arguments is done.
+
+         \sstitem
+         In applications which involve many such calculations, rather
+           than calling the present routine it will be more efficient to
+           use inline code, having previously computed fixed terms such
+           as sine and cosine of latitude.
+      }
+   }
+}
+\sstroutine{
+   palDjcal
+}{
+   Modified Julian Date to Gregorian Calendar
+}{
+   \sstdescription{
+      Modified Julian Date to Gregorian Calendar, expressed
+      in a form convenient for formatting messages (namely
+      rounded to a specified precision, and with the fields
+      stored in a single array)
+   }
+   \sstinvocation{
+      void palDjcal ( int ndp, double djm, int iymdf[4], int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ndp = int (Given)
+      }{
+         Number of decimal places of days in fraction.
+      }
+      \sstsubsection{
+         djm = double (Given)
+      }{
+         Modified Julian Date (JD-2400000.5)
+      }
+      \sstsubsection{
+         iymdf[4] = int[] (Returned)
+      }{
+         Year, month, day, fraction in Gregorian calendar.
+      }
+      \sstsubsection{
+         j = status (Returned)
+      }{
+         0 = OK. See eraJd2cal for other values.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraJd2cal
+      }
+   }
+}
+\sstroutine{
+   palDmat
+}{
+   Matrix inversion \& solution of simultaneous equations
+}{
+   \sstdescription{
+      Matrix inversion \& solution of simultaneous equations
+      For the set of n simultaneous equations in n unknowns:
+           A.Y = X
+      this routine calculates the inverse of A, the determinant
+      of matrix A and the vector of N unknowns.
+   }
+   \sstinvocation{
+      void palDmat( int n, double $*$a, double $*$y, double $*$d, int $*$jf,
+                     int $*$iw );
+   }
+   \sstarguments{
+      \sstsubsection{
+         n = int (Given)
+      }{
+         Number of simultaneous equations and number of unknowns.
+      }
+      \sstsubsection{
+         a = double[] (Given \& Returned)
+      }{
+         A non-singular NxN matrix (implemented as a contiguous block
+         of memory). After calling this routine {\tt "}a{\tt "} contains the
+         inverse of the matrix.
+      }
+      \sstsubsection{
+         y = double[] (Given \& Returned)
+      }{
+         On input the vector of N knowns. On exit this vector contains the
+         N solutions.
+      }
+      \sstsubsection{
+         d = double $*$ (Returned)
+      }{
+         The determinant.
+      }
+      \sstsubsection{
+         jf = int $*$ (Returned)
+      }{
+         The singularity flag.  If the matrix is non-singular, jf=0
+         is returned.  If the matrix is singular, jf=-1 \& d=0.0 are
+         returned.  In the latter case, the contents of array {\tt "}a{\tt "} on
+         return are undefined.
+      }
+      \sstsubsection{
+         iw = int[] (Given)
+      }{
+         Integer workspace of size N.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Implemented using Gaussian elimination with partial pivoting.
+
+         \sstitem
+         Optimized for speed rather than accuracy with errors 1 to 4
+           times those of routines optimized for accuracy.
+      }
+   }
+}
+\sstroutine{
+   palDs2tp
+}{
+   Spherical to tangent plane projection
+}{
+   \sstdescription{
+      Projection of spherical coordinates onto tangent plane:
+      {\tt "}gnomonic{\tt "} projection - {\tt "}standard coordinates{\tt "}
+   }
+   \sstinvocation{
+      palDs2tp( double ra, double dec, double raz, double decz,
+                double $*$xi, double $*$eta, int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ra = double (Given)
+      }{
+         RA spherical coordinate of point to be projected (radians)
+      }
+      \sstsubsection{
+         dec = double (Given)
+      }{
+         Dec spherical coordinate of point to be projected (radians)
+      }
+      \sstsubsection{
+         raz = double (Given)
+      }{
+         RA spherical coordinate of tangent point (radians)
+      }
+      \sstsubsection{
+         decz = double (Given)
+      }{
+         Dec spherical coordinate of tangent point (radians)
+      }
+      \sstsubsection{
+         xi = double $*$ (Returned)
+      }{
+         First rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         eta = double $*$ (Returned)
+      }{
+         Second rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         status: 0 = OK, star on tangent plane
+                 1 = error, star too far from axis
+                 2 = error, antistar on tangent plane
+                 3 = error, antistar too far from axis
+      }
+   }
+}
+\sstroutine{
+   palDat
+}{
+   Return offset between UTC and TAI
+}{
+   \sstdescription{
+      Increment to be applied to Coordinated Universal Time UTC to give
+      International Atomic Time (TAI).
+   }
+   \sstinvocation{
+      dat = palDat( double utc );
+   }
+   \sstarguments{
+      \sstsubsection{
+         utc = double (Given)
+      }{
+         UTC date as a modified JD (JD-2400000.5)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         dat = double
+      }{
+         TAI-UTC in seconds
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         This routine converts the MJD argument to calendar date before calling
+           the SOFA/ERFA eraDat function.
+
+         \sstitem
+         This routine matches the slaDat interface which differs from the eraDat
+           interface. Consider coding directly to the SOFA/ERFA interface.
+
+         \sstitem
+         See eraDat for a description of error conditions when calling this function
+           with a time outside of the UTC range.
+
+         \sstitem
+         The status argument from eraDat is ignored. This is reasonable since the
+           error codes are mainly related to incorrect calendar dates when calculating
+           the JD internally.
+      }
+   }
+}
+\sstroutine{
+   palDmoon
+}{
+   Approximate geocentric position and velocity of the Moon
+}{
+   \sstdescription{
+      Calculate the approximate geocentric position of the Moon
+      using a full implementation of the algorithm published by
+      Meeus (l{\tt '}Astronomie, June 1984, p348).
+   }
+   \sstinvocation{
+      void palDmoon( double date, double pv[6] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB as a Modified Julian Date (JD-2400000.5)
+      }
+      \sstsubsection{
+         pv = double [6] (Returned)
+      }{
+         Moon x,y,z,xdot,ydot,zdot, mean equator and
+         equinox of date (AU, AU/s)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Meeus quotes accuracies of 10 arcsec in longitude, 3 arcsec in
+           latitude and 0.2 arcsec in HP (equivalent to about 20 km in
+           distance).  Comparison with JPL DE200 over the interval
+           1960-2025 gives RMS errors of 3.7 arcsec and 83 mas/hour in
+           longitude, 2.3 arcsec and 48 mas/hour in latitude, 11 km
+           and 81 mm/s in distance.  The maximum errors over the same
+           interval are 18 arcsec and 0.50 arcsec/hour in longitude,
+           11 arcsec and 0.24 arcsec/hour in latitude, 40 km and 0.29 m/s
+           in distance.
+
+         \sstitem
+         The original algorithm is expressed in terms of the obsolete
+           timescale Ephemeris Time.  Either TDB or TT can be used, but
+           not UT without incurring significant errors (30 arcsec at
+           the present time) due to the Moon{\tt '}s 0.5 arcsec/sec movement.
+
+         \sstitem
+         The algorithm is based on pre IAU 1976 standards.  However,
+           the result has been moved onto the new (FK5) equinox, an
+           adjustment which is in any case much smaller than the
+           intrinsic accuracy of the procedure.
+
+         \sstitem
+         Velocity is obtained by a complete analytical differentiation
+           of the Meeus model.
+      }
+   }
+}
+\sstroutine{
+   palDrange
+}{
+   Normalize angle into range $+$/- pi
+}{
+   \sstdescription{
+      The result is {\tt "}angle{\tt "} expressed in the range $+$/- pi. If the
+      supplied value for {\tt "}angle{\tt "} is equal to $+$/- pi, it is returned
+      unchanged.
+   }
+   \sstinvocation{
+      palDrange( double angle )
+   }
+   \sstarguments{
+      \sstsubsection{
+         angle = double (Given)
+      }{
+         The angle in radians.
+      }
+   }
+}
+\sstroutine{
+   palDt
+}{
+   Estimate the offset between dynamical time and UT
+}{
+   \sstdescription{
+      Estimate the offset between dynamical time and Universal Time
+      for a given historical epoch.
+   }
+   \sstinvocation{
+      double palDt( double epoch );
+   }
+   \sstarguments{
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Julian epoch (e.g. 1850.0)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         palDt = double
+      }{
+         Rough estimate of ET-UT (after 1984, TT-UT) at the
+         given epoch, in seconds.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Depending on the epoch, one of three parabolic approximations
+           is used:
+
+      }
+          before 979    Stephenson \& Morrison{\tt '}s 390 BC to AD 948 model
+          979 to 1708   Stephenson \& Morrison{\tt '}s 948 to 1600 model
+          after 1708    McCarthy \& Babcock{\tt '}s post-1650 model
+
+        The breakpoints are chosen to ensure continuity:  they occur
+        at places where the adjacent models give the same answer as
+        each other.
+      \sstitemlist{
+
+         \sstitem
+         The accuracy is modest, with errors of up to 20 sec during
+           the interval since 1650, rising to perhaps 30 min by 1000 BC.
+           Comparatively accurate values from AD 1600 are tabulated in
+           the Astronomical Almanac (see section K8 of the 1995 AA).
+
+         \sstitem
+         The use of double-precision for both argument and result is
+           purely for compatibility with other SLALIB time routines.
+
+         \sstitem
+         The models used are based on a lunar tidal acceleration value
+           of -26.00 arcsec per century.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Explanatory Supplement to the Astronomical Almanac,
+      ed P.K.Seidelmann, University Science Books (1992),
+      section 2.553, p83.  This contains references to
+      the Stephenson \& Morrison and McCarthy \& Babcock
+      papers.
+   }
+}
+\sstroutine{
+   palDtp2s
+}{
+   Tangent plane to spherical coordinates
+}{
+   \sstdescription{
+      Transform tangent plane coordinates into spherical.
+   }
+   \sstinvocation{
+      palDtp2s( double xi, double eta, double raz, double decz,
+                double $*$ra, double $*$dec);
+   }
+   \sstarguments{
+      \sstsubsection{
+         xi = double (Given)
+      }{
+         First rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         eta = double (Given)
+      }{
+         Second rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         raz = double (Given)
+      }{
+         RA spherical coordinate of tangent point (radians)
+      }
+      \sstsubsection{
+         decz = double (Given)
+      }{
+         Dec spherical coordinate of tangent point (radians)
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         RA spherical coordinate of point to be projected (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Dec spherical coordinate of point to be projected (radians)
+      }
+   }
+}
+\sstroutine{
+   palDtps2c
+}{
+   Determine RA,Dec of tangent point from coordinates
+}{
+   \sstdescription{
+      From the tangent plane coordinates of a star of known RA,Dec,
+      determine the RA,Dec of the tangent point.
+   }
+   \sstinvocation{
+      palDtps2c( double xi, double eta, double ra, double dec,
+                 double $*$ raz1, double decz1,
+                 double $*$ raz2, double decz2, int $*$n);
+   }
+   \sstarguments{
+      \sstsubsection{
+         xi = double (Given)
+      }{
+         First rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         eta = double (Given)
+      }{
+         Second rectangular coordinate on tangent plane (radians)
+      }
+      \sstsubsection{
+         ra = double (Given)
+      }{
+         RA spherical coordinate of star (radians)
+      }
+      \sstsubsection{
+         dec = double (Given)
+      }{
+         Dec spherical coordinate of star (radians)
+      }
+      \sstsubsection{
+         raz1 = double $*$ (Returned)
+      }{
+         RA spherical coordinate of tangent point, solution 1 (radians)
+      }
+      \sstsubsection{
+         decz1 = double $*$ (Returned)
+      }{
+         Dec spherical coordinate of tangent point, solution 1 (radians)
+      }
+      \sstsubsection{
+         raz2 = double $*$ (Returned)
+      }{
+         RA spherical coordinate of tangent point, solution 2 (radians)
+      }
+      \sstsubsection{
+         decz2 = double $*$ (Returned)
+      }{
+         Dec spherical coordinate of tangent point, solution 2 (radians)
+      }
+      \sstsubsection{
+         n = int $*$ (Returned)
+      }{
+         number of solutions: 0 = no solutions returned (note 2)
+                              1 = only the first solution is useful (note 3)
+                              2 = both solutions are useful (note 3)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The RAZ1 and RAZ2 values are returned in the range 0-2pi.
+
+         \sstitem
+         Cases where there is no solution can only arise near the poles.
+           For example, it is clearly impossible for a star at the pole
+           itself to have a non-zero XI value, and hence it is
+           meaningless to ask where the tangent point would have to be
+           to bring about this combination of XI and DEC.
+
+         \sstitem
+         Also near the poles, cases can arise where there are two useful
+           solutions.  The argument N indicates whether the second of the
+           two solutions returned is useful.  N=1 indicates only one useful
+           solution, the usual case;  under these circumstances, the second
+           solution corresponds to the {\tt "}over-the-pole{\tt "} case, and this is
+           reflected in the values of RAZ2 and DECZ2 which are returned.
+
+         \sstitem
+         The DECZ1 and DECZ2 values are returned in the range $+$/-pi, but
+           in the usual, non-pole-crossing, case, the range is $+$/-pi/2.
+
+         \sstitem
+         This routine is the spherical equivalent of the routine sla\_DTPV2C.
+      }
+   }
+}
+\sstroutine{
+   palDtt
+}{
+   Return offset between UTC and TT
+}{
+   \sstdescription{
+      Increment to be applied to Coordinated Universal Time UTC to give
+      Terrestrial Time TT (formerly Ephemeris Time ET)
+   }
+   \sstinvocation{
+      dtt = palDtt( double utc );
+   }
+   \sstarguments{
+      \sstsubsection{
+         utc = double (Given)
+      }{
+         UTC date as a modified JD (JD-2400000.5)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         dtt = double
+      }{
+         TT-UTC in seconds
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Consider a comprehensive upgrade to use the time transformations in SOFA{\tt '}s time
+           cookbook:  http://www.iausofa.org/sofa\_ts\_c.pdf.
+
+         \sstitem
+         See eraDat for a description of error conditions when calling this function
+           with a time outside of the UTC range. This behaviour differs from slaDtt.
+      }
+   }
+}
+\sstroutine{
+   palEcleq
+}{
+   Transform from ecliptic coordinates to J2000.0 equatorial coordinates
+}{
+   \sstdescription{
+      Transform from ecliptic coordinate to J2000.0 equatorial coordinates.
+   }
+   \sstinvocation{
+      void palEcleq ( double dl, double db, double date,
+                      double $*$dr, double $*$dd );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dl = double (Given)
+      }{
+         Ecliptic longitude (mean of date, IAU 1980 theory, radians)
+      }
+      \sstsubsection{
+         db = double (Given)
+      }{
+         Ecliptic latitude (mean of date, IAU 1980 theory, radians)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as Modified Julian Date (JD-2400000.5). The difference
+         between TT and TDB is of the order of a millisecond or two
+         (i.e. about 0.02 arc-seconds).
+      }
+      \sstsubsection{
+         dr = double $*$ (Returned)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         dd = double $*$ (Returned)
+      }{
+         J2000.0 mean Dec (Radians)
+      }
+   }
+}
+\sstroutine{
+   palEcmat
+}{
+   Form the equatorial to ecliptic rotation matrix - IAU 2006
+   precession model
+}{
+   \sstdescription{
+      The equatorial to ecliptic rotation matrix is found and returned.
+      The matrix is in the sense   V(ecl)  =  RMAT $*$ V(equ);  the
+      equator, equinox and ecliptic are mean of date.
+   }
+   \sstinvocation{
+      palEcmat( double date, double rmat[3][3] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as Modified Julian Date (JD-2400000.5). The difference
+         between TT and TDB is of the order of a millisecond or two
+         (i.e. about 0.02 arc-seconds).
+      }
+      \sstsubsection{
+         rmat = double[3][3] (Returned)
+      }{
+         Rotation matrix
+      }
+   }
+}
+\sstroutine{
+   palEl2ue
+}{
+   Transform conventional elements into {\tt "}universal{\tt "} form
+}{
+   \sstdescription{
+      Transform conventional osculating elements into {\tt "}universal{\tt "} form.
+   }
+   \sstinvocation{
+      void palEl2ue ( double date, int jform, double epoch, double orbinc,
+                      double anode, double perih, double aorq, double e,
+                      double aorl, double dm, double u[13], int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Epoch (TT MJD) of osculation (Note 3)
+      }
+      \sstsubsection{
+         jform = int (Given)
+      }{
+         Element set actually returned (1-3; Note 6)
+      }
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbinc = double (Given)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode = double (Given)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih = double (Given)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq = double (Given)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e = double (Given)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         aorl = double (Given)
+      }{
+         mean anomaly or longitude (radians, JFORM=1,2 only)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         daily motion (radians, JFORM=1 only)
+      }
+      \sstsubsection{
+         u = double [13] (Returned)
+      }{
+         Universal orbital elements (Note 1)
+         \sstitemlist{
+
+            \sstitem
+              (0)  combined mass (M$+$m)
+
+            \sstitem
+              (1)  total energy of the orbit (alpha)
+
+            \sstitem
+              (2)  reference (osculating) epoch (t0)
+
+            \sstitem
+              (3-5)  position at reference epoch (r0)
+
+            \sstitem
+              (6-8)  velocity at reference epoch (v0)
+
+            \sstitem
+              (9)  heliocentric distance at reference epoch
+
+            \sstitem
+              (10)  r0.v0
+
+            \sstitem
+              (11)  date (t)
+
+            \sstitem
+              (12)  universal eccentric anomaly (psi) of date, approx
+         }
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:  0 = OK
+         \sstitemlist{
+
+            \sstitem
+                  -1 = illegal JFORM
+
+            \sstitem
+                  -2 = illegal E
+
+            \sstitem
+                  -3 = illegal AORQ
+
+            \sstitem
+                  -4 = illegal DM
+
+            \sstitem
+                  -5 = numerical error
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The {\tt "}universal{\tt "} elements are those which define the orbit for the
+           purposes of the method of universal variables (see reference).
+           They consist of the combined mass of the two bodies, an epoch,
+           and the position and velocity vectors (arbitrary reference frame)
+           at that epoch.  The parameter set used here includes also various
+           quantities that can, in fact, be derived from the other
+           information.  This approach is taken to avoiding unnecessary
+           computation and loss of accuracy.  The supplementary quantities
+           are (i) alpha, which is proportional to the total energy of the
+           orbit, (ii) the heliocentric distance at epoch, (iii) the
+           outwards component of the velocity at the given epoch, (iv) an
+           estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+           date and (v) that date.
+
+         \sstitem
+         The companion routine is palUe2pv.  This takes the set of numbers
+           that the present routine outputs and uses them to derive the
+           object{\tt '}s position and velocity.  A single prediction requires one
+           call to the present routine followed by one call to palUe2pv;
+           for convenience, the two calls are packaged as the routine
+           palPlanel.  Multiple predictions may be made by again calling the
+           present routine once, but then calling palUe2pv multiple times,
+           which is faster than multiple calls to palPlanel.
+
+         \sstitem
+         DATE is the epoch of osculation.  It is in the TT timescale
+           (formerly Ephemeris Time, ET) and is a Modified Julian Date
+           (JD-2400000.5).
+
+         \sstitem
+         The supplied orbital elements are with respect to the J2000
+           ecliptic and equinox.  The position and velocity parameters
+           returned in the array U are with respect to the mean equator and
+           equinox of epoch J2000, and are for the perihelion prior to the
+           specified epoch.
+
+         \sstitem
+         The universal elements returned in the array U are in canonical
+           units (solar masses, AU and canonical days).
+
+         \sstitem
+         Three different element-format options are available:
+
+      }
+        Option JFORM=1, suitable for the major planets:
+
+        EPOCH  = epoch of elements (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = longitude of perihelion, curly pi (radians)
+        AORQ   = mean distance, a (AU)
+        E      = eccentricity, e (range 0 to $<$1)
+        AORL   = mean longitude L (radians)
+        DM     = daily motion (radians)
+
+        Option JFORM=2, suitable for minor planets:
+
+        EPOCH  = epoch of elements (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = argument of perihelion, little omega (radians)
+        AORQ   = mean distance, a (AU)
+        E      = eccentricity, e (range 0 to $<$1)
+        AORL   = mean anomaly M (radians)
+
+        Option JFORM=3, suitable for comets:
+
+        EPOCH  = epoch of perihelion (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = argument of perihelion, little omega (radians)
+        AORQ   = perihelion distance, q (AU)
+        E      = eccentricity, e (range 0 to 10)
+
+      \sstitemlist{
+
+         \sstitem
+         Unused elements (DM for JFORM=2, AORL and DM for JFORM=3) are
+           not accessed.
+
+         \sstitem
+         The algorithm was originally adapted from the EPHSLA program of
+           D.H.P.Jones (private communication, 1996).  The method is based
+           on Stumpff{\tt '}s Universal Variables.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Everhart \& Pitkin, Am.J.Phys. 51, 712 (1983).
+   }
+}
+\sstroutine{
+   palEpco
+}{
+   Convert an epoch into the appropriate form - {\tt '}B{\tt '} or {\tt '}J{\tt '}
+}{
+   \sstdescription{
+      Converts a Besselian or Julian epoch to a Julian or Besselian
+      epoch.
+   }
+   \sstinvocation{
+      double palEpco( char k0, char k, double e );
+   }
+   \sstarguments{
+      \sstsubsection{
+         k0 = char (Given)
+      }{
+         Form of result: {\tt '}B{\tt '}=Besselian, {\tt '}J{\tt '}=Julian
+      }
+      \sstsubsection{
+         k = char (Given)
+      }{
+         Form of given epoch: {\tt '}B{\tt '} or {\tt '}J{\tt '}.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The result is always either equal to or very close to
+           the given epoch E.  The routine is required only in
+           applications where punctilious treatment of heterogeneous
+           mixtures of star positions is necessary.
+
+         \sstitem
+         k and k0 are case insensitive. This differes slightly from the
+           Fortran SLA implementation.
+
+         \sstitem
+         k and k0 are not validated. They are interpreted as follows:
+           o If k0 and k are the same the result is e
+           o If k0 is {\tt '}b{\tt '} or {\tt '}B{\tt '} and k isn{\tt '}t the conversion is J to B.
+           o In all other cases, the conversion is B to J.
+      }
+   }
+}
+\sstroutine{
+   palEpv
+}{
+   Earth position and velocity with respect to the BCRS
+}{
+   \sstdescription{
+      Earth position and velocity, heliocentric and barycentric, with
+      respect to the Barycentric Celestial Reference System.
+   }
+   \sstinvocation{
+      void palEpv( double date, double ph[3], double vh[3],
+                   double pb[3], double vb[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Date, TDB Modified Julian Date (JD-2400000.5)
+      }
+      \sstsubsection{
+         ph = double [3] (Returned)
+      }{
+         Heliocentric Earth position (AU)
+      }
+      \sstsubsection{
+         vh = double [3] (Returned)
+      }{
+         Heliocentric Earth velocity (AU/day)
+      }
+      \sstsubsection{
+         pb = double [3] (Returned)
+      }{
+         Barycentric Earth position (AU)
+      }
+      \sstsubsection{
+         vb = double [3] (Returned)
+      }{
+         Barycentric Earth velocity (AU/day)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         See eraEpv00 for details on accuracy
+
+         \sstitem
+         Note that the status argument from eraEpv00 is ignored
+      }
+   }
+}
+\sstroutine{
+   palEtrms
+}{
+   Compute the E-terms vector
+}{
+   \sstdescription{
+      Computes the E-terms (elliptic component of annual aberration)
+      vector.
+
+      Note the use of the J2000 aberration constant (20.49552 arcsec).
+      This is a reflection of the fact that the E-terms embodied in
+      existing star catalogues were computed from a variety of
+      aberration constants.  Rather than adopting one of the old
+      constants the latest value is used here.
+   }
+   \sstinvocation{
+      void palEtrms ( double ep, double ev[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ep = double (Given)
+      }{
+         Besselian epoch
+      }
+      \sstsubsection{
+         ev = double [3] (Returned)
+      }{
+         E-terms as (dx,dy,dz)
+      }
+   }
+   \sstdiytopic{
+      See also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Smith, C.A. et al., 1989.  Astr.J. 97, 265.
+
+         \sstitem
+         Yallop, B.D. et al., 1989.  Astr.J. 97, 274.
+      }
+   }
+}
+\sstroutine{
+   palEqecl
+}{
+   Transform from J2000.0 equatorial coordinates to ecliptic coordinates
+}{
+   \sstdescription{
+      Transform from J2000.0 equatorial coordinates to ecliptic coordinates.
+   }
+   \sstinvocation{
+      void palEqecl( double dr, double dd, double date,
+                     double $*$dl, double $*$db);
+   }
+   \sstarguments{
+      \sstsubsection{
+         dr = double (Given)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         dd = double (Given)
+      }{
+         J2000.0 mean Dec (Radians)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as Modified Julian Date (JD-2400000.5). The difference
+         between TT and TDB is of the order of a millisecond or two
+         (i.e. about 0.02 arc-seconds).
+      }
+      \sstsubsection{
+         dl = double $*$ (Returned)
+      }{
+         Ecliptic longitude (mean of date, IAU 1980 theory, radians)
+      }
+      \sstsubsection{
+         db = double $*$ (Returned)
+      }{
+         Ecliptic latitude (mean of date, IAU 1980 theory, radians)
+      }
+   }
+}
+\sstroutine{
+   palEqgal
+}{
+   Convert from J2000.0 equatorial coordinates to Galactic
+}{
+   \sstdescription{
+      Transformation from J2000.0 equatorial coordinates
+      to IAU 1958 galactic coordinates.
+   }
+   \sstinvocation{
+      void palEqgal ( double dr, double dd, double $*$dl, double $*$db );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dr = double (Given)
+      }{
+         J2000.0 RA (radians)
+      }
+      \sstsubsection{
+         dd = double (Given)
+      }{
+         J2000.0 Dec (radians
+      }
+      \sstsubsection{
+         dl = double $*$ (Returned)
+      }{
+         Galactic longitude (radians).
+      }
+      \sstsubsection{
+         db = double $*$ (Returned)
+      }{
+         Galactic latitude (radians).
+      }
+   }
+   \sstnotes{
+      The equatorial coordinates are J2000.0.  Use the routine
+      palGe50 if conversion to B1950.0 {\tt '}FK4{\tt '} coordinates is
+      required.
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+   }
+}
+\sstroutine{
+   palEvp
+}{
+   Returns the barycentric and heliocentric velocity and position of the
+   Earth
+}{
+   \sstdescription{
+      Returns the barycentric and heliocentric velocity and position of the
+      Earth at a given epoch, given with respect to a specified equinox.
+      For information about accuracy, see the function eraEpv00.
+   }
+   \sstinvocation{
+      void palEvp( double date, double deqx, double dvb[3], double dpb[3],
+                   double dvh[3], double dph[3] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB (loosely ET) as a Modified Julian Date (JD-2400000.5)
+      }
+      \sstsubsection{
+         deqx = double (Given)
+      }{
+         Julian epoch (e.g. 2000.0) of mean equator and equinox of the
+         vectors returned.  If deqx $<$= 0.0, all vectors are referred to the
+         mean equator and equinox (FK5) of epoch date.
+      }
+      \sstsubsection{
+         dvb = double[3] (Returned)
+      }{
+         Barycentric velocity (AU/s, AU)
+      }
+      \sstsubsection{
+         dpb = double[3] (Returned)
+      }{
+         Barycentric position (AU/s, AU)
+      }
+      \sstsubsection{
+         dvh = double[3] (Returned)
+      }{
+         heliocentric velocity (AU/s, AU)
+      }
+      \sstsubsection{
+         dph = double[3] (Returned)
+      }{
+         Heliocentric position (AU/s, AU)
+      }
+   }
+}
+\sstroutine{
+   palFk45z
+}{
+   Convert B1950.0 FK4 star data to J2000.0 FK5 assuming zero
+   proper motion in the FK5 frame
+}{
+   \sstdescription{
+      Convert B1950.0 FK4 star data to J2000.0 FK5 assuming zero
+      proper motion in the FK5 frame (double precision)
+
+      This function converts stars from the Bessel-Newcomb, FK4
+      system to the IAU 1976, FK5, Fricke system, in such a
+      way that the FK5 proper motion is zero.  Because such a star
+      has, in general, a non-zero proper motion in the FK4 system,
+      the routine requires the epoch at which the position in the
+      FK4 system was determined.
+
+      The method is from Appendix 2 of Ref 1, but using the constants
+      of Ref 4.
+   }
+   \sstinvocation{
+      palFk45z( double r1950, double d1950, double bepoch, double $*$r2000,
+                double $*$d2000 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r1950 = double (Given)
+      }{
+         B1950.0 FK4 RA at epoch (radians).
+      }
+      \sstsubsection{
+         d1950 = double (Given)
+      }{
+         B1950.0 FK4 Dec at epoch (radians).
+      }
+      \sstsubsection{
+         bepoch = double (Given)
+      }{
+         Besselian epoch (e.g. 1979.3)
+      }
+      \sstsubsection{
+         r2000 = double (Returned)
+      }{
+         J2000.0 FK5 RA (Radians).
+      }
+      \sstsubsection{
+         d2000 = double (Returned)
+      }{
+         J2000.0 FK5 Dec(Radians).
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The epoch BEPOCH is strictly speaking Besselian, but if a
+         Julian epoch is supplied the result will be affected only to
+         a negligible extent.
+
+         \sstitem
+         Conversion from Besselian epoch 1950.0 to Julian epoch 2000.0
+         only is provided for.  Conversions involving other epochs will
+         require use of the appropriate precession, proper motion, and
+         E-terms routines before and/or after palFk45z is called.
+
+         \sstitem
+         In the FK4 catalogue the proper motions of stars within 10
+         degrees of the poles do not embody the differential E-term effect
+         and should, strictly speaking, be handled in a different manner
+         from stars outside these regions. However, given the general lack
+         of homogeneity of the star data available for routine astrometry,
+         the difficulties of handling positions that may have been
+         determined from astrometric fields spanning the polar and non-polar
+         regions, the likelihood that the differential E-terms effect was not
+         taken into account when allowing for proper motion in past
+         astrometry, and the undesirability of a discontinuity in the
+         algorithm, the decision has been made in this routine to include the
+         effect of differential E-terms on the proper motions for all stars,
+         whether polar or not.  At epoch 2000, and measuring on the sky rather
+         than in terms of dRA, the errors resulting from this simplification
+         are less than 1 milliarcsecond in position and 1 milliarcsecond per
+         century in proper motion.
+      }
+   }
+   \sstdiytopic{
+      References
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Aoki,S., et al, 1983.  Astron.Astrophys., 128, 263.
+
+         \sstitem
+         Smith, C.A. et al, 1989.  {\tt "}The transformation of astrometric
+           catalog systems to the equinox J2000.0{\tt "}.  Astron.J. 97, 265.
+
+         \sstitem
+         Yallop, B.D. et al, 1989.  {\tt "}Transformation of mean star places
+           from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space{\tt "}.
+           Astron.J. 97, 274.
+
+         \sstitem
+         Seidelmann, P.K. (ed), 1992.  {\tt "}Explanatory Supplement to
+           the Astronomical Almanac{\tt "}, ISBN 0-935702-68-7.
+      }
+   }
+}
+\sstroutine{
+   palFk524
+}{
+   Convert J2000.0 FK5 star data to B1950.0 FK4
+}{
+   \sstdescription{
+      This function converts stars from the IAU 1976, FK5, Fricke
+      system, to the Bessel-Newcomb, FK4 system.  The precepts
+      of Smith et al (Ref 1) are followed, using the implementation
+      by Yallop et al (Ref 2) of a matrix method due to Standish.
+      Kinoshita{\tt '}s development of Andoyer{\tt '}s post-Newcomb precession is
+      used.  The numerical constants from Seidelmann et al (Ref 3) are
+      used canonically.
+   }
+   \sstinvocation{
+      palFk524( double r2000, double d2000, double dr2000, double dd2000,
+                double p2000, double v2000, double $*$r1950, double $*$d1950,
+                double $*$dr1950, double $*$dd1950, double $*$p1950, double $*$v1950 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 FK5 RA (radians).
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 FK5 Dec (radians).
+      }
+      \sstsubsection{
+         dr2000 = double (Given)
+      }{
+         J2000.0 FK5 RA proper motion (rad/Jul.yr)
+      }
+      \sstsubsection{
+         dd2000 = double (Given)
+      }{
+         J2000.0 FK5 Dec proper motion (rad/Jul.yr)
+      }
+      \sstsubsection{
+         p2000 = double (Given)
+      }{
+         J2000.0 FK5 parallax (arcsec)
+      }
+      \sstsubsection{
+         v2000 = double (Given)
+      }{
+         J2000.0 FK5 radial velocity (km/s, $+$ve = moving away)
+      }
+      \sstsubsection{
+         r1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 RA (radians).
+      }
+      \sstsubsection{
+         d1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 Dec (radians).
+      }
+      \sstsubsection{
+         dr1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 RA proper motion (rad/Jul.yr)
+      }
+      \sstsubsection{
+         dd1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 Dec proper motion (rad/Jul.yr)
+      }
+      \sstsubsection{
+         p1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 parallax (arcsec)
+      }
+      \sstsubsection{
+         v1950 = double $*$ (Returned)
+      }{
+         B1950.0 FK4 radial velocity (km/s, $+$ve = moving away)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The proper motions in RA are dRA/dt rather than
+         cos(Dec)$*$dRA/dt, and are per year rather than per century.
+
+         \sstitem
+         Note that conversion from Julian epoch 2000.0 to Besselian
+         epoch 1950.0 only is provided for.  Conversions involving
+         other epochs will require use of the appropriate precession,
+         proper motion, and E-terms routines before and/or after
+         FK524 is called.
+
+         \sstitem
+         In the FK4 catalogue the proper motions of stars within
+         10 degrees of the poles do not embody the differential
+         E-term effect and should, strictly speaking, be handled
+         in a different manner from stars outside these regions.
+         However, given the general lack of homogeneity of the star
+         data available for routine astrometry, the difficulties of
+         handling positions that may have been determined from
+         astrometric fields spanning the polar and non-polar regions,
+         the likelihood that the differential E-terms effect was not
+         taken into account when allowing for proper motion in past
+         astrometry, and the undesirability of a discontinuity in
+         the algorithm, the decision has been made in this routine to
+         include the effect of differential E-terms on the proper
+         motions for all stars, whether polar or not.  At epoch 2000,
+         and measuring on the sky rather than in terms of dRA, the
+         errors resulting from this simplification are less than
+         1 milliarcsecond in position and 1 milliarcsecond per
+         century in proper motion.
+      }
+   }
+   \sstdiytopic{
+      References
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Smith, C.A. et al, 1989.  {\tt "}The transformation of astrometric
+           catalog systems to the equinox J2000.0{\tt "}.  Astron.J. 97, 265.
+
+         \sstitem
+         Yallop, B.D. et al, 1989.  {\tt "}Transformation of mean star places
+           from FK4 B1950.0 to FK5 J2000.0 using matrices in 6-space{\tt "}.
+           Astron.J. 97, 274.
+
+         \sstitem
+         Seidelmann, P.K. (ed), 1992.  {\tt "}Explanatory Supplement to
+           the Astronomical Almanac{\tt "}, ISBN 0-935702-68-7.
+      }
+   }
+}
+\sstroutine{
+   palFk54z
+}{
+   Convert a J2000.0 FK5 star position to B1950.0 FK4 assuming
+   zero proper motion and parallax
+}{
+   \sstdescription{
+      This function converts star positions from the IAU 1976,
+      FK5, Fricke system to the Bessel-Newcomb, FK4 system.
+   }
+   \sstinvocation{
+      palFk54z( double r2000, double d2000, double bepoch, double $*$r1950,
+                double $*$d1950, double $*$dr1950, double $*$dd1950 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 FK5 RA (radians).
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 FK5 Dec (radians).
+      }
+      \sstsubsection{
+         bepoch = double (Given)
+      }{
+         Besselian epoch (e.g. 1950.0).
+      }
+      \sstsubsection{
+         r1950 = double $*$ (Returned)
+      }{
+         B1950 FK4 RA (radians) at epoch {\tt "}bepoch{\tt "}.
+      }
+      \sstsubsection{
+         d1950 = double $*$ (Returned)
+      }{
+         B1950 FK4 Dec (radians) at epoch {\tt "}bepoch{\tt "}.
+      }
+      \sstsubsection{
+         dr1950 = double $*$ (Returned)
+      }{
+         B1950 FK4 proper motion (RA) (radians/trop.yr)).
+      }
+      \sstsubsection{
+         dr1950 = double $*$ (Returned)
+      }{
+         B1950 FK4 proper motion (Dec) (radians/trop.yr)).
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The proper motion in RA is dRA/dt rather than cos(Dec)$*$dRA/dt.
+
+         \sstitem
+         Conversion from Julian epoch 2000.0 to Besselian epoch 1950.0
+         only is provided for.  Conversions involving other epochs will
+         require use of the appropriate precession functions before and
+         after this function is called.
+
+         \sstitem
+         The FK5 proper motions, the parallax and the radial velocity
+          are presumed zero.
+
+         \sstitem
+         It is the intention that FK5 should be a close approximation
+         to an inertial frame, so that distant objects have zero proper
+         motion;  such objects have (in general) non-zero proper motion
+         in FK4, and this function returns those fictitious proper
+         motions.
+
+         \sstitem
+         The position returned by this function is in the B1950
+         reference frame but at Besselian epoch BEPOCH.  For comparison
+         with catalogues the {\tt "}bepoch{\tt "} argument will frequently be 1950.0.
+      }
+   }
+}
+\sstroutine{
+   palGaleq
+}{
+   Convert from galactic to J2000.0 equatorial coordinates
+}{
+   \sstdescription{
+      Transformation from IAU 1958 galactic coordinates to
+      J2000.0 equatorial coordinates.
+   }
+   \sstinvocation{
+      void palGaleq ( double dl, double db, double $*$dr, double $*$dd );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dl = double (Given)
+      }{
+         Galactic longitude (radians).
+      }
+      \sstsubsection{
+         db = double (Given)
+      }{
+         Galactic latitude (radians).
+      }
+      \sstsubsection{
+         dr = double $*$ (Returned)
+      }{
+         J2000.0 RA (radians)
+      }
+      \sstsubsection{
+         dd = double $*$ (Returned)
+      }{
+         J2000.0 Dec (radians)
+      }
+   }
+   \sstnotes{
+      The equatorial coordinates are J2000.0.  Use the routine
+      palGe50 if conversion to B1950.0 {\tt '}FK4{\tt '} coordinates is
+      required.
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+   }
+}
+\sstroutine{
+   palGalsup
+}{
+   Convert from galactic to supergalactic coordinates
+}{
+   \sstdescription{
+      Transformation from IAU 1958 galactic coordinates to
+      de Vaucouleurs supergalactic coordinates.
+   }
+   \sstinvocation{
+      void palGalsup ( double dl, double db, double $*$dsl, double $*$dsb );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dl = double (Given)
+      }{
+         Galactic longitude.
+      }
+      \sstsubsection{
+         db = double (Given)
+      }{
+         Galactic latitude.
+      }
+      \sstsubsection{
+         dsl = double $*$ (Returned)
+      }{
+         Supergalactic longitude.
+      }
+      \sstsubsection{
+         dsb = double $*$ (Returned)
+      }{
+         Supergalactic latitude.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+          de Vaucouleurs, de Vaucouleurs, \& Corwin, Second Reference
+            Catalogue of Bright Galaxies, U. Texas, page 8.
+
+         \sstitem
+          Systems \& Applied Sciences Corp., Documentation for the
+            machine-readable version of the above catalogue,
+            Contract NAS 5-26490.
+
+      }
+      (These two references give different values for the galactic
+       longitude of the supergalactic origin.  Both are wrong;  the
+       correct value is L2=137.37.)
+   }
+}
+\sstroutine{
+   palGe50
+}{
+   Transform Galactic Coordinate to B1950 FK4
+}{
+   \sstdescription{
+      Transformation from IAU 1958 galactic coordinates to
+      B1950.0 {\tt '}FK4{\tt '} equatorial coordinates.
+   }
+   \sstinvocation{
+      palGe50( double dl, double db, double $*$dr, double $*$dd );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dl = double (Given)
+      }{
+         Galactic longitude (radians)
+      }
+      \sstsubsection{
+         db = double (Given)
+      }{
+         Galactic latitude (radians)
+      }
+      \sstsubsection{
+         dr = double $*$ (Returned)
+      }{
+         B9150.0 FK4 RA.
+      }
+      \sstsubsection{
+         dd = double $*$ (Returned)
+      }{
+         B1950.0 FK4 Dec.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The equatorial coordinates are B1950.0 {\tt '}FK4{\tt '}. Use the routine
+         palGaleq if conversion to J2000.0 coordinates is required.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Blaauw et al, Mon.Not.R.Astron.Soc.,121,123 (1960)
+      }
+   }
+}
+\sstroutine{
+   palGeoc
+}{
+   Convert geodetic position to geocentric
+}{
+   \sstdescription{
+      Convert geodetic position to geocentric.
+   }
+   \sstinvocation{
+      void palGeoc( double p, double h, double $*$ r, double $*$z );
+   }
+   \sstarguments{
+      \sstsubsection{
+         p = double (Given)
+      }{
+         latitude (radians)
+      }
+      \sstsubsection{
+         h = double (Given)
+      }{
+         height above reference spheroid (geodetic, metres)
+      }
+      \sstsubsection{
+         r = double $*$ (Returned)
+      }{
+         distance from Earth axis (AU)
+      }
+      \sstsubsection{
+         z = double $*$ (Returned)
+      }{
+         distance from plane of Earth equator (AU)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Geocentric latitude can be obtained by evaluating atan2(z,r)
+
+         \sstitem
+         Uses WGS84 reference ellipsoid and calls eraGd2gc
+      }
+   }
+}
+\sstroutine{
+   palIntin
+}{
+   Convert free-format input into an integer
+}{
+   \sstdescription{
+      Extracts a number from an input string starting at the specified
+      index.
+   }
+   \sstinvocation{
+      void palIntin( const char $*$ string, int $*$nstrt,
+                      long $*$ireslt, int $*$jflag );
+   }
+   \sstarguments{
+      \sstsubsection{
+         string = const char $*$ (Given)
+      }{
+         String containing number to be decoded.
+      }
+      \sstsubsection{
+         nstrt = int $*$ (Given and Returned)
+      }{
+         Character number indicating where decoding should start.
+         On output its value is updated to be the location of the
+         possible next value. For compatibility with SLA the first
+         character is index 1.
+      }
+      \sstsubsection{
+         ireslt = long $*$ (Returned)
+      }{
+         Result. Not updated when jflag=1.
+      }
+      \sstsubsection{
+         jflag = int $*$ (Returned)
+      }{
+         status: -1 = -OK, 0 = $+$OK, 1 = null, 2 = error
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses the strtol() system call to do the parsing. This may lead to
+           subtle differences when compared to the SLA/F parsing.
+
+         \sstitem
+         Commas are recognized as a special case and are skipped if one happens
+           to be the next character when updating nstrt. Additionally the output
+           nstrt position will skip past any trailing space.
+
+         \sstitem
+         If no number can be found flag will be set to 1.
+
+         \sstitem
+         If the number overflows or underflows jflag will be set to 2. For overflow
+           the returned result will have the value LONG\_MAX, for underflow it
+           will have the value LONG\_MIN.
+      }
+   }
+}
+\sstroutine{
+   palMap
+}{
+   Convert star RA,Dec from mean place to geocentric apparent
+}{
+   \sstdescription{
+      Convert star RA,Dec from mean place to geocentric apparent.
+   }
+   \sstinvocation{
+      void palMap( double rm, double dm, double pr, double pd,
+                   double px, double rv, double eq, double date,
+                   double $*$ra, double $*$da );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rm = double (Given)
+      }{
+         Mean RA (radians)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         Mean declination (radians)
+      }
+      \sstsubsection{
+         pr = double (Given)
+      }{
+         RA proper motion, changes per Julian year (radians)
+      }
+      \sstsubsection{
+         pd = double (Given)
+      }{
+         Dec proper motion, changes per Julian year (radians)
+      }
+      \sstsubsection{
+         px = double (Given)
+      }{
+         Parallax (arcsec)
+      }
+      \sstsubsection{
+         rv = double (Given)
+      }{
+         Radial velocity (km/s, $+$ve if receding)
+      }
+      \sstsubsection{
+         eq = double (Given)
+      }{
+         Epoch and equinox of star data (Julian)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB for apparent place (JD-2400000.5)
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         Apparent RA (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Apparent dec (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Calls palMappa and palMapqk
+
+         \sstitem
+         The reference systems and timescales used are IAU 2006.
+
+         \sstitem
+         EQ is the Julian epoch specifying both the reference frame and
+           the epoch of the position - usually 2000.  For positions where
+           the epoch and equinox are different, use the routine palPm to
+           apply proper motion corrections before using this routine.
+
+         \sstitem
+         The distinction between the required TDB and TT is always
+           negligible.  Moreover, for all but the most critical
+           applications UTC is adequate.
+
+         \sstitem
+         The proper motions in RA are dRA/dt rather than cos(Dec)$*$dRA/dt.
+
+         \sstitem
+         This routine may be wasteful for some applications because it
+           recomputes the Earth position/velocity and the precession-
+           nutation matrix each time, and because it allows for parallax
+           and proper motion.  Where multiple transformations are to be
+           carried out for one epoch, a faster method is to call the
+           palMappa routine once and then either the palMapqk routine
+           (which includes parallax and proper motion) or palMapqkz (which
+           assumes zero parallax and proper motion).
+
+         \sstitem
+         The accuracy is sub-milliarcsecond, limited by the
+           precession-nutation model (see palPrenut for details).
+
+         \sstitem
+         The accuracy is further limited by the routine palEvp, called
+           by palMappa, which computes the Earth position and velocity.
+           See eraEpv00 for details on that calculation.
+      }
+   }
+}
+\sstroutine{
+   palMappa
+}{
+   Compute parameters needed by palAmpqk and palMapqk
+}{
+   \sstdescription{
+      Compute star-independent parameters in preparation for
+      transformations between mean place and geocentric apparent place.
+
+      The parameters produced by this function are required in the
+      parallax, aberration, and nutation/bias/precession parts of the
+      mean/apparent transformations.
+
+      The reference systems and timescales used are IAU 2006.
+   }
+   \sstinvocation{
+      void palMappa( double eq, double date, double amprms[21] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         eq = double (Given)
+      }{
+         epoch of mean equinox to be used (Julian)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB (JD-2400000.5)
+      }
+      \sstsubsection{
+         amprms =   double[21]  (Returned)
+      }{
+         star-independent mean-to-apparent parameters:
+         \sstitemlist{
+
+            \sstitem
+            (0)      time interval for proper motion (Julian years)
+
+            \sstitem
+            (1-3)    barycentric position of the Earth (AU)
+
+            \sstitem
+            (4-6)    heliocentric direction of the Earth (unit vector)
+
+            \sstitem
+            (7)      (grav rad Sun)$*$2/(Sun-Earth distance)
+
+            \sstitem
+            (8-10)   abv: barycentric Earth velocity in units of c
+
+            \sstitem
+            (11)     sqrt(1-v$*$$*$2) where v=modulus(abv)
+
+            \sstitem
+            (12-20)  precession/nutation (3,3) matrix
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         For date, the distinction between the required TDB and TT
+         is always negligible.  Moreover, for all but the most
+         critical applications UTC is adequate.
+
+         \sstitem
+         The vector amprms(1-3) is referred to the mean equinox and
+         equator of epoch eq.
+
+         \sstitem
+         The parameters amprms produced by this function are used by
+         palAmpqk, palMapqk and palMapqkz.
+      }
+   }
+}
+\sstroutine{
+   palMapqk
+}{
+   Quick mean to apparent place
+}{
+   \sstdescription{
+      Quick mean to apparent place:  transform a star RA,Dec from
+      mean place to geocentric apparent place, given the
+      star-independent parameters.
+
+      Use of this routine is appropriate when efficiency is important
+      and where many star positions, all referred to the same equator
+      and equinox, are to be transformed for one epoch.  The
+      star-independent parameters can be obtained by calling the
+      palMappa routine.
+
+      If the parallax and proper motions are zero the palMapqkz
+      routine can be used instead.
+   }
+   \sstinvocation{
+      void palMapqk ( double rm, double dm, double pr, double pd,
+                      double px, double rv, double amprms[21],
+                      double $*$ra, double $*$da );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rm = double (Given)
+      }{
+         Mean RA (radians)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         Mean declination (radians)
+      }
+      \sstsubsection{
+         pr = double (Given)
+      }{
+         RA proper motion, changes per Julian year (radians)
+      }
+      \sstsubsection{
+         pd = double (Given)
+      }{
+         Dec proper motion, changes per Julian year (radians)
+      }
+      \sstsubsection{
+         px = double (Given)
+      }{
+         Parallax (arcsec)
+      }
+      \sstsubsection{
+         rv = double (Given)
+      }{
+         Radial velocity (km/s, $+$ve if receding)
+      }
+      \sstsubsection{
+         amprms = double [21] (Given)
+      }{
+         Star-independent mean-to-apparent parameters (see palMappa).
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         Apparent RA (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Apparent dec (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The reference frames and timescales used are post IAU 2006.
+      }
+   }
+}
+\sstroutine{
+   palMapqkz
+}{
+   Quick mean to apparent place
+}{
+   \sstdescription{
+      Quick mean to apparent place:  transform a star RA,dec from
+      mean place to geocentric apparent place, given the
+      star-independent parameters, and assuming zero parallax
+      and proper motion.
+
+      Use of this function is appropriate when efficiency is important
+      and where many star positions, all with parallax and proper
+      motion either zero or already allowed for, and all referred to
+      the same equator and equinox, are to be transformed for one
+      epoch.  The star-independent parameters can be obtained by
+      calling the palMappa function.
+
+      The corresponding function for the case of non-zero parallax
+      and proper motion is palMapqk.
+
+      The reference systems and timescales used are IAU 2006.
+
+      Strictly speaking, the function is not valid for solar-system
+      sources, though the error will usually be extremely small.
+   }
+   \sstinvocation{
+      void palMapqkz( double rm, double dm, double amprms[21],
+                      double $*$ra, double $*$da )
+   }
+   \sstarguments{
+      \sstsubsection{
+         rm = double (Given)
+      }{
+         Mean RA (radians).
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         Mean Dec (radians).
+      }
+      \sstsubsection{
+         amprms = double[21] (Given)
+      }{
+         Star-independent mean-to-apparent parameters (see palMappa):
+         (0-3)    not used
+         (4-6)    not used
+         (7)      not used
+         (8-10)   abv: barycentric Earth velocity in units of c
+         (11)     sqrt(1-v$*$$*$2) where v=modulus(abv)
+         (12-20)  precession/nutation (3,3) matrix
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         Apparent RA (radians).
+      }
+      \sstsubsection{
+         da = double $*$ (Returned)
+      }{
+         Apparent Dec (radians).
+      }
+   }
+}
+\sstroutine{
+   palNut
+}{
+   Form the matrix of nutation
+}{
+   \sstdescription{
+      Form the matrix of nutation for a given date using
+      the IAU 2006 nutation model and palDeuler.
+   }
+   \sstinvocation{
+      void palNut( double date, double rmatn[3][3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as modified Julian date (JD-2400000.5)
+      }
+      \sstsubsection{
+         rmatn = double [3][3] (Returned)
+      }{
+         Nutation matrix in the sense v(true)=rmatn $*$ v(mean)
+         where v(true) is the star vector relative to the
+         true equator and equinox of date and v(mean) is the
+         star vector relative to the mean equator and equinox
+         of date.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraNut06a via palNutc
+
+         \sstitem
+         The distinction between TDB and TT is negligible. For all but
+           the most critical applications UTC is adequate.
+      }
+   }
+}
+\sstroutine{
+   palNutc
+}{
+   Calculate nutation longitude \& obliquoty components
+}{
+   \sstdescription{
+      Calculates the longitude $*$ obliquity components and mean obliquity
+      using the SOFA/ERFA library.
+   }
+   \sstinvocation{
+      void palNutc( double date, double $*$ dpsi, double $*$deps, double $*$eps0 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT as modified Julian date (JD-2400000.5)
+      }
+      \sstsubsection{
+         dpsi = double $*$ (Returned)
+      }{
+         Nutation in longitude
+      }
+      \sstsubsection{
+         deps = double $*$ (Returned)
+      }{
+         Nutation in obliquity
+      }
+      \sstsubsection{
+         eps0 = double $*$ (Returned)
+      }{
+         Mean obliquity.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Calls eraObl06 and eraNut06a and therefore uses the IAU 206
+           precession/nutation model.
+
+         \sstitem
+         Note the change from SLA/F regarding the date. TT is used
+           rather than TDB.
+      }
+   }
+}
+\sstroutine{
+   palOap
+}{
+   Observed to apparent place
+}{
+   \sstdescription{
+      Observed to apparent place.
+   }
+   \sstinvocation{
+      void palOap ( const char $*$type, double ob1, double ob2, double date,
+                    double dut, double elongm, double phim, double hm,
+                    double xp, double yp, double tdk, double pmb,
+                    double rh, double wl, double tlr,
+                    double $*$rap, double $*$dap );
+   }
+   \sstarguments{
+      \sstsubsection{
+         type = const char $*$ (Given)
+      }{
+         Type of coordinates - {\tt '}R{\tt '}, {\tt '}H{\tt '} or {\tt '}A{\tt '} (see below)
+      }
+      \sstsubsection{
+         ob1 = double (Given)
+      }{
+         Observed Az, HA or RA (radians; Az is N=0;E=90)
+      }
+      \sstsubsection{
+         ob2 = double (Given)
+      }{
+         Observed ZD or Dec (radians)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         UTC date/time (Modified Julian Date, JD-2400000.5)
+      }
+      \sstsubsection{
+         dut = double (Given)
+      }{
+         delta UT: UT1-UTC (UTC seconds)
+      }
+      \sstsubsection{
+         elongm = double (Given)
+      }{
+         Mean longitude of the observer (radians, east $+$ve)
+      }
+      \sstsubsection{
+         phim = double (Given)
+      }{
+         Mean geodetic latitude of the observer (radians)
+      }
+      \sstsubsection{
+         hm = double (Given)
+      }{
+         Observer{\tt '}s height above sea level (metres)
+      }
+      \sstsubsection{
+         xp = double (Given)
+      }{
+         Polar motion x-coordinates (radians)
+      }
+      \sstsubsection{
+         yp = double (Given)
+      }{
+         Polar motion y-coordinates (radians)
+      }
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Local ambient temperature (K; std=273.15)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Local atmospheric pressure (mb; std=1013.25)
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Local relative humidity (in the range 0.0-1.0)
+      }
+      \sstsubsection{
+         wl = double (Given)
+      }{
+         Effective wavelength (micron, e.g. 0.55)
+      }
+      \sstsubsection{
+         tlr = double (Given)
+      }{
+         Tropospheric laps rate (K/metre, e.g. 0.0065)
+      }
+      \sstsubsection{
+         rap = double $*$ (Given)
+      }{
+         Geocentric apparent right ascension
+      }
+      \sstsubsection{
+         dap = double $*$ (Given)
+      }{
+         Geocentric apparent declination
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Only the first character of the TYPE argument is significant.
+         {\tt '}R{\tt '} or {\tt '}r{\tt '} indicates that OBS1 and OBS2 are the observed right
+         ascension and declination;  {\tt '}H{\tt '} or {\tt '}h{\tt '} indicates that they are
+         hour angle (west $+$ve) and declination;  anything else ({\tt '}A{\tt '} or
+         {\tt '}a{\tt '} is recommended) indicates that OBS1 and OBS2 are azimuth
+         (north zero, east 90 deg) and zenith distance.  (Zenith
+         distance is used rather than elevation in order to reflect the
+         fact that no allowance is made for depression of the horizon.)
+
+         \sstitem
+         The accuracy of the result is limited by the corrections for
+         refraction.  Providing the meteorological parameters are
+         known accurately and there are no gross local effects, the
+         predicted apparent RA,Dec should be within about 0.1 arcsec
+         for a zenith distance of less than 70 degrees.  Even at a
+         topocentric zenith distance of 90 degrees, the accuracy in
+         elevation should be better than 1 arcmin;  useful results
+         are available for a further 3 degrees, beyond which the
+         palRefro routine returns a fixed value of the refraction.
+         The complementary routines palAop (or palAopqk) and palOap
+         (or palOapqk) are self-consistent to better than 1 micro-
+         arcsecond all over the celestial sphere.
+
+         \sstitem
+         It is advisable to take great care with units, as even
+         unlikely values of the input parameters are accepted and
+         processed in accordance with the models used.
+
+         \sstitem
+         {\tt "}Observed{\tt "} Az,El means the position that would be seen by a
+         perfect theodolite located at the observer.  This is
+         related to the observed HA,Dec via the standard rotation, using
+         the geodetic latitude (corrected for polar motion), while the
+         observed HA and RA are related simply through the local
+         apparent ST.  {\tt "}Observed{\tt "} RA,Dec or HA,Dec thus means the
+         position that would be seen by a perfect equatorial located
+         at the observer and with its polar axis aligned to the
+         Earth{\tt '}s axis of rotation (n.b. not to the refracted pole).
+         By removing from the observed place the effects of
+         atmospheric refraction and diurnal aberration, the
+         geocentric apparent RA,Dec is obtained.
+
+         \sstitem
+         Frequently, mean rather than apparent RA,Dec will be required,
+         in which case further transformations will be necessary.  The
+         palAmp etc routines will convert the apparent RA,Dec produced
+         by the present routine into an {\tt "}FK5{\tt "} (J2000) mean place, by
+         allowing for the Sun{\tt '}s gravitational lens effect, annual
+         aberration, nutation and precession.  Should {\tt "}FK4{\tt "} (1950)
+         coordinates be needed, the routines palFk524 etc will also
+         need to be applied.
+
+         \sstitem
+         To convert to apparent RA,Dec the coordinates read from a
+         real telescope, corrections would have to be applied for
+         encoder zero points, gear and encoder errors, tube flexure,
+         the position of the rotator axis and the pointing axis
+         relative to it, non-perpendicularity between the mounting
+         axes, and finally for the tilt of the azimuth or polar axis
+         of the mounting (with appropriate corrections for mount
+         flexures).  Some telescopes would, of course, exhibit other
+         properties which would need to be accounted for at the
+         appropriate point in the sequence.
+
+         \sstitem
+         This routine takes time to execute, due mainly to the rigorous
+         integration used to evaluate the refraction.  For processing
+         multiple stars for one location and time, call palAoppa once
+         followed by one call per star to palOapqk.  Where a range of
+         times within a limited period of a few hours is involved, and the
+         highest precision is not required, call palAoppa once, followed
+         by a call to palAoppat each time the time changes, followed by
+         one call per star to palOapqk.
+
+         \sstitem
+         The DATE argument is UTC expressed as an MJD.  This is, strictly
+         speaking, wrong, because of leap seconds.  However, as long as
+         the delta UT and the UTC are consistent there are no
+         difficulties, except during a leap second.  In this case, the
+         start of the 61st second of the final minute should begin a new
+         MJD day and the old pre-leap delta UT should continue to be used.
+         As the 61st second completes, the MJD should revert to the start
+         of the day as, simultaneously, the delta UTC changes by one
+         second to its post-leap new value.
+
+         \sstitem
+         The delta UT (UT1-UTC) is tabulated in IERS circulars and
+         elsewhere.  It increases by exactly one second at the end of
+         each UTC leap second, introduced in order to keep delta UT
+         within $+$/- 0.9 seconds.
+
+         \sstitem
+         IMPORTANT -- TAKE CARE WITH THE LONGITUDE SIGN CONVENTION.
+         The longitude required by the present routine is east-positive,
+         in accordance with geographical convention (and right-handed).
+         In particular, note that the longitudes returned by the
+         palOBS routine are west-positive, following astronomical
+         usage, and must be reversed in sign before use in the present
+         routine.
+
+         \sstitem
+         The polar coordinates XP,YP can be obtained from IERS
+         circulars and equivalent publications.  The maximum amplitude
+         is about 0.3 arcseconds.  If XP,YP values are unavailable,
+         use XP=YP=0D0.  See page B60 of the 1988 Astronomical Almanac
+         for a definition of the two angles.
+
+         \sstitem
+         The height above sea level of the observing station, HM,
+         can be obtained from the Astronomical Almanac (Section J
+         in the 1988 edition), or via the routine palOBS.  If P,
+         the pressure in millibars, is available, an adequate
+         estimate of HM can be obtained from the expression
+
+      }
+             HM $\sim$ -29.3$*$TSL$*$LOG(P/1013.25).
+
+      where TSL is the approximate sea-level air temperature in K
+      (see Astrophysical Quantities, C.W.Allen, 3rd edition,
+      section 52).  Similarly, if the pressure P is not known,
+      it can be estimated from the height of the observing
+      station, HM, as follows:
+
+             P $\sim$ 1013.25$*$EXP(-HM/(29.3$*$TSL)).
+
+      Note, however, that the refraction is nearly proportional to the
+      pressure and that an accurate P value is important for precise
+      work.
+
+      \sstitemlist{
+
+         \sstitem
+         The azimuths etc. used by the present routine are with respect
+         to the celestial pole.  Corrections from the terrestrial pole
+         can be computed using palPolmo.
+      }
+   }
+}
+\sstroutine{
+   palOapqk
+}{
+   Quick observed to apparent place
+}{
+   \sstdescription{
+      type = const char $*$ (Given)
+         Type of coordinates - {\tt '}R{\tt '}, {\tt '}H{\tt '} or {\tt '}A{\tt '} (see below)
+      ob1 = double (Given)
+         Observed Az, HA or RA (radians; Az is N=0;E=90)
+      ob2 = double (Given)
+         Observed ZD or Dec (radians)
+      aoprms = const double [14] (Given)
+         Star-independent apparent-to-observed parameters.
+         See palAopqk for details.
+      rap = double $*$ (Given)
+         Geocentric apparent right ascension
+      dap = double $*$ (Given)
+         Geocentric apparent declination
+   }
+   \sstinvocation{
+      void palOapqk ( const char $*$type, double ob1, double ob2,
+                      const  double aoprms[14], double $*$rap, double $*$dap );
+   }
+   \sstarguments{
+      \sstsubsection{
+         Quick observed to apparent place.
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Only the first character of the TYPE argument is significant.
+         {\tt '}R{\tt '} or {\tt '}r{\tt '} indicates that OBS1 and OBS2 are the observed right
+         ascension and declination;  {\tt '}H{\tt '} or {\tt '}h{\tt '} indicates that they are
+         hour angle (west $+$ve) and declination;  anything else ({\tt '}A{\tt '} or
+         {\tt '}a{\tt '} is recommended) indicates that OBS1 and OBS2 are azimuth
+         (north zero, east 90 deg) and zenith distance.  (Zenith distance
+         is used rather than elevation in order to reflect the fact that
+         no allowance is made for depression of the horizon.)
+
+         \sstitem
+         The accuracy of the result is limited by the corrections for
+         refraction.  Providing the meteorological parameters are
+         known accurately and there are no gross local effects, the
+         predicted apparent RA,Dec should be within about 0.1 arcsec
+         for a zenith distance of less than 70 degrees.  Even at a
+         topocentric zenith distance of 90 degrees, the accuracy in
+         elevation should be better than 1 arcmin;  useful results
+         are available for a further 3 degrees, beyond which the
+         palREFRO routine returns a fixed value of the refraction.
+         The complementary routines palAop (or palAopqk) and palOap
+         (or palOapqk) are self-consistent to better than 1 micro-
+         arcsecond all over the celestial sphere.
+
+         \sstitem
+         It is advisable to take great care with units, as even
+         unlikely values of the input parameters are accepted and
+         processed in accordance with the models used.
+
+         \sstitem
+         {\tt "}Observed{\tt "} Az,El means the position that would be seen by a
+         perfect theodolite located at the observer.  This is
+         related to the observed HA,Dec via the standard rotation, using
+         the geodetic latitude (corrected for polar motion), while the
+         observed HA and RA are related simply through the local
+         apparent ST.  {\tt "}Observed{\tt "} RA,Dec or HA,Dec thus means the
+         position that would be seen by a perfect equatorial located
+         at the observer and with its polar axis aligned to the
+         Earth{\tt '}s axis of rotation (n.b. not to the refracted pole).
+         By removing from the observed place the effects of
+         atmospheric refraction and diurnal aberration, the
+         geocentric apparent RA,Dec is obtained.
+
+         \sstitem
+         Frequently, mean rather than apparent RA,Dec will be required,
+         in which case further transformations will be necessary.  The
+         palAmp etc routines will convert the apparent RA,Dec produced
+         by the present routine into an {\tt "}FK5{\tt "} (J2000) mean place, by
+         allowing for the Sun{\tt '}s gravitational lens effect, annual
+         aberration, nutation and precession.  Should {\tt "}FK4{\tt "} (1950)
+         coordinates be needed, the routines palFk524 etc will also
+         need to be applied.
+
+         \sstitem
+         To convert to apparent RA,Dec the coordinates read from a
+         real telescope, corrections would have to be applied for
+         encoder zero points, gear and encoder errors, tube flexure,
+         the position of the rotator axis and the pointing axis
+         relative to it, non-perpendicularity between the mounting
+         axes, and finally for the tilt of the azimuth or polar axis
+         of the mounting (with appropriate corrections for mount
+         flexures).  Some telescopes would, of course, exhibit other
+         properties which would need to be accounted for at the
+         appropriate point in the sequence.
+
+         \sstitem
+         The star-independent apparent-to-observed-place parameters
+         in AOPRMS may be computed by means of the palAoppa routine.
+         If nothing has changed significantly except the time, the
+         palAoppat routine may be used to perform the requisite
+         partial recomputation of AOPRMS.
+
+         \sstitem
+         The azimuths etc used by the present routine are with respect
+         to the celestial pole.  Corrections from the terrestrial pole
+         can be computed using palPolmo.
+      }
+   }
+}
+\sstroutine{
+   palObs
+}{
+   Parameters of selected ground-based observing stations
+}{
+   \sstdescription{
+      Station numbers, identifiers, names and other details are
+      subject to change and should not be hardwired into
+      application programs.
+
+      All characters in {\tt "}c{\tt "} up to the first space are
+      checked;  thus an abbreviated ID will return the parameters
+      for the first station in the list which matches the
+      abbreviation supplied, and no station in the list will ever
+      contain embedded spaces. {\tt "}c{\tt "} must not have leading spaces.
+
+      IMPORTANT -- BEWARE OF THE LONGITUDE SIGN CONVENTION.  The
+      longitude returned by sla\_OBS is west-positive in accordance
+      with astronomical usage.  However, this sign convention is
+      left-handed and is the opposite of the one used by geographers;
+      elsewhere in PAL the preferable east-positive convention is
+      used.  In particular, note that for use in palAop, palAoppa
+      and palOap the sign of the longitude must be reversed.
+
+      Users are urged to inform the author of any improvements
+      they would like to see made.  For example:
+
+          typographical corrections
+          more accurate parameters
+          better station identifiers or names
+          additional stations
+   }
+   \sstinvocation{
+      int palObs( size\_t n, const char $*$ c,
+                  char $*$ ident, size\_t identlen,
+                  char $*$ name, size\_t namelen,
+                  double $*$ w, double $*$ p, double $*$ h );
+   }
+   \sstarguments{
+      \sstsubsection{
+         n = size\_t (Given)
+      }{
+         Number specifying the observing station. If 0
+         the identifier in {\tt "}c{\tt "} is used to determine the
+         observing station to use.
+      }
+      \sstsubsection{
+         c = const char $*$ (Given)
+      }{
+         Identifier specifying the observing station for
+         which the parameters should be returned. Only used
+         if n is 0. Can be NULL for n$>$0. Case insensitive.
+      }
+      \sstsubsection{
+         ident = char $*$ (Returned)
+      }{
+         Identifier of the observing station selected. Will be
+         identical to {\tt "}c{\tt "} if n==0. Unchanged if {\tt "}n{\tt "} or {\tt "}c{\tt "}
+         do not match an observing station. Should be at least
+         11 characters (including the trailing nul).
+      }
+      \sstsubsection{
+         identlen = size\_t (Given)
+      }{
+         Size of the buffer {\tt "}ident{\tt "} including trailing nul.
+      }
+      \sstsubsection{
+         name = char $*$ (Returned)
+      }{
+         Full name of the specified observing station. Contains {\tt "}?{\tt "}
+         if {\tt "}n{\tt "} or {\tt "}c{\tt "} did not correspond to a valid station. Should
+         be at least 41 characters (including the trailing nul).
+      }
+      \sstsubsection{
+         w = double $*$ (Returned)
+      }{
+         Longitude (radians, West $+$ve). Unchanged if observing
+         station could not be identified.
+      }
+      \sstsubsection{
+         p = double $*$ (Returned)
+      }{
+         Geodetic latitude (radians, North $+$ve). Unchanged if observing
+         station could not be identified.
+      }
+      \sstsubsection{
+         h = double $*$ (Returned)
+      }{
+         Height above sea level (metres). Unchanged if observing
+         station could not be identified.
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         palObs = int
+      }{
+         0 if an observing station was returned. -1 if no match was
+         found.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Differs from the SLA interface in that the output short name
+           is not the same variable as the input short name. This simplifies
+           consting. Additionally the size of the output buffers are now
+           specified in the API and a status integer is returned.
+      }
+   }
+}
+\sstroutine{
+   palPa
+}{
+   HA, Dec to Parallactic Angle
+}{
+   \sstdescription{
+      Converts HA, Dec to Parallactic Angle.
+   }
+   \sstinvocation{
+      double palPa( double ha, double dec, double phi );
+   }
+   \sstarguments{
+      \sstsubsection{
+         ha = double (Given)
+      }{
+         Hour angle in radians (Geocentric apparent)
+      }
+      \sstsubsection{
+         dec = double (Given)
+      }{
+         Declination in radians (Geocentric apparent)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observatory latitude in radians (geodetic)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         palPa = double
+      }{
+         Parallactic angle in the range -pi to $+$pi.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The parallactic angle at a point in the sky is the position
+           angle of the vertical, i.e. the angle between the direction to
+           the pole and to the zenith.  In precise applications care must
+           be taken only to use geocentric apparent HA,Dec and to consider
+           separately the effects of atmospheric refraction and telescope
+           mount errors.
+
+         \sstitem
+         At the pole a zero result is returned.
+      }
+   }
+}
+\sstroutine{
+   palPcd
+}{
+   Apply pincushion/barrel distortion to a tangent-plane [x,y]
+}{
+   \sstdescription{
+      Applies pincushion and barrel distortion to a tangent
+      plane coordinate.
+   }
+   \sstinvocation{
+      palPcd( double disco, double $*$ x, double $*$ y );
+   }
+   \sstarguments{
+      \sstsubsection{
+         disco = double (Given)
+      }{
+         Pincushion/barrel distortion coefficient.
+      }
+      \sstsubsection{
+         x = double $*$ (Given \& Returned)
+      }{
+         On input the tangent-plane X coordinate, on output
+         the distorted X coordinate.
+      }
+      \sstsubsection{
+         y = double $*$ (Given \& Returned)
+      }{
+         On input the tangent-plane Y coordinate, on output
+         the distorted Y coordinate.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The distortion is of the form RP = R$*$(1 $+$ C$*$R$*$$*$2), where R is
+           the radial distance from the tangent point, C is the DISCO
+           argument, and RP is the radial distance in the presence of
+           the distortion.
+
+         \sstitem
+         For pincushion distortion, C is $+$ve;  for barrel distortion,
+           C is -ve.
+
+         \sstitem
+         For X,Y in units of one projection radius (in the case of
+           a photographic plate, the focal length), the following
+           DISCO values apply:
+
+\begin{center}
+\begin{tabular}{ll}
+            Geometry          &DISCO \\
+\hline
+            astrograph        & 0.0 \\
+            Schmidt           &-0.3333 \\
+            AAT PF doublet  &$+$147.069 \\
+            AAT PF triplet  &$+$178.585 \\
+            AAT f/8          &$+$21.20 \\
+            JKT f/8          &$+$13.32 \\
+\end{tabular}
+\end{center}
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         There is a companion routine, palUnpcd, which performs the
+           inverse operation.
+      }
+   }
+}
+
+\sstroutine{
+   palPertel
+}{
+   Update elements by applying planetary perturbations
+}{
+   \sstdescription{
+      Update the osculating orbital elements of an asteroid or comet by
+      applying planetary perturbations.
+   }
+   \sstinvocation{
+      void palPertel (int jform, double date0, double date1,
+                      double epoch0, double orbi0, double anode0,
+                      double perih0, double aorq0, double e0, double am0,
+                      double $*$epoch1, double $*$orbi1, double $*$anode1,
+                      double $*$perih1, double $*$aorq1, double $*$e1, double $*$am1,
+                      int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         jform = int (Given)
+      }{
+         Element set actually returned (1-3; Note 6)
+      }
+      \sstsubsection{
+         date0 = double (Given)
+      }{
+         Date of osculation (TT MJD) for the given elements.
+      }
+      \sstsubsection{
+         date1 = double (Given)
+      }{
+         Date of osculation (TT MJD) for the updated elements.
+      }
+      \sstsubsection{
+         epoch0 = double (Given)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbi0 = double (Given)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode0 = double (Given)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih0 = double (Given)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq0 = double (Given)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e0 = double (Given)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         am0 = double (Given)
+      }{
+         mean anomaly (radians, JFORM=2 only)
+      }
+      \sstsubsection{
+         epoch1 = double $*$ (Returned)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbi1 = double $*$ (Returned)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode1 = double $*$ (Returned)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih1 = double $*$ (Returned)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq1 = double $*$ (Returned)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e1 = double $*$ (Returned)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         am1 = double $*$ (Returned)
+      }{
+         mean anomaly (radians, JFORM=2 only)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:
+         \sstitemlist{
+
+            \sstitem
+              $+$102 = warning, distant epoch
+
+            \sstitem
+              $+$101 = warning, large timespan ( $>$ 100 years)
+
+            \sstitem
+              $+$1 to $+$10 = coincident with planet (Note 6)
+
+            \sstitem
+              0 = OK
+
+            \sstitem
+              -1 = illegal JFORM
+
+            \sstitem
+              -2 = illegal E0
+
+            \sstitem
+              -3 = illegal AORQ0
+
+            \sstitem
+              -4 = internal error
+
+            \sstitem
+              -5 = numerical error
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Two different element-format options are available:
+
+      }
+        Option JFORM=2, suitable for minor planets:
+
+        EPOCH   = epoch of elements (TT MJD)
+        ORBI    = inclination i (radians)
+        ANODE   = longitude of the ascending node, big omega (radians)
+        PERIH   = argument of perihelion, little omega (radians)
+        AORQ    = mean distance, a (AU)
+        E       = eccentricity, e
+        AM      = mean anomaly M (radians)
+
+        Option JFORM=3, suitable for comets:
+
+        EPOCH   = epoch of perihelion (TT MJD)
+        ORBI    = inclination i (radians)
+        ANODE   = longitude of the ascending node, big omega (radians)
+        PERIH   = argument of perihelion, little omega (radians)
+        AORQ    = perihelion distance, q (AU)
+        E       = eccentricity, e
+
+      \sstitemlist{
+
+         \sstitem
+         DATE0, DATE1, EPOCH0 and EPOCH1 are all instants of time in
+           the TT timescale (formerly Ephemeris Time, ET), expressed
+           as Modified Julian Dates (JD-2400000.5).
+
+      }
+        DATE0 is the instant at which the given (i.e. unperturbed)
+        osculating elements are correct.
+
+        DATE1 is the specified instant at which the updated osculating
+        elements are correct.
+
+        EPOCH0 and EPOCH1 will be the same as DATE0 and DATE1
+        (respectively) for the JFORM=2 case, normally used for minor
+        planets.  For the JFORM=3 case, the two epochs will refer to
+        perihelion passage and so will not, in general, be the same as
+        DATE0 and/or DATE1 though they may be similar to one another.
+      \sstitemlist{
+
+         \sstitem
+         The elements are with respect to the J2000 ecliptic and equinox.
+
+         \sstitem
+         Unused elements (AM0 and AM1 for JFORM=3) are not accessed.
+
+         \sstitem
+         See the palPertue routine for details of the algorithm used.
+
+         \sstitem
+         This routine is not intended to be used for major planets, which
+           is why JFORM=1 is not available and why there is no opportunity
+           to specify either the longitude of perihelion or the daily
+           motion.  However, if JFORM=2 elements are somehow obtained for a
+           major planet and supplied to the routine, sensible results will,
+           in fact, be produced.  This happens because the sla\_PERTUE routine
+           that is called to perform the calculations checks the separation
+           between the body and each of the planets and interprets a
+           suspiciously small value (0.001 AU) as an attempt to apply it to
+           the planet concerned.  If this condition is detected, the
+           contribution from that planet is ignored, and the status is set to
+           the planet number (1-10 = Mercury, Venus, EMB, Mars, Jupiter,
+           Saturn, Uranus, Neptune, Earth, Moon) as a warning.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Sterne, Theodore E., {\tt "}An Introduction to Celestial Mechanics{\tt "},
+           Interscience Publishers Inc., 1960.  Section 6.7, p199.
+      }
+   }
+}
+\sstroutine{
+   palPertue
+}{
+   Update the universal elements by applying planetary perturbations
+}{
+   \sstdescription{
+      Update the universal elements of an asteroid or comet by applying
+      planetary perturbations.
+   }
+   \sstinvocation{
+      void palPertue( double date, double u[13], int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Final epoch (TT MJD) for the update elements.
+      }
+      \sstsubsection{
+         u = const double [13] (Given \& Returned)
+      }{
+         Universal orbital elements (Note 1)
+             (0)  combined mass (M$+$m)
+             (1)  total energy of the orbit (alpha)
+             (2)  reference (osculating) epoch (t0)
+           (3-5)  position at reference epoch (r0)
+           (6-8)  velocity at reference epoch (v0)
+             (9)  heliocentric distance at reference epoch
+            (10)  r0.v0
+            (11)  date (t)
+            (12)  universal eccentric anomaly (psi) of date, approx
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:
+                    $+$102 = warning, distant epoch
+                    $+$101 = warning, large timespan ( $>$ 100 years)
+               $+$1 to $+$10 = coincident with major planet (Note 5)
+                       0 = OK
+         \sstitemlist{
+
+            \sstitem
+                         1 = numerical error
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The {\tt "}universal{\tt "} elements are those which define the orbit for the
+           purposes of the method of universal variables (see reference 2).
+           They consist of the combined mass of the two bodies, an epoch,
+           and the position and velocity vectors (arbitrary reference frame)
+           at that epoch.  The parameter set used here includes also various
+           quantities that can, in fact, be derived from the other
+           information.  This approach is taken to avoiding unnecessary
+           computation and loss of accuracy.  The supplementary quantities
+           are (i) alpha, which is proportional to the total energy of the
+           orbit, (ii) the heliocentric distance at epoch, (iii) the
+           outwards component of the velocity at the given epoch, (iv) an
+           estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+           date and (v) that date.
+
+         \sstitem
+         The universal elements are with respect to the J2000 equator and
+           equinox.
+
+         \sstitem
+         The epochs DATE, U(3) and U(12) are all Modified Julian Dates
+           (JD-2400000.5).
+
+         \sstitem
+         The algorithm is a simplified form of Encke{\tt '}s method.  It takes as
+           a basis the unperturbed motion of the body, and numerically
+           integrates the perturbing accelerations from the major planets.
+           The expression used is essentially Sterne{\tt '}s 6.7-2 (reference 1).
+           Everhart and Pitkin (reference 2) suggest rectifying the orbit at
+           each integration step by propagating the new perturbed position
+           and velocity as the new universal variables.  In the present
+           routine the orbit is rectified less frequently than this, in order
+           to gain a slight speed advantage.  However, the rectification is
+           done directly in terms of position and velocity, as suggested by
+           Everhart and Pitkin, bypassing the use of conventional orbital
+           elements.
+
+      }
+        The f(q) part of the full Encke method is not used.  The purpose
+        of this part is to avoid subtracting two nearly equal quantities
+        when calculating the {\tt "}indirect member{\tt "}, which takes account of the
+        small change in the Sun{\tt '}s attraction due to the slightly displaced
+        position of the perturbed body.  A simpler, direct calculation in
+        double precision proves to be faster and not significantly less
+        accurate.
+
+        Apart from employing a variable timestep, and occasionally
+        {\tt "}rectifying the orbit{\tt "} to keep the indirect member small, the
+        integration is done in a fairly straightforward way.  The
+        acceleration estimated for the middle of the timestep is assumed
+        to apply throughout that timestep;  it is also used in the
+        extrapolation of the perturbations to the middle of the next
+        timestep, to predict the new disturbed position.  There is no
+        iteration within a timestep.
+
+        Measures are taken to reach a compromise between execution time
+        and accuracy.  The starting-point is the goal of achieving
+        arcsecond accuracy for ordinary minor planets over a ten-year
+        timespan.  This goal dictates how large the timesteps can be,
+        which in turn dictates how frequently the unperturbed motion has
+        to be recalculated from the osculating elements.
+
+        Within predetermined limits, the timestep for the numerical
+        integration is varied in length in inverse proportion to the
+        magnitude of the net acceleration on the body from the major
+        planets.
+
+        The numerical integration requires estimates of the major-planet
+        motions.  Approximate positions for the major planets (Pluto
+        alone is omitted) are obtained from the routine palPlanet.  Two
+        levels of interpolation are used, to enhance speed without
+        significantly degrading accuracy.  At a low frequency, the routine
+        palPlanet is called to generate updated position$+$velocity {\tt "}state
+        vectors{\tt "}.  The only task remaining to be carried out at the full
+        frequency (i.e. at each integration step) is to use the state
+        vectors to extrapolate the planetary positions.  In place of a
+        strictly linear extrapolation, some allowance is made for the
+        curvature of the orbit by scaling back the radius vector as the
+        linear extrapolation goes off at a tangent.
+
+        Various other approximations are made.  For example, perturbations
+        by Pluto and the minor planets are neglected and relativistic
+        effects are not taken into account.
+
+        In the interests of simplicity, the background calculations for
+        the major planets are carried out en masse.  The mean elements and
+        state vectors for all the planets are refreshed at the same time,
+        without regard for orbit curvature, mass or proximity.
+
+        The Earth-Moon system is treated as a single body when the body is
+        distant but as separate bodies when closer to the EMB than the
+        parameter RNE, which incurs a time penalty but improves accuracy
+        for near-Earth objects.
+
+      \sstitemlist{
+
+         \sstitem
+         This routine is not intended to be used for major planets.
+           However, if major-planet elements are supplied, sensible results
+           will, in fact, be produced.  This happens because the routine
+           checks the separation between the body and each of the planets and
+           interprets a suspiciously small value (0.001 AU) as an attempt to
+           apply the routine to the planet concerned.  If this condition is
+           detected, the contribution from that planet is ignored, and the
+           status is set to the planet number (1-10 = Mercury, Venus, EMB,
+           Mars, Jupiter, Saturn, Uranus, Neptune, Earth, Moon) as a warning.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Sterne, Theodore E., {\tt "}An Introduction to Celestial Mechanics{\tt "},
+           Interscience Publishers Inc., 1960.  Section 6.7, p199.
+
+         \sstitem
+         Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+      }
+   }
+}
+\sstroutine{
+   palPlanel
+}{
+   Transform conventional elements into position and velocity
+}{
+   \sstdescription{
+      Heliocentric position and velocity of a planet, asteroid or comet,
+      starting from orbital elements.
+   }
+   \sstinvocation{
+      void palPlanel ( double date, int jform, double epoch, double orbinc,
+                       double anode, double perih, double aorq, double e,
+                       double aorl, double dm, double pv[6], int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Epoch (TT MJD) of osculation (Note 1)
+      }
+      \sstsubsection{
+         jform = int (Given)
+      }{
+         Element set actually returned (1-3; Note 3)
+      }
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Epoch of elements (TT MJD) (Note 4)
+      }
+      \sstsubsection{
+         orbinc = double (Given)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode = double (Given)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih = double (Given)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq = double (Given)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e = double (Given)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         aorl = double (Given)
+      }{
+         mean anomaly or longitude (radians, JFORM=1,2 only)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         daily motion (radians, JFORM=1 only)
+      }
+      \sstsubsection{
+         u = double [13] (Returned)
+      }{
+         Universal orbital elements (Note 1)
+             (0)  combined mass (M$+$m)
+             (1)  total energy of the orbit (alpha)
+             (2)  reference (osculating) epoch (t0)
+           (3-5)  position at reference epoch (r0)
+           (6-8)  velocity at reference epoch (v0)
+             (9)  heliocentric distance at reference epoch
+            (10)  r0.v0
+            (11)  date (t)
+            (12)  universal eccentric anomaly (psi) of date, approx
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:  0 = OK
+         \sstitemlist{
+
+            \sstitem
+                  -1 = illegal JFORM
+
+            \sstitem
+                  -2 = illegal E
+
+            \sstitem
+                  -3 = illegal AORQ
+
+            \sstitem
+                  -4 = illegal DM
+
+            \sstitem
+                  -5 = numerical error
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         DATE is the instant for which the prediction is required.  It is
+           in the TT timescale (formerly Ephemeris Time, ET) and is a
+           Modified Julian Date (JD-2400000.5).
+
+         \sstitem
+         The elements are with respect to the J2000 ecliptic and equinox.
+
+         \sstitem
+         A choice of three different element-set options is available:
+
+      }
+        Option JFORM = 1, suitable for the major planets:
+
+          EPOCH  = epoch of elements (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = longitude of perihelion, curly pi (radians)
+          AORQ   = mean distance, a (AU)
+          E      = eccentricity, e (range 0 to $<$1)
+          AORL   = mean longitude L (radians)
+          DM     = daily motion (radians)
+
+        Option JFORM = 2, suitable for minor planets:
+
+          EPOCH  = epoch of elements (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = argument of perihelion, little omega (radians)
+          AORQ   = mean distance, a (AU)
+          E      = eccentricity, e (range 0 to $<$1)
+          AORL   = mean anomaly M (radians)
+
+        Option JFORM = 3, suitable for comets:
+
+          EPOCH  = epoch of elements and perihelion (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = argument of perihelion, little omega (radians)
+          AORQ   = perihelion distance, q (AU)
+          E      = eccentricity, e (range 0 to 10)
+
+        Unused arguments (DM for JFORM=2, AORL and DM for JFORM=3) are not
+        accessed.
+      \sstitemlist{
+
+         \sstitem
+         Each of the three element sets defines an unperturbed heliocentric
+           orbit.  For a given epoch of observation, the position of the body
+           in its orbit can be predicted from these elements, which are
+           called {\tt "}osculating elements{\tt "}, using standard two-body analytical
+           solutions.  However, due to planetary perturbations, a given set
+           of osculating elements remains usable for only as long as the
+           unperturbed orbit that it describes is an adequate approximation
+           to reality.  Attached to such a set of elements is a date called
+           the {\tt "}osculating epoch{\tt "}, at which the elements are, momentarily,
+           a perfect representation of the instantaneous position and
+           velocity of the body.
+
+      }
+        Therefore, for any given problem there are up to three different
+        epochs in play, and it is vital to distinguish clearly between
+        them:
+
+        . The epoch of observation:  the moment in time for which the
+          position of the body is to be predicted.
+
+        . The epoch defining the position of the body:  the moment in time
+          at which, in the absence of purturbations, the specified
+          position (mean longitude, mean anomaly, or perihelion) is
+          reached.
+
+        . The osculating epoch:  the moment in time at which the given
+          elements are correct.
+
+        For the major-planet and minor-planet cases it is usual to make
+        the epoch that defines the position of the body the same as the
+        epoch of osculation.  Thus, only two different epochs are
+        involved:  the epoch of the elements and the epoch of observation.
+
+        For comets, the epoch of perihelion fixes the position in the
+        orbit and in general a different epoch of osculation will be
+        chosen.  Thus, all three types of epoch are involved.
+
+        For the present routine:
+
+        . The epoch of observation is the argument DATE.
+
+        . The epoch defining the position of the body is the argument
+          EPOCH.
+
+        . The osculating epoch is not used and is assumed to be close
+          enough to the epoch of observation to deliver adequate accuracy.
+          If not, a preliminary call to sla\_PERTEL may be used to update
+          the element-set (and its associated osculating epoch) by
+          applying planetary perturbations.
+      \sstitemlist{
+
+         \sstitem
+         The reference frame for the result is with respect to the mean
+           equator and equinox of epoch J2000.
+
+         \sstitem
+         The algorithm was originally adapted from the EPHSLA program of
+           D.H.P.Jones (private communication, 1996).  The method is based
+           on Stumpff{\tt '}s Universal Variables.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+   }
+}
+\sstroutine{
+   palPlanet
+}{
+   Approximate heliocentric position and velocity of major planet
+}{
+   \sstdescription{
+      Calculates the approximate heliocentric position and velocity of
+      the specified major planet.
+   }
+   \sstinvocation{
+      void palPlanet ( double date, int np, double pv[6], int $*$j );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TDB Modified Julian Date (JD-2400000.5).
+      }
+      \sstsubsection{
+         np = int (Given)
+      }{
+         planet (1=Mercury, 2=Venus, 3=EMB, 4=Mars,
+                 5=Jupiter, 6=Saturn, 7=Uranus, 8=Neptune)
+      }
+      \sstsubsection{
+         pv = double [6] (Returned)
+      }{
+         heliocentric x,y,z,xdot,ydot,zdot, J2000, equatorial triad
+         in units AU and AU/s.
+      }
+      \sstsubsection{
+         j = int $*$ (Returned)
+      }{
+         \sstitemlist{
+
+            \sstitem
+            -2 = solution didn{\tt '}t converge.
+
+            \sstitem
+            -1 = illegal np (1-8)
+
+            \sstitem
+            0 = OK
+
+            \sstitem
+            $+$1 = warning: year outside 1000-3000
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         See SOFA/ERFA eraPlan94 for details
+
+         \sstitem
+         Note that Pluto is supported in SLA/F but not in this routine
+
+         \sstitem
+         Status -2 is equivalent to eraPlan94 status $+$2.
+
+         \sstitem
+         Note that velocity units here match the SLA/F documentation.
+      }
+   }
+}
+\sstroutine{
+   palPlante
+}{
+   Topocentric RA,Dec of a Solar-System object from heliocentric orbital elements
+}{
+   \sstdescription{
+      Topocentric apparent RA,Dec of a Solar-System object whose
+      heliocentric orbital elements are known.
+   }
+   \sstinvocation{
+      void palPlante ( double date, double elong, double phi, int jform,
+                       double epoch, double orbinc, double anode, double perih,
+                       double aorq, double e, double aorl, double dm,
+                       double $*$ra, double $*$dec, double $*$r, int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT MJD of observation (JD-2400000.5)
+      }
+      \sstsubsection{
+         elong = double (Given)
+      }{
+         Observer{\tt '}s east longitude (radians)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observer{\tt '}s geodetic latitude (radians)
+      }
+      \sstsubsection{
+         jform = int (Given)
+      }{
+         Element set actually returned (1-3; Note 6)
+      }
+      \sstsubsection{
+         epoch = double (Given)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbinc = double (Given)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode = double (Given)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih = double (Given)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq = double (Given)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e = double (Given)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         aorl = double (Given)
+      }{
+         mean anomaly or longitude (radians, JFORM=1,2 only)
+      }
+      \sstsubsection{
+         dm = double (Given)
+      }{
+         daily motion (radians, JFORM=1 only)
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         Topocentric apparent RA (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Topocentric apparent Dec (radians)
+      }
+      \sstsubsection{
+         r = double $*$ (Returned)
+      }{
+         Distance from observer (AU)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status: 0 = OK
+         \sstitemlist{
+
+            \sstitem
+                 -1 = illegal jform
+
+            \sstitem
+                 -2 = illegal e
+
+            \sstitem
+                 -3 = illegal aorq
+
+            \sstitem
+                 -4 = illegal dm
+
+            \sstitem
+                 -5 = numerical error
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         DATE is the instant for which the prediction is required.  It is
+           in the TT timescale (formerly Ephemeris Time, ET) and is a
+           Modified Julian Date (JD-2400000.5).
+
+         \sstitem
+         The longitude and latitude allow correction for geocentric
+           parallax.  This is usually a small effect, but can become
+           important for near-Earth asteroids.  Geocentric positions can be
+           generated by appropriate use of routines palEpv (or palEvp) and
+           palUe2pv.
+
+         \sstitem
+         The elements are with respect to the J2000 ecliptic and equinox.
+
+         \sstitem
+         A choice of three different element-set options is available:
+
+      }
+        Option JFORM = 1, suitable for the major planets:
+
+          EPOCH  = epoch of elements (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = longitude of perihelion, curly pi (radians)
+          AORQ   = mean distance, a (AU)
+          E      = eccentricity, e (range 0 to $<$1)
+          AORL   = mean longitude L (radians)
+          DM     = daily motion (radians)
+
+        Option JFORM = 2, suitable for minor planets:
+
+          EPOCH  = epoch of elements (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = argument of perihelion, little omega (radians)
+          AORQ   = mean distance, a (AU)
+          E      = eccentricity, e (range 0 to $<$1)
+          AORL   = mean anomaly M (radians)
+
+        Option JFORM = 3, suitable for comets:
+
+          EPOCH  = epoch of elements and perihelion (TT MJD)
+          ORBINC = inclination i (radians)
+          ANODE  = longitude of the ascending node, big omega (radians)
+          PERIH  = argument of perihelion, little omega (radians)
+          AORQ   = perihelion distance, q (AU)
+          E      = eccentricity, e (range 0 to 10)
+
+        Unused arguments (DM for JFORM=2, AORL and DM for JFORM=3) are not
+        accessed.
+      \sstitemlist{
+
+         \sstitem
+         Each of the three element sets defines an unperturbed heliocentric
+           orbit.  For a given epoch of observation, the position of the body
+           in its orbit can be predicted from these elements, which are
+           called {\tt "}osculating elements{\tt "}, using standard two-body analytical
+           solutions.  However, due to planetary perturbations, a given set
+           of osculating elements remains usable for only as long as the
+           unperturbed orbit that it describes is an adequate approximation
+           to reality.  Attached to such a set of elements is a date called
+           the {\tt "}osculating epoch{\tt "}, at which the elements are, momentarily,
+           a perfect representation of the instantaneous position and
+           velocity of the body.
+
+      }
+        Therefore, for any given problem there are up to three different
+        epochs in play, and it is vital to distinguish clearly between
+        them:
+
+        . The epoch of observation:  the moment in time for which the
+          position of the body is to be predicted.
+
+        . The epoch defining the position of the body:  the moment in time
+          at which, in the absence of purturbations, the specified
+          position (mean longitude, mean anomaly, or perihelion) is
+          reached.
+
+        . The osculating epoch:  the moment in time at which the given
+          elements are correct.
+
+        For the major-planet and minor-planet cases it is usual to make
+        the epoch that defines the position of the body the same as the
+        epoch of osculation.  Thus, only two different epochs are
+        involved:  the epoch of the elements and the epoch of observation.
+
+        For comets, the epoch of perihelion fixes the position in the
+        orbit and in general a different epoch of osculation will be
+        chosen.  Thus, all three types of epoch are involved.
+
+        For the present routine:
+
+        . The epoch of observation is the argument DATE.
+
+        . The epoch defining the position of the body is the argument
+          EPOCH.
+
+        . The osculating epoch is not used and is assumed to be close
+          enough to the epoch of observation to deliver adequate accuracy.
+          If not, a preliminary call to sla\_PERTEL may be used to update
+          the element-set (and its associated osculating epoch) by
+          applying planetary perturbations.
+      \sstitemlist{
+
+         \sstitem
+         Two important sources for orbital elements are Horizons, operated
+           by the Jet Propulsion Laboratory, Pasadena, and the Minor Planet
+           Center, operated by the Center for Astrophysics, Harvard.
+
+      }
+        The JPL Horizons elements (heliocentric, J2000 ecliptic and
+        equinox) correspond to SLALIB arguments as follows.
+
+         Major planets:
+
+          JFORM  = 1
+          EPOCH  = JDCT-2400000.5
+          ORBINC = IN (in radians)
+          ANODE  = OM (in radians)
+          PERIH  = OM$+$W (in radians)
+          AORQ   = A
+          E      = EC
+          AORL   = MA$+$OM$+$W (in radians)
+          DM     = N (in radians)
+
+          Epoch of osculation = JDCT-2400000.5
+
+         Minor planets:
+
+          JFORM  = 2
+          EPOCH  = JDCT-2400000.5
+          ORBINC = IN (in radians)
+          ANODE  = OM (in radians)
+          PERIH  = W (in radians)
+          AORQ   = A
+          E      = EC
+          AORL   = MA (in radians)
+
+          Epoch of osculation = JDCT-2400000.5
+
+         Comets:
+
+          JFORM  = 3
+          EPOCH  = Tp-2400000.5
+          ORBINC = IN (in radians)
+          ANODE  = OM (in radians)
+          PERIH  = W (in radians)
+          AORQ   = QR
+          E      = EC
+
+          Epoch of osculation = JDCT-2400000.5
+
+       The MPC elements correspond to SLALIB arguments as follows.
+
+         Minor planets:
+
+          JFORM  = 2
+          EPOCH  = Epoch-2400000.5
+          ORBINC = Incl. (in radians)
+          ANODE  = Node (in radians)
+          PERIH  = Perih. (in radians)
+          AORQ   = a
+          E      = e
+          AORL   = M (in radians)
+
+          Epoch of osculation = Epoch-2400000.5
+
+        Comets:
+
+          JFORM  = 3
+          EPOCH  = T-2400000.5
+          ORBINC = Incl. (in radians)
+          ANODE  = Node. (in radians)
+          PERIH  = Perih. (in radians)
+          AORQ   = q
+          E      = e
+
+          Epoch of osculation = Epoch-2400000.5
+   }
+}
+\sstroutine{
+   palPlantu
+}{
+   Topocentric RA,Dec of a Solar-System object from universal elements
+}{
+   \sstdescription{
+      Topocentric apparent RA,Dec of a Solar-System object whose
+      heliocentric universal elements are known.
+   }
+   \sstinvocation{
+      void palPlantu ( double date, double elong, double phi, const double u[13],
+                       double $*$ra, double $*$dec, double $*$r, int $*$jstat ) \{
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT MJD of observation (JD-2400000.5)
+      }
+      \sstsubsection{
+         elong = double (Given)
+      }{
+         Observer{\tt '}s east longitude (radians)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observer{\tt '}s geodetic latitude (radians)
+      }
+      \sstsubsection{
+         u = const double [13] (Given)
+      }{
+         Universal orbital elements
+         \sstitemlist{
+
+            \sstitem
+              (0)  combined mass (M$+$m)
+
+            \sstitem
+              (1)  total energy of the orbit (alpha)
+
+            \sstitem
+              (2)  reference (osculating) epoch (t0)
+
+            \sstitem
+              (3-5)  position at reference epoch (r0)
+
+            \sstitem
+              (6-8)  velocity at reference epoch (v0)
+
+            \sstitem
+              (9)  heliocentric distance at reference epoch
+
+            \sstitem
+              (10)  r0.v0
+
+            \sstitem
+              (11)  date (t)
+
+            \sstitem
+              (12)  universal eccentric anomaly (psi) of date, approx
+         }
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         Topocentric apparent RA (radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Topocentric apparent Dec (radians)
+      }
+      \sstsubsection{
+         r = double $*$ (Returned)
+      }{
+         Distance from observer (AU)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status: 0 = OK
+         \sstitemlist{
+
+            \sstitem
+                 -1 = radius vector zero
+
+            \sstitem
+                 -2 = failed to converge
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         DATE is the instant for which the prediction is required.  It is
+           in the TT timescale (formerly Ephemeris Time, ET) and is a
+           Modified Julian Date (JD-2400000.5).
+
+         \sstitem
+         The longitude and latitude allow correction for geocentric
+           parallax.  This is usually a small effect, but can become
+           important for near-Earth asteroids.  Geocentric positions can be
+           generated by appropriate use of routines palEpv (or palEvp) and
+           palUe2pv.
+
+         \sstitem
+         The {\tt "}universal{\tt "} elements are those which define the orbit for the
+           purposes of the method of universal variables (see reference 2).
+           They consist of the combined mass of the two bodies, an epoch,
+           and the position and velocity vectors (arbitrary reference frame)
+           at that epoch.  The parameter set used here includes also various
+           quantities that can, in fact, be derived from the other
+           information.  This approach is taken to avoiding unnecessary
+           computation and loss of accuracy.  The supplementary quantities
+           are (i) alpha, which is proportional to the total energy of the
+           orbit, (ii) the heliocentric distance at epoch, (iii) the
+           outwards component of the velocity at the given epoch, (iv) an
+           estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+           date and (v) that date.
+
+         \sstitem
+         The universal elements are with respect to the J2000 equator and
+           equinox.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Sterne, Theodore E., {\tt "}An Introduction to Celestial Mechanics{\tt "},
+           Interscience Publishers Inc., 1960.  Section 6.7, p199.
+
+         \sstitem
+         Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+      }
+   }
+}
+\sstroutine{
+   palPm
+}{
+   Apply corrections for proper motion a star RA,Dec
+}{
+   \sstdescription{
+      Apply corrections for proper motion to a star RA,Dec using the
+      SOFA/ERFA routine eraStarpm.
+   }
+   \sstinvocation{
+      void palPm ( double r0, double d0, double pr, double pd,
+                   double px, double rv, double ep0, double ep1,
+                   double $*$r1, double $*$d1 );
+   }
+   \sstarguments{
+      \sstsubsection{
+         r0 = double (Given)
+      }{
+         RA at epoch ep0 (radians)
+      }
+      \sstsubsection{
+         d0 = double (Given)
+      }{
+         Dec at epoch ep0 (radians)
+      }
+      \sstsubsection{
+         pr = double (Given)
+      }{
+         RA proper motion in radians per year.
+      }
+      \sstsubsection{
+         pd = double (Given)
+      }{
+         Dec proper motion in radians per year.
+      }
+      \sstsubsection{
+         px = double (Given)
+      }{
+         Parallax (arcsec)
+      }
+      \sstsubsection{
+         rv = double (Given)
+      }{
+         Radial velocity (km/sec $+$ve if receding)
+      }
+      \sstsubsection{
+         ep0 = double (Given)
+      }{
+         Start epoch in years, assumed to be Julian.
+      }
+      \sstsubsection{
+         ep1 = double (Given)
+      }{
+         End epoch in years, assumed to be Julian.
+      }
+      \sstsubsection{
+         r1 = double $*$ (Returned)
+      }{
+         RA at epoch ep1 (radians)
+      }
+      \sstsubsection{
+         d1 = double $*$ (Returned)
+      }{
+         Dec at epoch ep1 (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses eraStarpm but ignores the status returns from that routine.
+           In particular note that parallax should not be zero when the
+           proper motions are non-zero. SLA/F allows parallax to be zero.
+
+         \sstitem
+         Assumes all epochs are Julian epochs.
+      }
+   }
+}
+\sstroutine{
+   palPolmo
+}{
+   Correct for polar motion
+}{
+   \sstdescription{
+      Polar motion:  correct site longitude and latitude for polar
+      motion and calculate azimuth difference between celestial and
+      terrestrial poles.
+   }
+   \sstinvocation{
+      palPolmo ( double elongm, double phim, double xp, double yp,
+                 double $*$elong, double $*$phi, double $*$daz );
+   }
+   \sstarguments{
+      \sstsubsection{
+         elongm = double (Given)
+      }{
+         Mean logitude of the observer (radians, east $+$ve)
+      }
+      \sstsubsection{
+         phim = double (Given)
+      }{
+         Mean geodetic latitude of the observer (radians)
+      }
+      \sstsubsection{
+         xp = double (Given)
+      }{
+         Polar motion x-coordinate (radians)
+      }
+      \sstsubsection{
+         yp = double (Given)
+      }{
+         Polar motion y-coordinate (radians)
+      }
+      \sstsubsection{
+         elong = double $*$ (Returned)
+      }{
+         True longitude of the observer (radians, east $+$ve)
+      }
+      \sstsubsection{
+         phi = double $*$ (Returned)
+      }{
+         True geodetic latitude of the observer (radians)
+      }
+      \sstsubsection{
+         daz = double $*$ (Returned)
+      }{
+         Azimuth correction (terrestrial-celestial, radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         {\tt "}Mean{\tt "} longitude and latitude are the (fixed) values for the
+           site{\tt '}s location with respect to the IERS terrestrial reference
+           frame;  the latitude is geodetic.  TAKE CARE WITH THE LONGITUDE
+           SIGN CONVENTION.  The longitudes used by the present routine
+           are east-positive, in accordance with geographical convention
+           (and right-handed).  In particular, note that the longitudes
+           returned by the sla\_OBS routine are west-positive, following
+           astronomical usage, and must be reversed in sign before use in
+           the present routine.
+
+         \sstitem
+         XP and YP are the (changing) coordinates of the Celestial
+           Ephemeris Pole with respect to the IERS Reference Pole.
+           XP is positive along the meridian at longitude 0 degrees,
+           and YP is positive along the meridian at longitude
+           270 degrees (i.e. 90 degrees west).  Values for XP,YP can
+           be obtained from IERS circulars and equivalent publications;
+           the maximum amplitude observed so far is about 0.3 arcseconds.
+
+         \sstitem
+         {\tt "}True{\tt "} longitude and latitude are the (moving) values for
+           the site{\tt '}s location with respect to the celestial ephemeris
+           pole and the meridian which corresponds to the Greenwich
+           apparent sidereal time.  The true longitude and latitude
+           link the terrestrial coordinates with the standard celestial
+           models (for precession, nutation, sidereal time etc).
+
+         \sstitem
+         The azimuths produced by sla\_AOP and sla\_AOPQK are with
+           respect to due north as defined by the Celestial Ephemeris
+           Pole, and can therefore be called {\tt "}celestial azimuths{\tt "}.
+           However, a telescope fixed to the Earth measures azimuth
+           essentially with respect to due north as defined by the
+           IERS Reference Pole, and can therefore be called {\tt "}terrestrial
+           azimuth{\tt "}.  Uncorrected, this would manifest itself as a
+           changing {\tt "}azimuth zero-point error{\tt "}.  The value DAZ is the
+           correction to be added to a celestial azimuth to produce
+           a terrestrial azimuth.
+
+         \sstitem
+         The present routine is rigorous.  For most practical
+           purposes, the following simplified formulae provide an
+           adequate approximation:
+
+      }
+        elong = elongm$+$xp$*$cos(elongm)-yp$*$sin(elongm)
+        phi   = phim$+$(xp$*$sin(elongm)$+$yp$*$cos(elongm))$*$tan(phim)
+        daz   = -sqrt(xp$*$xp$+$yp$*$yp)$*$cos(elongm-atan2(xp,yp))/cos(phim)
+
+        An alternative formulation for DAZ is:
+
+        x = cos(elongm)$*$cos(phim)
+        y = sin(elongm)$*$cos(phim)
+        daz = atan2(-x$*$yp-y$*$xp,x$*$x$+$y$*$y)
+
+      \sstitemlist{
+
+         \sstitem
+         Reference:  Seidelmann, P.K. (ed), 1992.  {\tt "}Explanatory Supplement
+                       to the Astronomical Almanac{\tt "}, ISBN 0-935702-68-7,
+                       sections 3.27, 4.25, 4.52.
+      }
+   }
+}
+
+\sstroutine{
+   palPrebn
+}{
+   Generate the matrix of precession between two objects (old)
+}{
+   \sstdescription{
+      Generate the matrix of precession between two epochs,
+      using the old, pre-IAU1976, Bessel-Newcomb model, using
+      Kinoshita{\tt '}s formulation
+   }
+   \sstinvocation{
+      void palPrebn ( double bep0, double bep1, double rmatp[3][3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         bep0 = double (Given)
+      }{
+         Beginning Besselian epoch.
+      }
+      \sstsubsection{
+         bep1 = double (Given)
+      }{
+         Ending Besselian epoch
+      }
+      \sstsubsection{
+         rmatp = double[3][3] (Returned)
+      }{
+         precession matrix in the sense V(BEP1) = RMATP $*$ V(BEP0)
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Kinoshita, H. (1975) {\tt '}Formulas for precession{\tt '}, SAO Special
+      Report No. 364, Smithsonian Institution Astrophysical
+      Observatory, Cambridge, Massachusetts.
+   }
+}
+\sstroutine{
+   palPrec
+}{
+   Form the matrix of precession between two epochs (IAU 2006)
+}{
+   \sstdescription{
+      The IAU 2006 precession matrix from ep0 to ep1 is found and
+      returned. The matrix is in the sense  V(EP1)  =  RMATP $*$ V(EP0).
+      The epochs are TDB (loosely TT) Julian epochs.
+
+      Though the matrix method itself is rigorous, the precession
+      angles are expressed through canonical polynomials which are
+      valid only for a limited time span of a few hundred years around
+      the current epoch.
+   }
+   \sstinvocation{
+      palPrec( double ep0, double ep1, double rmatp[3][3] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         ep0 = double (Given)
+      }{
+         Beginning epoch
+      }
+      \sstsubsection{
+         ep1 = double (Given)
+      }{
+         Ending epoch
+      }
+      \sstsubsection{
+         rmatp = double[3][3] (Returned)
+      }{
+         Precession matrix
+      }
+   }
+}
+\sstroutine{
+   palPreces
+}{
+   Precession - either FK4 or FK5 as required
+}{
+   \sstdescription{
+      Precess coordinates using the appropriate system and epochs.
+   }
+   \sstinvocation{
+      void palPreces ( const char sys[3], double ep0, double ep1,
+                       double $*$ra, double $*$dc );
+   }
+   \sstarguments{
+      \sstsubsection{
+         sys = const char [3] (Given)
+      }{
+         Precession to be applied: FK4 or FK5. Case insensitive.
+      }
+      \sstsubsection{
+         ep0 = double (Given)
+      }{
+         Starting epoch.
+      }
+      \sstsubsection{
+         ep1 = double (Given)
+      }{
+         Ending epoch
+      }
+      \sstsubsection{
+         ra = double $*$ (Given \& Returned)
+      }{
+         On input the RA mean equator \& equinox at epoch ep0. On exit
+         the RA mean equator \& equinox of epoch ep1.
+      }
+      \sstsubsection{
+         dec = double $*$ (Given \& Returned)
+      }{
+         On input the dec mean equator \& equinox at epoch ep0. On exit
+         the dec mean equator \& equinox of epoch ep1.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Uses palPrec for FK5 data and palPrebn for FK4 data.
+
+         \sstitem
+         The epochs are Besselian if SYSTEM={\tt '}FK4{\tt '} and Julian if {\tt '}FK5{\tt '}.
+            For example, to precess coordinates in the old system from
+            equinox 1900.0 to 1950.0 the call would be:
+                 palPreces( {\tt "}FK4{\tt "}, 1900.0, 1950.0, \&ra, \&dc );
+
+         \sstitem
+         This routine will NOT correctly convert between the old and
+           the new systems - for example conversion from B1950 to J2000.
+           For these purposes see palFk425, palFk524, palFk45z and
+           palFk54z.
+
+         \sstitem
+         If an invalid SYSTEM is supplied, values of -99D0,-99D0 will
+           be returned for both RA and DC.
+      }
+   }
+}
+\sstroutine{
+   palPrenut
+}{
+   Form the matrix of bias-precession-nutation (IAU 2006/2000A)
+}{
+   \sstdescription{
+      Form the matrix of bias-precession-nutation (IAU 2006/2000A).
+      The epoch and date are TT (but TDB is usually close enough).
+      The matrix is in the sense   v(true)  =  rmatpn $*$ v(mean).
+   }
+   \sstinvocation{
+      void palPrenut( double epoch, double date, double rmatpn[3][3] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         epoch = double (Returned)
+      }{
+         Julian epoch for mean coordinates.
+      }
+      \sstsubsection{
+         date = double (Returned)
+      }{
+         Modified Julian Date (JD-2400000.5) for true coordinates.
+      }
+      \sstsubsection{
+         rmatpn = double[3][3] (Returned)
+      }{
+         combined NPB matrix
+      }
+   }
+}
+\sstroutine{
+   palPv2el
+}{
+   Position velocity to heliocentirc osculating elements
+}{
+   \sstdescription{
+      Heliocentric osculating elements obtained from instantaneous position
+      and velocity.
+   }
+   \sstinvocation{
+      void palPv2el ( const double pv[6], double date, double pmass, int jformr,
+                      int $*$jform, double $*$epoch, double $*$orbinc,
+                      double $*$anode, double $*$perih, double $*$aorq, double $*$e,
+                      double $*$aorl, double $*$dm, int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         pv = const double [6] (Given)
+      }{
+         Heliocentric x,y,z,xdot,ydot,zdot of date,
+         J2000 equatorial triad (AU,AU/s; Note 1)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Date (TT Modified Julian Date = JD-2400000.5)
+      }
+      \sstsubsection{
+         pmass = double (Given)
+      }{
+         Mass of the planet (Sun=1; Note 2)
+      }
+      \sstsubsection{
+         jformr = int (Given)
+      }{
+         Requested element set (1-3; Note 3)
+      }
+      \sstsubsection{
+         jform = int $*$ (Returned)
+      }{
+         Element set actually returned (1-3; Note 4)
+      }
+      \sstsubsection{
+         epoch = double $*$ (Returned)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbinc = double $*$ (Returned)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode = double $*$ (Returned)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih = double $*$ (Returned)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq = double $*$ (Returned)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e = double $*$ (Returned)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         aorl = double $*$ (Returned)
+      }{
+         mean anomaly or longitude (radians, JFORM=1,2 only)
+      }
+      \sstsubsection{
+         dm = double $*$ (Returned)
+      }{
+         daily motion (radians, JFORM=1 only)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:  0 = OK
+         \sstitemlist{
+
+            \sstitem
+                   -1 = illegal PMASS
+
+            \sstitem
+                   -2 = illegal JFORMR
+
+            \sstitem
+                   -3 = position/velocity out of range
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The PV 6-vector is with respect to the mean equator and equinox of
+           epoch J2000.  The orbital elements produced are with respect to
+           the J2000 ecliptic and mean equinox.
+
+         \sstitem
+         The mass, PMASS, is important only for the larger planets.  For
+           most purposes (e.g. asteroids) use 0D0.  Values less than zero
+           are illegal.
+
+         \sstitem
+         Three different element-format options are supported:
+
+      }
+        Option JFORM=1, suitable for the major planets:
+
+        EPOCH  = epoch of elements (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = longitude of perihelion, curly pi (radians)
+        AORQ   = mean distance, a (AU)
+        E      = eccentricity, e
+        AORL   = mean longitude L (radians)
+        DM     = daily motion (radians)
+
+        Option JFORM=2, suitable for minor planets:
+
+        EPOCH  = epoch of elements (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = argument of perihelion, little omega (radians)
+        AORQ   = mean distance, a (AU)
+        E      = eccentricity, e
+        AORL   = mean anomaly M (radians)
+
+        Option JFORM=3, suitable for comets:
+
+        EPOCH  = epoch of perihelion (TT MJD)
+        ORBINC = inclination i (radians)
+        ANODE  = longitude of the ascending node, big omega (radians)
+        PERIH  = argument of perihelion, little omega (radians)
+        AORQ   = perihelion distance, q (AU)
+        E      = eccentricity, e
+
+      \sstitemlist{
+
+         \sstitem
+         It may not be possible to generate elements in the form
+           requested through JFORMR.  The caller is notified of the form
+           of elements actually returned by means of the JFORM argument:
+
+      }
+         JFORMR   JFORM     meaning
+
+           1        1       OK - elements are in the requested format
+           1        2       never happens
+           1        3       orbit not elliptical
+
+           2        1       never happens
+           2        2       OK - elements are in the requested format
+           2        3       orbit not elliptical
+
+           3        1       never happens
+           3        2       never happens
+           3        3       OK - elements are in the requested format
+
+      \sstitemlist{
+
+         \sstitem
+         The arguments returned for each value of JFORM (cf Note 5: JFORM
+           may not be the same as JFORMR) are as follows:
+
+      }
+          JFORM         1              2              3
+          EPOCH         t0             t0             T
+          ORBINC        i              i              i
+          ANODE         Omega          Omega          Omega
+          PERIH         curly pi       omega          omega
+          AORQ          a              a              q
+          E             e              e              e
+          AORL          L              M              -
+          DM            n              -              -
+
+        where:
+
+          t0           is the epoch of the elements (MJD, TT)
+          T              {\tt "}    epoch of perihelion (MJD, TT)
+          i              {\tt "}    inclination (radians)
+          Omega          {\tt "}    longitude of the ascending node (radians)
+          curly pi       {\tt "}    longitude of perihelion (radians)
+          omega          {\tt "}    argument of perihelion (radians)
+          a              {\tt "}    mean distance (AU)
+          q              {\tt "}    perihelion distance (AU)
+          e              {\tt "}    eccentricity
+          L              {\tt "}    longitude (radians, 0-2pi)
+          M              {\tt "}    mean anomaly (radians, 0-2pi)
+          n              {\tt "}    daily motion (radians)
+      \sstitemlist{
+
+         \sstitem
+             means no value is set
+
+         \sstitem
+         At very small inclinations, the longitude of the ascending node
+           ANODE becomes indeterminate and under some circumstances may be
+           set arbitrarily to zero.  Similarly, if the orbit is close to
+           circular, the true anomaly becomes indeterminate and under some
+           circumstances may be set arbitrarily to zero.  In such cases,
+           the other elements are automatically adjusted to compensate,
+           and so the elements remain a valid description of the orbit.
+
+         \sstitem
+         The osculating epoch for the returned elements is the argument
+           DATE.
+
+         \sstitem
+         Reference:  Sterne, Theodore E., {\tt "}An Introduction to Celestial
+                       Mechanics{\tt "}, Interscience Publishers, 1960
+      }
+   }
+}
+\sstroutine{
+   palPv2ue
+}{
+   Universal elements to position and velocity
+}{
+   \sstdescription{
+      Construct a universal element set based on an instantaneous position
+      and velocity.
+   }
+   \sstinvocation{
+      void palPv2ue( const double pv[6], double date, double pmass,
+                     double u[13], int $*$ jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         pv = double [6] (Given)
+      }{
+         Heliocentric x,y,z,xdot,ydot,zdot of date, (AU,AU/s; Note 1)
+      }
+      \sstsubsection{
+         date = double (Given)
+      }{
+         Date (TT modified Julian Date = JD-2400000.5)
+      }
+      \sstsubsection{
+         pmass = double (Given)
+      }{
+         Mass of the planet (Sun=1; note 2)
+      }
+      \sstsubsection{
+         u = double [13] (Returned)
+      }{
+         Universal orbital elements (Note 3)
+
+         \sstitemlist{
+
+            \sstitem
+              (0)  combined mass (M$+$m)
+
+            \sstitem
+              (1)  total energy of the orbit (alpha)
+
+            \sstitem
+              (2)  reference (osculating) epoch (t0)
+
+            \sstitem
+              (3-5)  position at reference epoch (r0)
+
+            \sstitem
+              (6-8)  velocity at reference epoch (v0)
+
+            \sstitem
+              (9)  heliocentric distance at reference epoch
+
+            \sstitem
+              (10)  r0.v0
+
+            \sstitem
+              (11)  date (t)
+
+            \sstitem
+              (12)  universal eccentric anomaly (psi) of date, approx
+         }
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status: 0 = OK
+         \sstitemlist{
+
+            \sstitem
+                   -1 = illegal PMASS
+
+            \sstitem
+                   -2 = too close to Sun
+
+            \sstitem
+                   -3 = too slow
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The PV 6-vector can be with respect to any chosen inertial frame,
+           and the resulting universal-element set will be with respect to
+           the same frame.  A common choice will be mean equator and ecliptic
+           of epoch J2000.
+
+         \sstitem
+         The mass, PMASS, is important only for the larger planets.  For
+           most purposes (e.g. asteroids) use 0D0.  Values less than zero
+           are illegal.
+
+         \sstitem
+         The {\tt "}universal{\tt "} elements are those which define the orbit for the
+           purposes of the method of universal variables (see reference).
+           They consist of the combined mass of the two bodies, an epoch,
+           and the position and velocity vectors (arbitrary reference frame)
+           at that epoch.  The parameter set used here includes also various
+           quantities that can, in fact, be derived from the other
+           information.  This approach is taken to avoiding unnecessary
+           computation and loss of accuracy.  The supplementary quantities
+           are (i) alpha, which is proportional to the total energy of the
+           orbit, (ii) the heliocentric distance at epoch, (iii) the
+           outwards component of the velocity at the given epoch, (iv) an
+           estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+           date and (v) that date.
+
+         \sstitem
+         Reference:  Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+      }
+   }
+}
+\sstroutine{
+   palPvobs
+}{
+   Position and velocity of an observing station
+}{
+   \sstdescription{
+      Returns the position and velocity of an observing station.
+   }
+   \sstinvocation{
+      palPvobs( double p, double h, double stl, double pv[6] )
+   }
+   \sstarguments{
+      \sstsubsection{
+         p = double (Given)
+      }{
+         Latitude (geodetic, radians).
+      }
+      \sstsubsection{
+         h = double (Given)
+      }{
+         Height above reference spheroid (geodetic, metres).
+      }
+      \sstsubsection{
+         stl = double (Given)
+      }{
+         Local apparent sidereal time (radians).
+      }
+      \sstsubsection{
+         pv = double[ 6 ] (Returned)
+      }{
+         position/velocity 6-vector (AU, AU/s, true equator
+                                     and equinox of date).
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The WGS84 reference ellipsoid is used.
+      }
+   }
+}
+\sstroutine{
+   palRdplan
+}{
+   Approximate topocentric apparent RA,Dec of a planet
+}{
+   \sstdescription{
+      Approximate topocentric apparent RA,Dec of a planet, and its
+      angular diameter.
+   }
+   \sstinvocation{
+      void palRdplan( double date, int np, double elong, double phi,
+                      double $*$ ra, double $*$ dec, double $*$ diam );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         MJD of observation (JD-2400000.5) in TDB. For all practical
+         purposes TT can be used instead of TDB, and for many applications
+         UT will do (except for the Moon).
+      }
+      \sstsubsection{
+         np = int (Given)
+      }{
+         Planet: 1 = Mercury
+                 2 = Venus
+                 3 = Moon
+                 4 = Mars
+                 5 = Jupiter
+                 6 = Saturn
+                 7 = Uranus
+                 8 = Neptune
+              else = Sun
+      }
+      \sstsubsection{
+         elong = double (Given)
+      }{
+         Observer{\tt '}s east longitude (radians)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Observer{\tt '}s geodetic latitude (radians)
+      }
+      \sstsubsection{
+         ra = double $*$ (Returned)
+      }{
+         RA (topocentric apparent, radians)
+      }
+      \sstsubsection{
+         dec = double $*$ (Returned)
+      }{
+         Dec (topocentric apparent, radians)
+      }
+      \sstsubsection{
+         diam = double $*$ (Returned)
+      }{
+         Angular diameter (equatorial, radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Unlike with slaRdplan, Pluto is not supported.
+
+         \sstitem
+         The longitude and latitude allow correction for geocentric
+           parallax.  This is a major effect for the Moon, but in the
+           context of the limited accuracy of the present routine its
+           effect on planetary positions is small (negligible for the
+           outer planets).  Geocentric positions can be generated by
+           appropriate use of the routines palDmoon and eraPlan94.
+      }
+   }
+}
+\sstroutine{
+   palRefco
+}{
+   Determine constants in atmospheric refraction model
+}{
+   \sstdescription{
+      Determine the constants A and B in the atmospheric refraction
+      model dZ = A tan Z $+$ B tan$*$$*$3 Z.
+
+      Z is the {\tt "}observed{\tt "} zenith distance (i.e. affected by refraction)
+      and dZ is what to add to Z to give the {\tt "}topocentric{\tt "} (i.e. in vacuo)
+      zenith distance.
+   }
+   \sstinvocation{
+      void palRefco ( double hm, double tdk, double pmb, double rh,
+                      double wl, double phi, double tlr, double eps,
+                      double $*$refa, double $*$refb );
+   }
+   \sstarguments{
+      \sstsubsection{
+         hm = double (Given)
+      }{
+         Height of the observer above sea level (metre)
+      }
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Ambient temperature at the observer (K)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Pressure at the observer (millibar)
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Relative humidity at the observer (range 0-1)
+      }
+      \sstsubsection{
+         wl = double (Given)
+      }{
+         Effective wavelength of the source (micrometre)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Latitude of the observer (radian, astronomical)
+      }
+      \sstsubsection{
+         tlr = double (Given)
+      }{
+         Temperature lapse rate in the troposphere (K/metre)
+      }
+      \sstsubsection{
+         eps = double (Given)
+      }{
+         Precision required to terminate iteration (radian)
+      }
+      \sstsubsection{
+         refa = double $*$ (Returned)
+      }{
+         tan Z coefficient (radian)
+      }
+      \sstsubsection{
+         refb = double $*$ (Returned)
+      }{
+         tan$*$$*$3 Z coefficient (radian)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         Typical values for the TLR and EPS arguments might be 0.0065 and
+         1E-10 respectively.
+
+         \sstitem
+         The radio refraction is chosen by specifying WL $>$ 100 micrometres.
+
+         \sstitem
+         The routine is a slower but more accurate alternative to the
+         palRefcoq routine.  The constants it produces give perfect
+         agreement with palRefro at zenith distances arctan(1) (45 deg)
+         and arctan(4) (about 76 deg).  It achieves 0.5 arcsec accuracy
+         for ZD $<$ 80 deg, 0.01 arcsec accuracy for ZD $<$ 60 deg, and
+         0.001 arcsec accuracy for ZD $<$ 45 deg.
+      }
+   }
+}
+\sstroutine{
+   palRefro
+}{
+   Atmospheric refraction for radio and optical/IR wavelengths
+}{
+   \sstdescription{
+      Calculates the atmospheric refraction for radio and optical/IR
+      wavelengths.
+   }
+   \sstinvocation{
+      void palRefro( double zobs, double hm, double tdk, double pmb,
+   }
+   \sstarguments{
+      \sstsubsection{
+         zobs = double (Given)
+      }{
+         Observed zenith distance of the source (radian)
+      }
+      \sstsubsection{
+         hm = double (Given)
+      }{
+         Height of the observer above sea level (metre)
+      }
+      \sstsubsection{
+         tdk = double (Given)
+      }{
+         Ambient temperature at the observer (K)
+      }
+      \sstsubsection{
+         pmb = double (Given)
+      }{
+         Pressure at the observer (millibar)
+      }
+      \sstsubsection{
+         rh = double (Given)
+      }{
+         Relative humidity at the observer (range 0-1)
+      }
+      \sstsubsection{
+         wl = double (Given)
+      }{
+         Effective wavelength of the source (micrometre)
+      }
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         Latitude of the observer (radian, astronomical)
+      }
+      \sstsubsection{
+         tlr = double (Given)
+      }{
+         Temperature lapse rate in the troposphere (K/metre)
+      }
+      \sstsubsection{
+         eps = double (Given)
+      }{
+         Precision required to terminate iteration (radian)
+      }
+      \sstsubsection{
+         ref = double $*$ (Returned)
+      }{
+         Refraction: in vacuao ZD minus observed ZD (radian)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         A suggested value for the TLR argument is 0.0065.  The
+         refraction is significantly affected by TLR, and if studies
+         of the local atmosphere have been carried out a better TLR
+         value may be available.  The sign of the supplied TLR value
+         is ignored.
+
+         \sstitem
+         A suggested value for the EPS argument is 1E-8.  The result is
+         usually at least two orders of magnitude more computationally
+         precise than the supplied EPS value.
+
+         \sstitem
+         The routine computes the refraction for zenith distances up
+         to and a little beyond 90 deg using the method of Hohenkerk
+         and Sinclair (NAO Technical Notes 59 and 63, subsequently adopted
+         in the Explanatory Supplement, 1992 edition - see section 3.281).
+
+         \sstitem
+         The code is a development of the optical/IR refraction subroutine
+         AREF of C.Hohenkerk (HMNAO, September 1984), with extensions to
+         support the radio case.  Apart from merely cosmetic changes, the
+         following modifications to the original HMNAO optical/IR refraction
+         code have been made:
+
+      }
+      .  The angle arguments have been changed to radians.
+
+      .  Any value of ZOBS is allowed (see note 6, below).
+
+      .  Other argument values have been limited to safe values.
+
+      .  Murray{\tt '}s values for the gas constants have been used
+         (Vectorial Astrometry, Adam Hilger, 1983).
+
+      .  The numerical integration phase has been rearranged for
+         extra clarity.
+
+      .  A better model for Ps(T) has been adopted (taken from
+         Gill, Atmosphere-Ocean Dynamics, Academic Press, 1982).
+
+      .  More accurate expressions for Pwo have been adopted
+         (again from Gill 1982).
+
+      .  The formula for the water vapour pressure, given the
+         saturation pressure and the relative humidity, is from
+         Crane (1976), expression 2.5.5.
+
+      .  Provision for radio wavelengths has been added using
+         expressions devised by A.T.Sinclair, RGO (private
+         communication 1989).  The refractivity model currently
+         used is from J.M.Rueger, {\tt "}Refractive Index Formulae for
+         Electronic Distance Measurement with Radio and Millimetre
+         Waves{\tt "}, in Unisurv Report S-68 (2002), School of Surveying
+         and Spatial Information Systems, University of New South
+         Wales, Sydney, Australia.
+
+      .  The optical refractivity for dry air is from Resolution 3 of
+         the International Association of Geodesy adopted at the XXIIth
+         General Assembly in Birmingham, UK, 1999.
+
+      .  Various small changes have been made to gain speed.
+
+      \sstitemlist{
+
+         \sstitem
+         The radio refraction is chosen by specifying WL $>$ 100 micrometres.
+         Because the algorithm takes no account of the ionosphere, the
+         accuracy deteriorates at low frequencies, below about 30 MHz.
+
+         \sstitem
+         Before use, the value of ZOBS is expressed in the range $+$/- pi.
+         If this ranged ZOBS is -ve, the result REF is computed from its
+         absolute value before being made -ve to match.  In addition, if
+         it has an absolute value greater than 93 deg, a fixed REF value
+         equal to the result for ZOBS = 93 deg is returned, appropriately
+         signed.
+
+         \sstitem
+         As in the original Hohenkerk and Sinclair algorithm, fixed values
+         of the water vapour polytrope exponent, the height of the
+         tropopause, and the height at which refraction is negligible are
+         used.
+
+         \sstitem
+         The radio refraction has been tested against work done by
+         Iain Coulson, JACH, (private communication 1995) for the
+         James Clerk Maxwell Telescope, Mauna Kea.  For typical conditions,
+         agreement at the 0.1 arcsec level is achieved for moderate ZD,
+         worsening to perhaps 0.5-1.0 arcsec at ZD 80 deg.  At hot and
+         humid sea-level sites the accuracy will not be as good.
+
+         \sstitem
+         It should be noted that the relative humidity RH is formally
+         defined in terms of {\tt "}mixing ratio{\tt "} rather than pressures or
+         densities as is often stated.  It is the mass of water per unit
+         mass of dry air divided by that for saturated air at the same
+         temperature and pressure (see Gill 1982).
+
+         \sstitem
+         The algorithm is designed for observers in the troposphere. The
+         supplied temperature, pressure and lapse rate are assumed to be
+         for a point in the troposphere and are used to define a model
+         atmosphere with the tropopause at 11km altitude and a constant
+         temperature above that.  However, in practice, the refraction
+         values returned for stratospheric observers, at altitudes up to
+         25km, are quite usable.
+      }
+   }
+}
+\sstroutine{
+   palRefv
+}{
+   Adjust an unrefracted Cartesian vector to include the effect of atmospheric refraction
+}{
+   \sstdescription{
+      Adjust an unrefracted Cartesian vector to include the effect of
+      atmospheric refraction, using the simple A tan Z $+$ B tan$*$$*$3 Z
+      model.
+   }
+   \sstinvocation{
+      void palRefv ( double vu[3], double refa, double refb, double vr[3] );
+   }
+   \sstarguments{
+      \sstsubsection{
+         vu[3] = double (Given)
+      }{
+         Unrefracted position of the source (Az/El 3-vector)
+      }
+      \sstsubsection{
+         refa = double (Given)
+      }{
+         tan Z coefficient (radian)
+      }
+      \sstsubsection{
+         refb = double (Given)
+      }{
+         tan$*$$*$3 Z coefficient (radian)
+      }
+      \sstsubsection{
+         vr[3] = double (Returned)
+      }{
+         Refracted position of the source (Az/El 3-vector)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         This routine applies the adjustment for refraction in the
+         opposite sense to the usual one - it takes an unrefracted
+         (in vacuo) position and produces an observed (refracted)
+         position, whereas the A tan Z $+$ B tan$*$$*$3 Z model strictly
+         applies to the case where an observed position is to have the
+         refraction removed.  The unrefracted to refracted case is
+         harder, and requires an inverted form of the text-book
+         refraction models;  the algorithm used here is equivalent to
+         one iteration of the Newton-Raphson method applied to the above
+         formula.
+
+         \sstitem
+         Though optimized for speed rather than precision, the present
+         routine achieves consistency with the refracted-to-unrefracted
+         A tan Z $+$ B tan$*$$*$3 Z model at better than 1 microarcsecond within
+         30 degrees of the zenith and remains within 1 milliarcsecond to
+         beyond ZD 70 degrees.  The inherent accuracy of the model is, of
+         course, far worse than this - see the documentation for sla\_REFCO
+         for more information.
+
+         \sstitem
+         At low elevations (below about 3 degrees) the refraction
+         correction is held back to prevent arithmetic problems and
+         wildly wrong results.  For optical/IR wavelengths, over a wide
+         range of observer heights and corresponding temperatures and
+         pressures, the following levels of accuracy (arcsec, worst case)
+         are achieved, relative to numerical integration through a model
+         atmosphere:
+
+      }
+               ZD    error
+
+               80      0.7
+               81      1.3
+               82      2.5
+               83      5
+               84     10
+               85     20
+               86     55
+               87    160
+               88    360
+               89    640
+               90   1100
+               91   1700         \} relevant only to
+               92   2600         \} high-elevation sites
+
+      The results for radio are slightly worse over most of the range,
+      becoming significantly worse below ZD=88 and unusable beyond
+      ZD=90.
+
+      \sstitemlist{
+
+         \sstitem
+         See also the routine palRefz, which performs the adjustment to
+         the zenith distance rather than in Cartesian Az/El coordinates.
+         The present routine is faster than palRefz and, except very low down,
+         is equally accurate for all practical purposes.  However, beyond
+         about ZD 84 degrees palRefz should be used, and for the utmost
+         accuracy iterative use of palRefro should be considered.
+      }
+   }
+}
+\sstroutine{
+   palRefz
+}{
+   Adjust unrefracted zenith distance
+}{
+   \sstdescription{
+      Adjust an unrefracted zenith distance to include the effect of
+      atmospheric refraction, using the simple A tan Z $+$ B tan$*$$*$3 Z
+      model (plus special handling for large ZDs).
+   }
+   \sstinvocation{
+      void palRefz ( double zu, double refa, double refb, double $*$zr );
+   }
+   \sstarguments{
+      \sstsubsection{
+         zu = double (Given)
+      }{
+         Unrefracted zenith distance of the source (radians)
+      }
+      \sstsubsection{
+         refa = double (Given)
+      }{
+         tan Z coefficient (radians)
+      }
+      \sstsubsection{
+         refb = double (Given)
+      }{
+         tan$*$$*$3 Z coefficient (radian)
+      }
+      \sstsubsection{
+         zr = double $*$ (Returned)
+      }{
+         Refracted zenith distance (radians)
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         This routine applies the adjustment for refraction in the
+         opposite sense to the usual one - it takes an unrefracted
+         (in vacuo) position and produces an observed (refracted)
+         position, whereas the A tan Z $+$ B tan$*$$*$3 Z model strictly
+         applies to the case where an observed position is to have the
+         refraction removed.  The unrefracted to refracted case is
+         harder, and requires an inverted form of the text-book
+         refraction models;  the formula used here is based on the
+         Newton-Raphson method.  For the utmost numerical consistency
+         with the refracted to unrefracted model, two iterations are
+         carried out, achieving agreement at the 1D-11 arcseconds level
+         for a ZD of 80 degrees.  The inherent accuracy of the model
+         is, of course, far worse than this - see the documentation for
+         palRefco for more information.
+
+         \sstitem
+         At ZD 83 degrees, the rapidly-worsening A tan Z $+$ B tan$\wedge$3 Z
+         model is abandoned and an empirical formula takes over.  For
+         optical/IR wavelengths, over a wide range of observer heights and
+         corresponding temperatures and pressures, the following levels of
+         accuracy (arcsec, worst case) are achieved, relative to numerical
+         integration through a model atmosphere:
+
+      }
+               ZR    error
+
+               80      0.7
+               81      1.3
+               82      2.4
+               83      4.7
+               84      6.2
+               85      6.4
+               86      8
+               87     10
+               88     15
+               89     30
+               90     60
+               91    150         \} relevant only to
+               92    400         \} high-elevation sites
+
+      For radio wavelengths the errors are typically 50\% larger than
+      the optical figures and by ZD 85 deg are twice as bad, worsening
+      rapidly below that.  To maintain 1 arcsec accuracy down to ZD=85
+      at the Green Bank site, Condon (2004) has suggested amplifying
+      the amount of refraction predicted by palRefz below 10.8 deg
+      elevation by the factor (1$+$0.00195$*$(10.8-E\_t)), where E\_t is the
+      unrefracted elevation in degrees.
+
+      The high-ZD model is scaled to match the normal model at the
+      transition point;  there is no glitch.
+
+      \sstitemlist{
+
+         \sstitem
+         Beyond 93 deg zenith distance, the refraction is held at its
+         93 deg value.
+
+         \sstitem
+         See also the routine palRefv, which performs the adjustment in
+         Cartesian Az/El coordinates, and with the emphasis on speed
+         rather than numerical accuracy.
+      }
+   }
+   \sstdiytopic{
+      References
+   }{
+      Condon,J.J., Refraction Corrections for the GBT, PTCS/PN/35.2,
+      NRAO Green Bank, 2004.
+   }
+}
+\sstroutine{
+   palRverot
+}{
+   Velocity component in a given direction due to Earth rotation
+}{
+   \sstdescription{
+      Calculate the velocity component in a given direction due to Earth
+      rotation.
+
+      The simple algorithm used assumes a spherical Earth, of
+      a radius chosen to give results accurate to about 0.0005 km/s
+      for observing stations at typical latitudes and heights.  For
+      applications requiring greater precision, use the routine
+      palPvobs.
+   }
+   \sstinvocation{
+      double palRverot ( double phi, double ra, double da, double st );
+   }
+   \sstarguments{
+      \sstsubsection{
+         phi = double (Given)
+      }{
+         latitude of observing station (geodetic) (radians)
+      }
+      \sstsubsection{
+         ra = double (Given)
+      }{
+         apparent RA (radians)
+      }
+      \sstsubsection{
+         da = double (Given)
+      }{
+         apparent Dec (radians)
+      }
+      \sstsubsection{
+         st = double (Given)
+      }{
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         palRverot = double
+      }{
+         Component of Earth rotation in direction RA,DA (km/s).
+         The result is $+$ve when the observatory is receding from the
+         given point on the sky.
+      }
+   }
+}
+\sstroutine{
+   palRvgalc
+}{
+   Velocity component in a given direction due to the rotation
+   of the Galaxy
+}{
+   \sstdescription{
+      This function returns the Component of dynamical LSR motion in
+      the direction of R2000,D2000. The result is $+$ve when the dynamical
+      LSR is receding from the given point on the sky.
+   }
+   \sstinvocation{
+      double palRvgalc( double r2000, double d2000 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 mean Dec (radians)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Component of dynamical LSR motion in direction R2000,D2000 (km/s).
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The Local Standard of Rest used here is a point in the
+         vicinity of the Sun which is in a circular orbit around
+         the Galactic centre.  Sometimes called the {\tt "}dynamical{\tt "} LSR,
+         it is not to be confused with a {\tt "}kinematical{\tt "} LSR, which
+         is the mean standard of rest of star catalogues or stellar
+         populations.
+      }
+   }
+   \sstdiytopic{
+      Reference
+   }{
+      \sstitemlist{
+
+         \sstitem
+         The orbital speed of 220 km/s used here comes from Kerr \&
+         Lynden-Bell (1986), MNRAS, 221, p1023.
+      }
+   }
+}
+\sstroutine{
+   palRvlg
+}{
+   Velocity component in a given direction due to Galactic rotation
+   and motion of the local group
+}{
+   \sstdescription{
+      This function returns the velocity component in a given
+      direction due to the combination of the rotation of the
+      Galaxy and the motion of the Galaxy relative to the mean
+      motion of the local group. The result is $+$ve when the Sun
+      is receding from the given point on the sky.
+   }
+   \sstinvocation{
+      double palRvlg( double r2000, double d2000 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 mean Dec (radians)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Component of SOLAR motion in direction R2000,D2000 (km/s).
+      }{
+      }
+   }
+   \sstdiytopic{
+      Reference
+   }{
+      \sstitemlist{
+
+         \sstitem
+         IAU Trans 1976, 168, p201.
+      }
+   }
+}
+\sstroutine{
+   palRvlsrd
+}{
+   Velocity component in a given direction due to the Sun{\tt '}s motion
+   with respect to the dynamical Local Standard of Rest
+}{
+   \sstdescription{
+      This function returns the velocity component in a given direction
+      due to the Sun{\tt '}s motion with respect to the dynamical Local Standard
+      of Rest. The result is $+$ve when the Sun is receding from the given
+      point on the sky.
+   }
+   \sstinvocation{
+      double palRvlsrd( double r2000, double d2000 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 mean Dec (radians)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Component of {\tt "}peculiar{\tt "} solar motion in direction R2000,D2000 (km/s).
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The Local Standard of Rest used here is the {\tt "}dynamical{\tt "} LSR,
+         a point in the vicinity of the Sun which is in a circular orbit
+         around the Galactic centre.  The Sun{\tt '}s motion with respect to the
+         dynamical LSR is called the {\tt "}peculiar{\tt "} solar motion.
+
+         \sstitem
+         There is another type of LSR, called a {\tt "}kinematical{\tt "} LSR.  A
+         kinematical LSR is the mean standard of rest of specified star
+         catalogues or stellar populations, and several slightly different
+         kinematical LSRs are in use.  The Sun{\tt '}s motion with respect to an
+         agreed kinematical LSR is known as the {\tt "}standard{\tt "} solar motion.
+         To obtain a radial velocity correction with respect to an adopted
+         kinematical LSR use the routine sla\_RVLSRK.
+      }
+   }
+   \sstdiytopic{
+      Reference
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Delhaye (1965), in {\tt "}Stars and Stellar Systems{\tt "}, vol 5, p73.
+      }
+   }
+}
+\sstroutine{
+   palRvlsrk
+}{
+   Velocity component in a given direction due to the Sun{\tt '}s motion
+   with respect to an adopted kinematic Local Standard of Rest
+}{
+   \sstdescription{
+      This function returns the velocity component in a given direction
+      due to the Sun{\tt '}s motion with respect to an adopted kinematic
+      Local Standard of Rest. The result is $+$ve when the Sun is receding
+      from the given point on the sky.
+   }
+   \sstinvocation{
+      double palRvlsrk( double r2000, double d2000 )
+   }
+   \sstarguments{
+      \sstsubsection{
+         r2000 = double (Given)
+      }{
+         J2000.0 mean RA (radians)
+      }
+      \sstsubsection{
+         d2000 = double (Given)
+      }{
+         J2000.0 mean Dec (radians)
+      }
+   }
+   \sstreturnedvalue{
+      \sstsubsection{
+         Component of {\tt "}standard{\tt "} solar motion in direction R2000,D2000 (km/s).
+      }{
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The Local Standard of Rest used here is one of several
+         {\tt "}kinematical{\tt "} LSRs in common use.  A kinematical LSR is the mean
+         standard of rest of specified star catalogues or stellar
+         populations.  The Sun{\tt '}s motion with respect to a kinematical LSR
+         is known as the {\tt "}standard{\tt "} solar motion.
+
+         \sstitem
+         There is another sort of LSR, the {\tt "}dynamical{\tt "} LSR, which is a
+         point in the vicinity of the Sun which is in a circular orbit
+         around the Galactic centre.  The Sun{\tt '}s motion with respect to
+         the dynamical LSR is called the {\tt "}peculiar{\tt "} solar motion.  To
+         obtain a radial velocity correction with respect to the
+         dynamical LSR use the routine sla\_RVLSRD.
+      }
+   }
+   \sstdiytopic{
+      Reference
+   }{
+      \sstitemlist{
+
+         \sstitem
+         Delhaye (1965), in {\tt "}Stars and Stellar Systems{\tt "}, vol 5, p73.
+      }
+   }
+}
+\sstroutine{
+   palSubet
+}{
+   Remove the E-terms from a pre IAU 1976 catalogue RA,Dec
+}{
+   \sstdescription{
+      Remove the E-terms (elliptic component of annual aberration)
+      from a pre IAU 1976 catalogue RA,Dec to give a mean place.
+   }
+   \sstinvocation{
+      void palSubet ( double rc, double dc, double eq,
+                      double $*$rm, double $*$dm );
+   }
+   \sstarguments{
+      \sstsubsection{
+         rc = double (Given)
+      }{
+         RA with E-terms included (radians)
+      }
+      \sstsubsection{
+         dc = double (Given)
+      }{
+         Dec with E-terms included (radians)
+      }
+      \sstsubsection{
+         eq = double (Given)
+      }{
+         Besselian epoch of mean equator and equinox
+      }
+      \sstsubsection{
+         rm = double $*$ (Returned)
+      }{
+         RA without E-terms (radians)
+      }
+      \sstsubsection{
+         dm = double $*$ (Returned)
+      }{
+         Dec without E-terms (radians)
+      }
+   }
+   \sstnotes{
+      Most star positions from pre-1984 optical catalogues (or
+      derived from astrometry using such stars) embody the
+      E-terms.  This routine converts such a position to a
+      formal mean place (allowing, for example, comparison with a
+      pulsar timing position).
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      Explanatory Supplement to the Astronomical Ephemeris,
+      section 2D, page 48.
+   }
+}
+\sstroutine{
+   palSupgal
+}{
+   Convert from supergalactic to galactic coordinates
+}{
+   \sstdescription{
+      Transformation from de Vaucouleurs supergalactic coordinates
+      to IAU 1958 galactic coordinates
+   }
+   \sstinvocation{
+      void palSupgal ( double dsl, double dsb, double $*$dl, double $*$db );
+   }
+   \sstarguments{
+      \sstsubsection{
+         dsl = double (Given)
+      }{
+         Supergalactic longitude.
+      }
+      \sstsubsection{
+         dsb = double (Given)
+      }{
+         Supergalactic latitude.
+      }
+      \sstsubsection{
+         dl = double $*$ (Returned)
+      }{
+         Galactic longitude.
+      }
+      \sstsubsection{
+         db = double $*$ (Returned)
+      }{
+         Galactic latitude.
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      \sstitemlist{
+
+         \sstitem
+          de Vaucouleurs, de Vaucouleurs, \& Corwin, Second Reference
+            Catalogue of Bright Galaxies, U. Texas, page 8.
+
+         \sstitem
+          Systems \& Applied Sciences Corp., Documentation for the
+            machine-readable version of the above catalogue,
+            Contract NAS 5-26490.
+
+      }
+      (These two references give different values for the galactic
+       longitude of the supergalactic origin.  Both are wrong;  the
+       correct value is L2=137.37.)
+   }
+}
+\sstroutine{
+   palUe2el
+}{
+   Universal elements to heliocentric osculating elements
+}{
+   \sstdescription{
+      Transform universal elements into conventional heliocentric
+      osculating elements.
+   }
+   \sstinvocation{
+      void palUe2el ( const double u[13], int jformr,
+                      int $*$jform, double $*$epoch, double $*$orbinc,
+                      double $*$anode, double $*$perih, double $*$aorq, double $*$e,
+                      double $*$aorl, double $*$dm, int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         u = const double [13] (Given)
+      }{
+         Universal orbital elements (Note 1)
+             (0)  combined mass (M$+$m)
+             (1)  total energy of the orbit (alpha)
+             (2)  reference (osculating) epoch (t0)
+           (3-5)  position at reference epoch (r0)
+           (6-8)  velocity at reference epoch (v0)
+             (9)  heliocentric distance at reference epoch
+            (10)  r0.v0
+            (11)  date (t)
+            (12)  universal eccentric anomaly (psi) of date, approx
+      }
+      \sstsubsection{
+         jformr = int (Given)
+      }{
+         Requested element set (1-3; Note 3)
+      }
+      \sstsubsection{
+         jform = int $*$ (Returned)
+      }{
+         Element set actually returned (1-3; Note 4)
+      }
+      \sstsubsection{
+         epoch = double $*$ (Returned)
+      }{
+         Epoch of elements (TT MJD)
+      }
+      \sstsubsection{
+         orbinc = double $*$ (Returned)
+      }{
+         inclination (radians)
+      }
+      \sstsubsection{
+         anode = double $*$ (Returned)
+      }{
+         longitude of the ascending node (radians)
+      }
+      \sstsubsection{
+         perih = double $*$ (Returned)
+      }{
+         longitude or argument of perihelion (radians)
+      }
+      \sstsubsection{
+         aorq = double $*$ (Returned)
+      }{
+         mean distance or perihelion distance (AU)
+      }
+      \sstsubsection{
+         e = double $*$ (Returned)
+      }{
+         eccentricity
+      }
+      \sstsubsection{
+         aorl = double $*$ (Returned)
+      }{
+         mean anomaly or longitude (radians, JFORM=1,2 only)
+      }
+      \sstsubsection{
+         dm = double $*$ (Returned)
+      }{
+         daily motion (radians, JFORM=1 only)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:  0 = OK
+         \sstitemlist{
+
+            \sstitem
+                    1 = illegal combined mass
+
+            \sstitem
+                    2 = illegal JFORMR
+
+            \sstitem
+                    3 = position/velocity out of range
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+           The {\tt "}universal{\tt "} elements are those which define the orbit for the
+             purposes of the method of universal variables (see reference 2).
+             They consist of the combined mass of the two bodies, an epoch,
+             and the position and velocity vectors (arbitrary reference frame)
+             at that epoch.  The parameter set used here includes also various
+             quantities that can, in fact, be derived from the other
+             information.  This approach is taken to avoiding unnecessary
+             computation and loss of accuracy.  The supplementary quantities
+             are (i) alpha, which is proportional to the total energy of the
+             orbit, (ii) the heliocentric distance at epoch, (iii) the
+             outwards component of the velocity at the given epoch, (iv) an
+             estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+             date and (v) that date.
+
+         \sstitem
+           The universal elements are with respect to the mean equator and
+             equinox of epoch J2000.  The orbital elements produced are with
+             respect to the J2000 ecliptic and mean equinox.
+
+         \sstitem
+           Three different element-format options are supported:
+
+      }
+           Option JFORM=1, suitable for the major planets:
+
+           EPOCH  = epoch of elements (TT MJD)
+           ORBINC = inclination i (radians)
+           ANODE  = longitude of the ascending node, big omega (radians)
+           PERIH  = longitude of perihelion, curly pi (radians)
+           AORQ   = mean distance, a (AU)
+           E      = eccentricity, e
+           AORL   = mean longitude L (radians)
+           DM     = daily motion (radians)
+
+           Option JFORM=2, suitable for minor planets:
+
+           EPOCH  = epoch of elements (TT MJD)
+           ORBINC = inclination i (radians)
+           ANODE  = longitude of the ascending node, big omega (radians)
+           PERIH  = argument of perihelion, little omega (radians)
+           AORQ   = mean distance, a (AU)
+           E      = eccentricity, e
+           AORL   = mean anomaly M (radians)
+
+           Option JFORM=3, suitable for comets:
+
+           EPOCH  = epoch of perihelion (TT MJD)
+           ORBINC = inclination i (radians)
+           ANODE  = longitude of the ascending node, big omega (radians)
+           PERIH  = argument of perihelion, little omega (radians)
+           AORQ   = perihelion distance, q (AU)
+           E      = eccentricity, e
+
+      \sstitemlist{
+
+         \sstitem
+           It may not be possible to generate elements in the form
+             requested through JFORMR.  The caller is notified of the form
+             of elements actually returned by means of the JFORM argument:
+
+      }
+           JFORMR   JFORM     meaning
+
+             1        1       OK - elements are in the requested format
+             1        2       never happens
+             1        3       orbit not elliptical
+
+             2        1       never happens
+             2        2       OK - elements are in the requested format
+             2        3       orbit not elliptical
+
+             3        1       never happens
+             3        2       never happens
+             3        3       OK - elements are in the requested format
+
+      \sstitemlist{
+
+         \sstitem
+           The arguments returned for each value of JFORM (cf Note 6: JFORM
+             may not be the same as JFORMR) are as follows:
+
+      }
+            JFORM         1              2              3
+            EPOCH         t0             t0             T
+            ORBINC        i              i              i
+            ANODE         Omega          Omega          Omega
+            PERIH         curly pi       omega          omega
+            AORQ          a              a              q
+            E             e              e              e
+            AORL          L              M              -
+            DM            n              -              -
+
+        where:
+
+            t0           is the epoch of the elements (MJD, TT)
+            T              {\tt "}    epoch of perihelion (MJD, TT)
+            i              {\tt "}    inclination (radians)
+            Omega          {\tt "}    longitude of the ascending node (radians)
+            curly pi       {\tt "}    longitude of perihelion (radians)
+            omega          {\tt "}    argument of perihelion (radians)
+            a              {\tt "}    mean distance (AU)
+            q              {\tt "}    perihelion distance (AU)
+            e              {\tt "}    eccentricity
+            L              {\tt "}    longitude (radians, 0-2pi)
+            M              {\tt "}    mean anomaly (radians, 0-2pi)
+            n              {\tt "}    daily motion (radians)
+      \sstitemlist{
+
+         \sstitem
+               means no value is set
+
+         \sstitem
+           At very small inclinations, the longitude of the ascending node
+             ANODE becomes indeterminate and under some circumstances may be
+             set arbitrarily to zero.  Similarly, if the orbit is close to
+             circular, the true anomaly becomes indeterminate and under some
+             circumstances may be set arbitrarily to zero.  In such cases,
+             the other elements are automatically adjusted to compensate,
+             and so the elements remain a valid description of the orbit.
+
+      }
+      See Also:
+      \sstitemlist{
+
+         \sstitem
+           Sterne, Theodore E., {\tt "}An Introduction to Celestial Mechanics{\tt "},
+             Interscience Publishers Inc., 1960.  Section 6.7, p199.
+
+         \sstitem
+           Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+      }
+   }
+}
+\sstroutine{
+   palUe2pv
+}{
+   Heliocentric position and velocity of a planet, asteroid or comet, from universal elements
+}{
+   \sstdescription{
+      Heliocentric position and velocity of a planet, asteroid or comet,
+      starting from orbital elements in the {\tt "}universal variables{\tt "} form.
+   }
+   \sstinvocation{
+      void palUe2pv( double date, double u[13], double pv[6], int $*$jstat );
+   }
+   \sstarguments{
+      \sstsubsection{
+         date = double (Given)
+      }{
+         TT Modified Julian date (JD-2400000.5).
+      }
+      \sstsubsection{
+         u = double [13] (Given \& Returned)
+      }{
+          Universal orbital elements (updated, see note 1)
+          given    (0)   combined mass (M$+$m)
+            {\tt "}      (1)   total energy of the orbit (alpha)
+            {\tt "}      (2)   reference (osculating) epoch (t0)
+            {\tt "}    (3-5)   position at reference epoch (r0)
+            {\tt "}    (6-8)   velocity at reference epoch (v0)
+            {\tt "}      (9)   heliocentric distance at reference epoch
+            {\tt "}     (10)   r0.v0
+         returned (11)   date (t)
+            {\tt "}     (12)   universal eccentric anomaly (psi) of date
+      }
+      \sstsubsection{
+         pv = double [6] (Returned)
+      }{
+         Position (AU) and velocity (AU/s)
+      }
+      \sstsubsection{
+         jstat = int $*$ (Returned)
+      }{
+         status:  0 = OK
+         \sstitemlist{
+
+            \sstitem
+                    1 = radius vector zero
+
+            \sstitem
+                    2 = failed to converge
+         }
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The {\tt "}universal{\tt "} elements are those which define the orbit for the
+           purposes of the method of universal variables (see reference).
+           They consist of the combined mass of the two bodies, an epoch,
+           and the position and velocity vectors (arbitrary reference frame)
+           at that epoch.  The parameter set used here includes also various
+           quantities that can, in fact, be derived from the other
+           information.  This approach is taken to avoiding unnecessary
+           computation and loss of accuracy.  The supplementary quantities
+           are (i) alpha, which is proportional to the total energy of the
+           orbit, (ii) the heliocentric distance at epoch, (iii) the
+           outwards component of the velocity at the given epoch, (iv) an
+           estimate of psi, the {\tt "}universal eccentric anomaly{\tt "} at a given
+           date and (v) that date.
+
+         \sstitem
+         The companion routine is palEl2ue.  This takes the conventional
+           orbital elements and transforms them into the set of numbers
+           needed by the present routine.  A single prediction requires one
+           one call to palEl2ue followed by one call to the present routine;
+           for convenience, the two calls are packaged as the routine
+           sla\_PLANEL.  Multiple predictions may be made by again
+           calling palEl2ue once, but then calling the present routine
+           multiple times, which is faster than multiple calls to palPlanel.
+
+         \sstitem
+         It is not obligatory to use palEl2ue to obtain the parameters.
+           However, it should be noted that because palEl2ue performs its
+           own validation, no checks on the contents of the array U are made
+           by the present routine.
+           in the TT timescale (formerly Ephemeris Time, ET) and is a
+           Modified Julian Date (JD-2400000.5).
+           units (solar masses, AU and canonical days).  The position and
+           velocity are not sensitive to the choice of reference frame.  The
+           palEl2ue routine in fact produces coordinates with respect to the
+           J2000 equator and equinox.
+
+         \sstitem
+         The algorithm was originally adapted from the EPHSLA program of
+           D.H.P.Jones (private communication, 1996).  The method is based
+           on Stumpff{\tt '}s Universal Variables.
+
+         \sstitem
+         Reference:  Everhart, E. \& Pitkin, E.T., Am.J.Phys. 51, 712, 1983.
+      }
+   }
+}
+\sstroutine{
+   palUnpcd
+}{
+   Remove pincushion/barrel distortion
+}{
+   \sstdescription{
+      Remove pincushion/barrel distortion from a distorted [x,y] to give
+      tangent-plane [x,y].
+   }
+   \sstinvocation{
+      palUnpcd( double disco, double $*$ x, double $*$ y );
+   }
+   \sstarguments{
+      \sstsubsection{
+         disco = double (Given)
+      }{
+         Pincushion/barrel distortion coefficient.
+      }
+      \sstsubsection{
+         x = double $*$ (Given \& Returned)
+      }{
+         On input the distorted X coordinate, on output
+         the tangent-plane X coordinate.
+      }
+      \sstsubsection{
+         y = double $*$ (Given \& Returned)
+      }{
+         On input the distorted Y coordinate, on output
+         the tangent-plane Y coordinate.
+      }
+   }
+   \sstnotes{
+      \sstitemlist{
+
+         \sstitem
+         The distortion is of the form RP = R$*$(1$+$C$*$R$\wedge$2), where R is
+           the radial distance from the tangent point, C is the DISCO
+           argument, and RP is the radial distance in the presence of
+           the distortion.
+
+         \sstitem
+         For pincushion distortion, C is $+$ve;  for barrel distortion,
+           C is -ve.
+
+         \sstitem
+         For X,Y in \texttt{"} radians\texttt{"}  - units of one projection radius,
+           which in the case of a photograph is the focal length of
+           the camera - the following DISCO values apply:
+
+\begin{center}
+\begin{tabular}{ll}
+            Geometry          &DISCO \\
+\hline
+            astrograph        & 0.0 \\
+            Schmidt           &-0.3333 \\
+            AAT PF doublet  &$+$147.069 \\
+            AAT PF triplet  &$+$178.585 \\
+            AAT f/8          &$+$21.20 \\
+            JKT f/8          &$+$13.32 \\
+\end{tabular}
+\end{center}
+
+      }
+      \sstitemlist{
+
+         \sstitem
+         The present routine is a rigorous inverse of the companion
+           routine palPcd.  The expression for RP in Note 1 is rewritten
+           in the form x$\wedge$3$+$a$*$x$+$b=0 and solved by standard techniques.
+
+         \sstitem
+         Cases where the cubic has multiple real roots can sometimes
+           occur, corresponding to extreme instances of barrel distortion
+           where up to three different undistorted [X,Y]s all produce the
+           same distorted [X,Y].  However, only one solution is returned,
+           the one that produces the smallest change in [X,Y].
+      }
+   }
+   \sstdiytopic{
+      See Also
+   }{
+      palPcd
+   }
+}
+
+
+
+% ? End of main text
+\end{document}
