Index: trunk/mops/oorb/COPYING
===================================================================
--- trunk/mops/oorb/COPYING	(revision 34646)
+++ trunk/mops/oorb/COPYING	(revision 34646)
@@ -0,0 +1,675 @@
+
+                    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/mops/oorb/Makefile
===================================================================
--- trunk/mops/oorb/Makefile	(revision 34646)
+++ trunk/mops/oorb/Makefile	(revision 34646)
@@ -0,0 +1,52 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# This is a makefile for the classes, modules, executables,
+# and documentation in the OpenOrb-project.
+#
+# Author:  MG
+# Version: 2009-11-09
+
+include make.config
+
+# Write back-up:
+backup:
+	$(SHELL) -c "if test -d ../backup_$(PROJNAME); then true; else mkdir ../backup_$(PROJNAME); fi"
+	cp -a * ../backup_$(PROJNAME)
+
+# Make tar-ball:
+tar: all_clean
+	cd .. ; tar cvf $(PROJNAME)_v$(VERSION).tar $(PROJNAME) ; gzip $(PROJNAME)_v$(VERSION).tar
+
+all_clean: clean
+	cd $(DOCPATH)    ; $(MAKE) clean
+	cd $(CLASSPATH)  ; $(MAKE) clean
+	cd $(MODULEPATH) ; $(MAKE) clean
+	cd $(MAINPATH)   ; $(MAKE) clean
+	cd $(PYTHONPATH) ; $(MAKE) clean
+	cd $(LIBPATH)    ; $(MAKE) clean
+
+# Remove library and modules:
+clean:
+	rm -f *~ *.mod *.o
+
Index: trunk/mops/oorb/Makefile.include
===================================================================
--- trunk/mops/oorb/Makefile.include	(revision 34646)
+++ trunk/mops/oorb/Makefile.include	(revision 34646)
@@ -0,0 +1,3 @@
+FC = $(FC_GFORTRAN)
+FCOPTIONS = $(FCOPTIONS_DEB_GFORTRAN)
+FC_INC = $(FC_INC_GFORTRAN)
Index: trunk/mops/oorb/README
===================================================================
--- trunk/mops/oorb/README	(revision 34646)
+++ trunk/mops/oorb/README	(revision 34646)
@@ -0,0 +1,8 @@
+
+
+For documentation do
+
+ cd doc
+ make pdf
+
+which should produce PDF document 'OpenOrb_Tutorial_vN.N.pdf'.
Index: trunk/mops/oorb/classes/Base_class.f90
===================================================================
--- trunk/mops/oorb/classes/Base_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Base_class.f90	(revision 34646)
@@ -0,0 +1,1067 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!  
+!! This is actually not a class in a strict sense, but can anyway be
+!! thought of as a sort of a class that all other classes should
+!! inherit. It contains the most fundamental parameters, types and
+!! routines, that should be available for all classes.
+!!
+!! IAU units are used (if not otherwise stated):
+!! - mass = solar mass
+!! - distance = astronomical unit (AU)
+!! - time = day
+!! - angle = rad
+!!
+!! @author  MG, JV, TL
+!! @version 2011-08-08
+!!
+MODULE Base_cl
+
+  USE utilities
+  IMPLICIT NONE
+  PRIVATE :: calendarDateToJulianDate
+  PRIVATE :: julianDateToCalendarDate
+  PRIVATE :: coordinatedUniversalTime
+
+  INTEGER, PARAMETER :: stderr = 0 !! Standard error logical unit. 
+  !!                                  Shouldn't be connected to a file.
+  INTEGER, PARAMETER :: stdin  = 5 !! Standard input logical unit 
+  !!                                  (refers usually to the keyboard).
+  INTEGER, PARAMETER :: stdout = 6 !! Standard output logical unit 
+  !!                                  (refers usually to the screen).
+  INTEGER, PARAMETER :: debug  = 7 !! Debugging logical unit. 
+  INTEGER, PARAMETER :: cbp =  SELECTED_REAL_KIND(p=12) !! Base precision kind for type complex.
+  INTEGER, PARAMETER :: hp  =  SELECTED_REAL_KIND(p=18) !! High precision kind for type real.
+  INTEGER, PARAMETER :: bp  =  SELECTED_REAL_KIND(p=12) !! Base precision kind for type real.
+  INTEGER, PARAMETER :: lp  =  SELECTED_REAL_KIND(p=6)  !! Low precision kind for type real.
+  INTEGER, PARAMETER :: ihp =  SELECTED_INT_KIND(12)    !! High precision kind for type integer.
+  INTEGER, PARAMETER :: ibp =  SELECTED_INT_KIND(7)     !! Base precision kind for type integer.
+  REAL(bp) :: timezone = 10.0_bp  !! Difference between UT and local time [h]. Default: 10 (HST).
+  CHARACTER(len=3), DIMENSION(12), PARAMETER :: month_abbr = (/ &
+       "Jan", &
+       "Feb", &
+       "Mar", &
+       "Apr", &
+       "May", &
+       "Jun", &
+       "Jul", &
+       "Aug", &
+       "Sep", &
+       "Oct", &
+       "Nov", &
+       "Dec"   /)
+  ! Lengths of months in days:
+  INTEGER, DIMENSION(12), PARAMETER :: monthlen = (/ 31, 28, 31, &
+       30, 31, 30, 31, 31, 30, 31, 30, 31 /)
+  REAL(bp), PARAMETER :: pi       = 3.14159265358979324_bp  !! Pi.
+  REAL(bp), PARAMETER :: two_pi   = 2.0_bp*pi               !! 2*Pi.
+  REAL(bp), PARAMETER :: rad_hour = pi/12.0_bp              !! Radians per hour.
+  REAL(bp), PARAMETER :: rad_min  = rad_hour/60.0_bp        !! Radians per minute.
+  REAL(bp), PARAMETER :: rad_sec  = rad_min/60.0_bp         !! Radians per second.
+  REAL(bp), PARAMETER :: rad_deg  = pi/180.0_bp             !! Radians per degree.
+  REAL(bp), PARAMETER :: rad_amin = rad_deg/60.0_bp         !! Radians per arcminute.
+  REAL(bp), PARAMETER :: rad_asec = rad_amin/60.0_bp        !! Radians per arcsecond.
+  REAL(bp), PARAMETER :: km_au    = 1.4959787066e8_bp       !! Kilometres per astronomical unit.
+  REAL(bp), PARAMETER :: m_au     = 1.4959787066e11_bp      !! Metres per astronomical unit.
+  REAL(bp), PARAMETER :: day_year = 365.256363004_bp        !! Days per sidereal year (J2000.0).
+  REAL(bp), PARAMETER :: hour_day = 24.0_bp                 !! Hours per day.
+  REAL(bp), PARAMETER :: min_day  = hour_day*60.0_bp        !! Minutes per day.
+  REAL(bp), PARAMETER :: sec_day  = min_day*60.0_bp         !! Seconds per day.
+  REAL(bp), PARAMETER :: sec_year = sec_day*day_year        !! Seconds per year.
+  REAL(bp), PARAMETER :: kg_solar = 1.9892e30_bp            !! Kilograms per solar mass (IAU 1976).  
+  ! ggc and mu (= ggc**2) have been deprecated, use array 'planetary_mu' in modules/planetary_data.f90
+  REAL(bp), PARAMETER :: sol      = 173.14463272_bp         !! Speed of light (AU/d).
+  !REAL(bp), PARAMETER :: eps = 23.439280833_bp*rad_deg     !! Obliquity of ecliptic (J2000.0) 
+  !!                                                           Gaia 2006 (84381.41100asec).
+  !REAL(bp), PARAMETER :: eps      = 23.439291111_bp*rad_deg !! Obliquity of ecliptic (J2000.0) Danby 1992.
+  !REAL(bp), PARAMETER :: eps      = 23.439281111_bp*rad_deg !! Obliquity of ecliptic (J2000.0) JPL 2005.
+  REAL(bp), PARAMETER :: eps      = 23.43929111111_bp*rad_deg !! Obliquity of ecliptic (J2000.0), old code
+  REAL(bp), PARAMETER :: r_earth  = 6378.140_bp/km_au       !! Earth equatorial radius (not mean!).
+  REAL(bp), PARAMETER :: smamax   = 500.0_bp                !! Maximum for semimajor axis (AU).
+  REAL(bp), PARAMETER :: rmoon    = 2.57e-3_bp              !! Earth-Moon mean distance (AU).
+  REAL(bp), PARAMETER :: kgm3_smau3 = (km_au)**3/kg_solar   !! density conversion
+  INTEGER, PARAMETER :: FNAME_LEN = 512
+  INTEGER, PARAMETER :: DIR_LEN = 256
+  INTEGER, PARAMETER :: OBS_RECORD_LEN = 256
+  INTEGER, PARAMETER :: ELEMENT_TYPE_LEN = 16
+  INTEGER, PARAMETER :: FRAME_LEN = 16
+  INTEGER, PARAMETER :: DYN_MODEL_LEN = 16
+  INTEGER, PARAMETER :: INTEGRATOR_LEN = 32
+  INTEGER, PARAMETER :: DESIGNATION_LEN = 16
+  INTEGER, PARAMETER :: OBSY_CODE_LEN = 4
+  CHARACTER(len=FNAME_LEN) :: OORB_DATA_DIR
+
+  CHARACTER(len=FNAME_LEN), PARAMETER :: EPH_FNAME = "de405.dat"
+  ! OBS CODES
+  CHARACTER(len=FNAME_LEN), PARAMETER :: CODE_FNAME = "OBSCODE.dat"
+  ! Default name of the file containing the difference between ET and UT:
+  CHARACTER(len=FNAME_LEN), PARAMETER :: ETUT_FNAME   = "ET-UT.dat"
+  ! Default name of the file containing the difference between TAI and UTC:
+  CHARACTER(len=FNAME_LEN), PARAMETER :: TAIUTC_FNAME = "TAI-UTC.dat"
+  ! ET-TAI in seconds:
+  REAL(bp), PARAMETER :: ETMTAI = 32.184_bp
+
+  ! MPC conversion table
+  CHARACTER(len=1), DIMENSION(0:61), PARAMETER :: mpc_conv_table = &
+       (/ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", &
+       "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", &
+       "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", &
+       "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", &
+       "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", &
+       "x", "y", "z" /)
+
+  INTEGER :: err_verb = 1
+  INTEGER :: info_verb = 1
+  LOGICAL :: simulated_observations = .FALSE.
+  CHARACTER(len=1024) :: errstr = ""
+  LOGICAL :: error = .FALSE.
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Given cosinus and sinus of an angle, returns the angle in radians.
+  !!
+  REAL(bp) FUNCTION angle(cos_angle, sin_angle)
+
+    IMPLICIT NONE
+    REAL(bp) :: cos_angle, sin_angle
+
+    ! Safety check (problems with accuracy)
+    IF (ABS(cos_angle) > 1.0_bp) cos_angle = SIGN(1.0_bp,cos_angle)*1.0_bp
+    IF (ABS(sin_angle) > 1.0_bp) sin_angle = SIGN(1.0_bp,sin_angle)*1.0_bp
+
+    IF (SIGN(1.0_bp,cos_angle) == SIGN(1.0_bp,sin_angle)) THEN
+       IF (cos_angle >= 0.0_bp .OR. sin_angle == 0.0_bp) THEN
+          angle = ACOS(cos_angle)
+       ELSE
+          angle = two_pi - ACOS(cos_angle)
+       ENDIF
+    ELSE IF (SIGN(1.0_bp,cos_angle) /= SIGN(1.0_bp,sin_angle)) THEN
+       IF (SIGN(1.0_bp,cos_angle) < 0.0_bp) THEN
+          angle = ACOS(cos_angle)
+       ELSE
+          angle = two_pi-ACOS(cos_angle)
+       END IF
+    END IF
+
+  END FUNCTION angle
+
+
+
+
+
+  !! Description:
+  !!
+  !! This routine converts calendar date and time to the corresponding
+  !! Julian date. The algorithm from Van Flandern and Pulkkinen,
+  !! Ap.J. Suppl. vol 41, page 392.
+  !!
+  SUBROUTINE calendarDateToJulianDate(year, month, day, h, min, sec, jd)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in)   :: year, month, day, h, min
+    REAL(bp), INTENT(in)  :: sec
+    REAL(bp), INTENT(out) :: jd
+    INTEGER               :: iaux
+
+    iaux = -7*(year+(month+9)/12)/4 - &
+         3*((year+(month-9)/7)/100+1)/4 + 275*month/9
+    jd = iaux + day + 367.0_bp*year + 1721028.5_bp + &
+         (h + min/60.0_bp + sec/3600.0_bp)/24.0_bp
+
+  END SUBROUTINE calendarDateToJulianDate
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms degrees, arcminutes, and/or -seconds to radians.
+  !!
+  SUBROUTINE DAMAStoRadians(deg, arcmin, arcsec, rad)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in)   :: deg, arcmin
+    REAL(bp), INTENT(in)  :: arcsec
+    REAL(bp), INTENT(out) :: rad
+
+    rad = (deg + arcmin/60.0_bp + arcsec/3600.0_bp)*pi/180.0_bp
+
+  END SUBROUTINE DAMAStoRadians
+
+
+
+
+
+  !! Description:
+  !!
+  !! Converts fractional days to hours, minutes, and seconds. Note
+  !! that "d" must be positive!
+  !!
+  SUBROUTINE dayToHMS(d, h, m, s)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)  :: d
+    REAL(bp), INTENT(out) :: s
+    INTEGER, INTENT(out)  :: h, m
+    REAL(bp)              :: fh, fm
+
+    fh = 24.0_bp*d
+    fh = fh + EPSILON(fh)
+    h = INT(fh)
+    fm = 60.0_bp*(fh - REAL(h, bp))
+    fm = fm + EPSILON(fm)
+    m = INT(fm)
+    s = 60.0_bp*(fm - REAL(m, bp))
+
+  END SUBROUTINE dayToHMS
+
+
+
+
+
+  !! *Description*:
+  !! 
+  !! This routines reports errors in a standard fashion. The first
+  !! character string is the name of the routine from which this
+  !! routine is invoked. It is nice to know from where this message
+  !! originates. The other character string is the error
+  !! description. The error message is written to the standard error
+  !! logical unit, and can be presented to the end-user.
+  !!
+  !! The standard array of I/O errors can occur but they are ignored
+  !! because this is an error handling routine and it would be easy
+  !! to get into an error loop.
+  !!
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! use Base_cl !(contains global logical variable "error")
+  !! .
+  !! .
+  !! .
+  !! subroutine thisroutine(...)
+  !! .
+  !! .
+  !! .
+  !! if (error) then
+  !! call errorMessage("thisroutine","Experienced this error.",1)
+  !! return
+  !! end if
+  !! </pre>
+  !!
+  SUBROUTINE errorMessage(routine_name, msg_str, vrbs)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)    :: routine_name, msg_str
+    INTEGER, INTENT(in)             :: vrbs
+    CHARACTER(len=3), DIMENSION(12) :: month_abbrev
+    CHARACTER(len=256)              :: form
+    INTEGER, DIMENSION(3)           :: date, time
+    INTEGER                         :: err
+
+    IF (err_verb >= vrbs) THEN
+       month_abbrev = (/ "Jan", "Feb", "Mar", "Apr", "May", "Jun", &
+            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" /)
+       CALL coordinatedUniversalTime(date,time)
+       form = "('***ERROR*** ', i2, ' ', a3, ' ', i4, ' ', i2.2, " // &
+            "':', i2.2, ':', i2.2, 'UTC (', a, ') ', a)"
+       WRITE(stderr, TRIM(form), iostat=err) date(1), month_abbrev(date(2)), &
+            date(3), time(1), time(2), time(3), TRIM(routine_name), &
+            TRIM(msg_str)
+       IF (err /= 0) WRITE(stderr,*) "Could not write error message!" 
+    END IF
+
+  END SUBROUTINE errorMessage
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms hours, minutes, and/or seconds to radians.
+  !!
+  SUBROUTINE HMStoRadians(hour, min, sec, rad)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in)   :: hour, min
+    REAL(bp), INTENT(in)  :: sec
+    REAL(bp), INTENT(out) :: rad
+
+    rad = (hour + min/60.0_bp + sec/3600.0_bp)*two_pi/24.0_bp
+
+  END SUBROUTINE HMStoRadians
+
+
+
+
+
+  !! *Description*:
+  !! 
+  !! This routines prints information in a standard fashion. The first
+  !! character string is the name of the routine from which this
+  !! routine is invoked. It is nice to know from where this message
+  !! originates. The other character string is the message. The info
+  !! message is written to the standard error logical unit, and can be
+  !! presented to the end-user.
+  !!
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! use Base_cl
+  !! .
+  !! .
+  !! .
+  !! call infoMessage("thisroutine", "Experienced this thing.", stdout, 1)
+  !! return
+  !! end if
+  !! </pre>
+  !!
+  SUBROUTINE infoMessage(routine_name, msg_str, lu, vrbs)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)    :: routine_name, msg_str
+    INTEGER, INTENT(in)             :: lu, vrbs
+    CHARACTER(len=3), DIMENSION(12) :: month_abbrev
+    CHARACTER(len=256)              :: form
+    INTEGER, DIMENSION(3)           :: date, time
+    INTEGER                         :: err
+
+    IF (info_verb >= vrbs) THEN
+       month_abbrev = (/ "Jan", "Feb", "Mar", "Apr", "May", "Jun", &
+            "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" /)
+       CALL coordinatedUniversalTime(date,time)
+       form = "('***INFO*** ', i2, ' ', a3, ' ', i4, ' ', i2.2, " // &
+            "':', i2.2, ':', i2.2, 'UTC (', a, ') ', a)"
+       WRITE(lu,TRIM(form),iostat=err) date(1), month_abbrev(date(2)), &
+            date(3), time(1), time(2), time(3), TRIM(routine_name), &
+            TRIM(msg_str)
+       IF (err /= 0) WRITE(stderr,*) "Could not write message!" 
+    END IF
+
+  END SUBROUTINE infoMessage
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This routine converts the Julian date to calendar date and time.
+  !! The algorithm from Q.J.R. Astr. Soc. 1984, vol 25) page 53.
+  !!
+  !! Note:
+  !!
+  !! For 100 year dates which are not leap years
+  !! (ie 1900, 2100, etc) the conversion at mar 1 is wrong.
+  !!       eg    2415078.5  --->  1900,2,28  (correct)
+  !!             2415079.5  --->  1900,2,29  (should be 1900,3,1 !)
+  !!             2415080.5  --->  1900,3,2   (correct)
+  !!
+  SUBROUTINE julianDateToCalendarDate(jd, year, month, day, hour, min, sec)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)  :: jd
+    REAL(bp), INTENT(out) :: sec
+    INTEGER, INTENT(out)  :: year, month, day, hour, min
+    REAL(bp)              :: fjd, jul, fday
+    INTEGER               :: ijul, ig, idp
+
+    jul = jd
+    fjd = jul - INT(jul)
+    IF(fjd >= 0.5_bp) THEN
+       ijul = jul + 1.0_bp
+       fday = fjd - 0.5_bp
+    ELSE
+       ijul = jul
+       fday = fjd + 0.5_bp
+    ENDIF
+    ig = INT(INT((jul-4479.5_bp)/36524.25)*0.75_bp + 0.5_bp) - 37
+    jul = ijul + ig
+    year = INT(jul/365.25_bp) - 4712
+    idp = INT(MOD(jul-59.25_bp, 365.25_bp))
+    month = 1 + MOD(INT((idp+0.5_bp)/30.6_bp)+2,12)
+    day = INT(MOD(idp+0.5_bp, 30.6_bp)) + 1
+    CALL dayToHMS(fday,hour,min,sec)
+
+  END SUBROUTINE julianDateToCalendarDate
+
+
+
+
+
+  !! Mean obliquity of ecliptic (see Astronomical Almanac 1987, B18)
+  !!
+  !!  INPUT:    TJM   -   Modified Julian Time (TDT)
+  !!
+  !!  OUTPUT:   in radians
+  !!
+  REAL(bp) FUNCTION meanObliquity(tjm)
+
+    IMPLICIT NONE
+
+    !  type(Time), intent(in) :: t
+    REAL(bp), INTENT(in) :: tjm
+    REAL(bp)             :: t0
+    REAL(bp), PARAMETER  :: ob0 = &
+         (23.0_bp*3600.0_bp+26.0_bp*60.0_bp+21.45_bp)*rad_asec, & ! IAU value
+                                !(float(23*3600+26*60)+21.448_bp) * rad_asec ! Improved value
+         ob1 = -46.815_bp  * rad_asec, &
+         ob2 = -0.0006_bp  * rad_asec, &
+         ob3 =  0.00181_bp * rad_asec
+
+    t0     = ( tjm - 51544.5_bp ) / 36525.0_bp
+    meanObliquity = (( ob3 * t0 + ob2 ) * t0 + ob1 ) * t0 + ob0
+
+  END FUNCTION meanObliquity
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms radians to degrees, arcminutes, and -seconds.
+  !!
+  SUBROUTINE radiansToDAMAS(rad, deg, arcmin, arcsec)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)  :: rad
+    INTEGER, INTENT(out)  :: deg, arcmin
+    REAL(bp), INTENT(out) :: arcsec
+
+    deg    = INT(ABS(rad)/rad_deg)
+    arcmin = INT(60.0_bp*(ABS(rad)/rad_deg-deg))
+    arcsec = 3600.0_bp*(ABS(rad)/rad_deg-(deg+arcmin/60.0_bp))
+    deg    = INT(rad/rad_deg)
+
+  END SUBROUTINE radiansToDAMAS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms radians to hours, minutes, and -seconds.
+  !!
+  SUBROUTINE radiansToHMS(rad, hour, min, sec)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)  :: rad
+    INTEGER, INTENT(out)  :: hour, min
+    REAL(bp), INTENT(out) :: sec
+
+    hour = INT(rad/(rad_deg*15.0_bp))
+    min  = INT(60.0_bp*(rad/(rad_deg*15.0_bp)-hour))
+    sec  = 3600.0_bp*(rad/(rad_deg*15.0_bp)-(hour+min/60.0_bp))
+
+  END SUBROUTINE radiansToHMS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotation matrix around i"th axis: If X are "old" coordinates and
+  !! X" are "new" coordinates (referred to a frame which is rotated by
+  !! an angle alpha around an axis in direct sense), then X" = R X,
+  !! where R is the rotation matrix.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION rotationMatrix(alpha, axis)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: alpha
+    INTEGER, INTENT(in) :: axis
+    REAL(bp), DIMENSION(3,3) :: rotationMatrix 
+    INTEGER :: i1, i2, i3
+
+    IF (axis < 1 .OR. axis > 3) THEN
+       error = .TRUE.
+       CALL errorMessage("Base / rotationMatrix", &
+            "Axis out of range. It has to be 1, 2, or 3.", 1)
+       RETURN
+    END IF
+
+    i1 = axis
+    IF(i1 > 3) THEN
+       i1 = i1 - 3
+    END IF
+    i2 = i1 + 1
+    IF(i2 > 3) THEN
+       i2 = i2 - 3
+    END IF
+    i3 = i2 + 1
+    IF(i3 > 3) THEN
+       i3 = i3 - 3
+    END IF
+
+    rotationMatrix(i1,i1) = 1.0_bp
+    rotationMatrix(i1,i2) = 0.0_bp
+    rotationMatrix(i1,i3) = 0.0_bp
+
+    rotationMatrix(i2,i1) = 0.0_bp
+    rotationMatrix(i2,i2) = COS(alpha)
+    rotationMatrix(i2,i3) = SIN(alpha)
+
+    rotationMatrix(i3,i1) = 0.0_bp
+    rotationMatrix(i3,i2) = -SIN(alpha)
+    rotationMatrix(i3,i3) = COS(alpha)
+
+  END FUNCTION rotationMatrix
+
+
+
+
+  SUBROUTINE setAccessToDataFiles()
+
+    IMPLICIT NONE
+
+    ! only use with gfortran
+    !CALL get_environment_variable("OORB_DATA", OORB_DATA_DIR)
+    ! only use with g95
+    CALL getenv("OORB_DATA", OORB_DATA_DIR)
+    IF (LEN_TRIM(OORB_DATA_DIR) == 0) THEN
+       OORB_DATA_DIR = "."
+    END IF
+
+  END SUBROUTINE setAccessToDataFiles
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the global error verbose variable to a given value.
+  !! The value can be any integer between 1 and 5. By setting
+  !! it to 1, only the most critical error messages are shown.
+  !! Number 5 corresponds to all error messages.   
+  !!
+  SUBROUTINE setErrorVerbose(error)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: error
+
+    SELECT CASE (error)
+    CASE (:-1)
+       err_verb = 0
+    CASE (0:5) 
+       err_verb = error
+    CASE (6:)
+       err_verb = 5
+    CASE default
+       err_verb = 1
+    END SELECT
+
+  END SUBROUTINE setErrorVerbose
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the global information verbose variable to a given value.
+  !! The value can be any integer between 1 and 5. By setting
+  !! it to 1, only the most critical informative messages are shown.
+  !! Number 5 corresponds to all informative messages.   
+  !!
+  SUBROUTINE setInfoVerbose(info)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: info
+
+    SELECT CASE (info)
+    CASE (:-1)
+       info_verb = 0
+    CASE (0:5) 
+       info_verb = info
+    CASE (6:)
+       info_verb = 5
+    CASE default
+       info_verb = 1
+    END SELECT
+
+  END SUBROUTINE setInfoVerbose
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! If simulated observations (no light time correction, and
+  !! epoch given in TDT) are used, set "simulated" to _true_.
+  !! The default value is _false_.
+  !!
+  SUBROUTINE setSimulatedObservations(simulated)
+
+    IMPLICIT NONE
+    LOGICAL, INTENT(in) :: simulated
+
+    simulated_observations = simulated
+
+  END SUBROUTINE setSimulatedObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the angular distance in radians between two points on the
+  !! sky (that is, a unit sphere).
+  !!
+  REAL(bp) FUNCTION angularDistance(ra1, dec1, ra2, dec2)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: ra1, dec1, ra2, dec2
+    REAL(bp) :: cos_distance
+
+    cos_distance = COS(ra2-ra1)*COS(dec1)*COS(dec2) + &
+         SIN(dec1)*SIN(dec2)
+    IF (ABS(cos_distance) > 1.0_bp) THEN
+       cos_distance = SIGN(1.0_bp, cos_distance)
+    END IF
+    angularDistance = ACOS(cos_distance)
+
+  END FUNCTION angularDistance
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms MPC3 type designation to MPC type.
+  !!
+  !! Example:
+  !!
+  !! K04A0001S -> K04A01S
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE MPC3DesToMPCDes(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    CALL toInt(designation(6:7), i, error)
+    IF (error) THEN
+       CALL errorMessage("Base / MPC3DesToMPCDes", &
+            "Could not convert string to integer.", 1)
+       RETURN
+    END IF
+    designation(1:7) = designation(1:4) // mpc_conv_table(i) // &
+         designation(8:9)
+    designation(8:) = " "
+
+  END SUBROUTINE MPC3DesToMPCDes
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms MPC type designation to MPC3 type.
+  !!
+  !! Example:
+  !!
+  !! K04A01S -> K04A0001S
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE MPCDesToMPC3Des(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    IF (.NOT.(designation(1:1) == "I" .OR. &
+         designation(1:1) == "J" .OR. &
+         designation(1:1) == "K")) THEN
+       RETURN
+    END IF
+    DO i=0,SIZE(mpc_conv_table,dim=1)-1
+       IF (mpc_conv_table(i) == designation(5:5)) THEN
+          EXIT
+       END IF
+    END DO
+    designation(5:5) = "0"
+    designation(8:9) = designation(6:7)
+    IF (i <= 9) THEN
+       designation(6:6) = "0"
+       CALL toString(i, designation(7:7), error)
+    ELSE IF (i > 9) THEN
+       CALL toString(i, designation(6:7), error)
+    END IF
+
+  END SUBROUTINE MPCDesToMPC3Des
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Decodes an encoded MPC type designation.
+  !!
+  !! Example:
+  !!
+  !! K04A01S -> 2004 AS1
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE decodeMPCDesignation(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    CHARACTER(len=DESIGNATION_LEN) :: designation_
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    i = IACHAR(designation(1:1))
+    IF (INDEX(TRIM(designation)," ") /= 0 .OR. &
+         (i >= 48 .AND.  i <= 57)) THEN
+       ! Designation already seems to be decoded, because it 
+       ! contains empty space or starts with a number.
+       RETURN
+    END IF
+
+    IF (designation(3:3) == "S") THEN
+       ! Designation of type T3S1234:
+       designation_(1:4) = designation(4:7)
+       designation_(5:5) = " "
+       designation_(6:8) = designation(1:1) // "-" // &
+            designation(2:2)
+       designation = " "
+       designation = TRIM(designation_)
+    ELSE
+       ! Designation of type K01A12B:
+       designation_ = " "
+       DO i=0,SIZE(mpc_conv_table,dim=1)-1
+          IF (mpc_conv_table(i) == designation(1:1)) THEN
+             EXIT
+          END IF
+       END DO
+       CALL toString(i, designation_(1:2), error)
+       IF (error) THEN
+          CALL errorMessage("Base / decodeMPCDesignation", &
+               "Could not convert integer to string (5).", 1)       
+          WRITE(stderr,*) TRIM(designation)
+          RETURN
+       END IF
+       designation_(3:4) = designation(2:3)
+       designation_(5:5) = " "
+       designation_(6:6) = designation(4:4)
+       designation_(7:7) = designation(7:7)
+       DO i=0,SIZE(mpc_conv_table,dim=1)-1
+          IF (mpc_conv_table(i) == designation(5:5)) THEN
+             EXIT
+          END IF
+       END DO
+       CALL toString(i, designation_(8:9), error)
+       IF (error) THEN
+          CALL errorMessage("Base / decodeMPCDesignation", &
+               "Could not convert integer to string (10).", 1)       
+          WRITE(stderr,*) TRIM(designation)
+          RETURN
+       END IF
+       IF (designation_(8:9) == "00") THEN
+          designation_(8:) = " "
+       ELSE IF (designation_(8:8) == "0") THEN
+          designation_(8:8) = designation_(9:9)
+       END IF
+       IF (LEN_TRIM(designation_) >= 8 .OR. designation(6:6) /= "0") THEN
+          designation_ = TRIM(designation_) // designation(6:6)
+       END IF
+       designation = TRIM(designation_)
+    END IF
+
+  END SUBROUTINE decodeMPCDesignation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Decodes an encoded MPC type designation.
+  !!
+  !! Example:
+  !!
+  !! K04A0001S -> 2004 AS1
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE decodeMPC3Designation(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    CHARACTER(len=DESIGNATION_LEN) :: designation_
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    i = IACHAR(designation(1:1))
+    IF (INDEX(TRIM(designation)," ") /= 0 .OR. &
+         (i >= 48 .AND.  i <= 57)) THEN
+       ! Designation already seems to be decoded, because it 
+       ! contains empty space or starts with a number.
+       RETURN
+    END IF
+
+    IF (designation(3:3) == "S") THEN
+       ! Designation of type T3S1234:
+       designation_(1:4) = designation(4:7)
+       designation_(5:5) = " "
+       designation_(6:8) = designation(1:1) // "-" // &
+            designation(2:2)
+       designation = " "
+       designation = TRIM(designation_)
+    ELSE
+       ! Designation of type K01A0012B:
+       designation_ = " "
+       DO i=0,SIZE(mpc_conv_table,dim=1)-1
+          IF (mpc_conv_table(i) == designation(1:1)) THEN
+             EXIT
+          END IF
+       END DO
+       CALL toString(i, designation_(1:2), error)
+       IF (error) THEN
+          CALL errorMessage("Base / decodeMPCDesignation", &
+               "Could not convert integer to string (5).", 1)       
+          WRITE(stderr,*) TRIM(designation)
+          RETURN
+       END IF
+       designation_(3:4) = designation(2:3)
+       designation_(5:5) = " "
+       designation_(6:6) = designation(4:4)
+       designation_(7:7) = designation(9:9)
+       i = 5
+       DO WHILE (designation(i:i) == "0")
+          i = i + 1
+          IF (i > 8) THEN
+             EXIT
+          END IF
+       END DO
+       IF (i <= 8) THEN
+          designation_ = TRIM(designation_) // designation(i:8)
+       END IF
+       designation = TRIM(designation_)
+    END IF
+
+  END SUBROUTINE decodeMPC3Designation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Encodes a decoded MPC type designation.
+  !!
+  !! Example:
+  !!
+  !! 2004 AS1 -> K04A01S 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE encodeMPCDesignation(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    CHARACTER(len=DESIGNATION_LEN) :: designation_
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    i = IACHAR(designation(1:1))
+    IF (INDEX(TRIM(designation)," ") == 0 .OR. &
+         i < 48 .OR.  i > 57) THEN
+       ! Designation already seems to be encoded, because it has no
+       ! empty space or starts with a non-number.
+       RETURN
+    END IF
+
+    IF (INDEX(TRIM(designation),"-") /= 0) THEN
+       ! Designation of type 1234 A-B:
+       designation_(1:1) = designation(6:6)
+       designation_(2:2) = designation(8:8)
+       designation_(3:7) = "S" // designation(1:4)
+       designation = designation_(1:7)
+       designation(8:) = " "
+    ELSE
+       ! Designation of type 2001 AB12:
+       CALL toInt(designation(1:2), i, error)
+       IF (error) THEN
+          CALL errorMessage("Base / encodeMPCDesignation", &
+               "Could not convert string to integer (5).", 1)       
+          WRITE(stderr,*) TRIM(designation)
+          RETURN
+       END IF
+       designation_ = " "
+       designation_(1:3) = mpc_conv_table(i) // designation(3:4)
+       designation_(4:4) = designation(6:6)
+       IF (LEN_TRIM(designation) == 7) THEN
+          designation_(5:6) = "00" // designation(8:8)
+       ELSE IF (LEN_TRIM(designation) == 8) THEN
+          designation_(5:6) = "0" // designation(8:8)
+       ELSE IF (LEN_TRIM(designation) == 9) THEN
+          designation_(5:6) = designation(8:9)       
+       ELSE
+          CALL toInt(designation(8:9), i, error)
+          IF (error) THEN
+             CALL errorMessage("Base / encodeMPCDesignation", &
+                  "Could not convert string to integer (10).", 1)       
+             WRITE(stderr,*) TRIM(designation)
+             RETURN
+          END IF
+          designation_(5:6) = mpc_conv_table(i) // designation(10:10)
+       END IF
+       designation_(7:7) = designation(7:7)
+       designation = " "
+       designation = TRIM(designation_)
+    END IF
+
+  END SUBROUTINE encodeMPCDesignation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Encodes a decoded MPC type designation to the MPC3 format.
+  !!
+  !! Example:
+  !!
+  !! 2004 AS1 -> K04A0001S 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE encodeMPC3Designation(designation)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: designation
+    CHARACTER(len=DESIGNATION_LEN) :: designation_
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(designation)
+    i = IACHAR(designation(1:1))
+    IF (INDEX(TRIM(designation)," ") == 0 .OR. &
+         i < 48 .OR.  i > 57) THEN
+       ! Designation already seems to be encoded, because it has no
+       ! empty space or starts with a non-number.
+       RETURN
+    END IF
+
+    IF (INDEX(TRIM(designation),"-") /= 0) THEN
+       ! Designation of type 1234 A-B:
+       designation_(1:1) = designation(6:6)
+       designation_(2:2) = designation(8:8)
+       designation_(3:9) = "S00" // designation(1:4)
+       designation = designation_(1:9)
+       designation(10:) = " "
+    ELSE
+       ! Designation of type 2001 AB12:
+       CALL toInt(designation(1:2), i, error)
+       IF (error) THEN
+          CALL errorMessage("Base / encodeMPC3Designation", &
+               "Could not convert string to integer (5).", 1)       
+          WRITE(stderr,*) TRIM(designation)
+          RETURN
+       END IF
+       designation_ = TRIM(ADJUSTL(designation(8:)))
+       DO WHILE (LEN_TRIM(designation_) < 4) 
+          designation_ = "0" // TRIM(designation_)
+       END DO
+       designation_ = mpc_conv_table(i) // designation(3:4) // &
+            designation(6:6) // TRIM(designation_)
+       designation_(9:9) = designation(7:7)
+       designation = " "
+       designation = TRIM(designation_)
+    END IF
+
+  END SUBROUTINE encodeMPC3Designation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This routine returns the date and time in Greenwich England.
+  !! date(1) is day, date(2) is month (Jan=1,...,Dec=12), date(3) is
+  !! year, t(1) is hour, t(2) is minute, and t(3) is second.
+  !!
+  SUBROUTINE coordinatedUniversalTime(date, time)
+
+    IMPLICIT NONE
+    INTEGER, DIMENSION(3), INTENT(out) :: date, time
+    REAL(bp)                           :: jd, s
+    INTEGER, DIMENSION(8)              :: date_time
+
+    CALL DATE_AND_TIME(values=date_time)
+    CALL calendarDateToJulianDate(date_time(1), date_time(2), date_time(3), &
+         date_time(5), date_time(6), REAL(date_time(7), bp), jd)
+    ! Change jd to get correct UTC:
+    jd = jd - date_time(4)/(60.0_bp*24.0_bp)
+    CALL julianDateToCalendarDate(jd, date_time(1), date_time(2), date_time(3), &
+         date_time(5), date_time(6), s)
+    date_time(7) = NINT(s)
+    ! If seconds rounds to 60 then add half a second to the Julian date
+    ! and recalculate the calendar date:
+    IF (date_time(7) == 60) THEN
+       jd = jd + 0.5_bp/86400.0_bp
+       CALL julianDateToCalendarDate(jd, date_time(1), date_time(2), date_time(3), &
+            date_time(5), date_time(6), s)
+       date_time(7) = NINT(s)
+    ENDIF
+    date(1) = date_time(3)
+    date(2) = date_time(2)
+    date(3) = date_time(1)
+    time(1) = date_time(5)
+    time(2) = date_time(6)
+    time(3) = date_time(7)
+
+  END SUBROUTINE coordinatedUniversalTime
+
+
+
+
+
+END MODULE Base_cl
Index: trunk/mops/oorb/classes/CartesianCoordinates_class.f90
===================================================================
--- trunk/mops/oorb/classes/CartesianCoordinates_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/CartesianCoordinates_class.f90	(revision 34646)
@@ -0,0 +1,1110 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!  
+!! Type and routines for static Cartesian coordinates.
+!!
+!! @see Orbit_class 
+!!  
+!! @author  MG, JV, KM, TL
+!! @version 2009-12-31
+!!
+MODULE CartesianCoordinates_cl
+
+  USE Base_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  IMPLICIT NONE
+
+  PRIVATE :: new_CC
+  PRIVATE :: new_CC_coordinates
+  PRIVATE :: new_CC_spherical
+  PRIVATE :: new_CC_values
+  PRIVATE :: nullify_CC
+  PRIVATE :: copy_CC
+  PRIVATE :: exist_CC
+  PRIVATE :: getCoordinates_CC
+  PRIVATE :: getSCoord_CC
+  PRIVATE :: getPosition_CC
+  PRIVATE :: getVelocity_CC
+  PRIVATE :: getFrame_CC
+  PRIVATE :: getTime_CC
+  PRIVATE :: opposite_CC
+  PRIVATE :: rotateToEcliptic_CC
+  PRIVATE :: rotateToEcliptic_simple
+  PRIVATE :: rotateToEquatorial_CC
+  PRIVATE :: rotateToEquatorial_simple
+  PRIVATE :: addition_CC
+  PRIVATE :: subtraction_CC
+  PRIVATE :: partialsScoordWrtCcoord_CC
+
+  TYPE CartesianCoordinates
+     PRIVATE
+     REAL(bp), DIMENSION(3)   :: position
+     REAL(bp), DIMENSION(3)   :: velocity
+     ! Frame can be ecliptic or equatorial.
+     CHARACTER(len=FRAME_LEN) :: frame = "ecliptic"
+     TYPE (Time)              :: t
+     LOGICAL                  :: is_initialized = .FALSE.
+  END TYPE CartesianCoordinates
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_CC
+     MODULE PROCEDURE new_CC_coordinates
+     MODULE PROCEDURE new_CC_spherical
+     MODULE PROCEDURE new_CC_values
+  END INTERFACE
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_CC
+  END INTERFACE
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_CC
+  END INTERFACE
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_CC
+  END INTERFACE
+
+  INTERFACE getCoordinates
+     MODULE PROCEDURE getCoordinates_CC
+  END INTERFACE
+
+  INTERFACE getPosition
+     MODULE PROCEDURE getPosition_CC
+  END INTERFACE
+
+  INTERFACE getVelocity
+     MODULE PROCEDURE getVelocity_CC
+  END INTERFACE
+
+  INTERFACE getFrame
+     MODULE PROCEDURE getFrame_CC
+  END INTERFACE
+
+  INTERFACE getSCoord
+     MODULE PROCEDURE getSCoord_CC
+  END INTERFACE
+
+  INTERFACE getTime
+     MODULE PROCEDURE getTime_CC
+  END INTERFACE
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_CC
+     MODULE PROCEDURE reallocate_CC_1
+     MODULE PROCEDURE reallocate_CC_2
+  END INTERFACE
+
+  INTERFACE rotateToEquatorial
+     MODULE PROCEDURE rotateToEquatorial_CC
+     MODULE PROCEDURE rotateToEquatorial_simple
+  END INTERFACE
+
+  INTERFACE rotateToEcliptic
+     MODULE PROCEDURE rotateToEcliptic_CC
+     MODULE PROCEDURE rotateToEcliptic_simple
+  END INTERFACE
+
+  !! Returns a Cartesian state, which is the sum of the two given
+  !! Cartesian states (ecliptic or equatorial).
+  INTERFACE OPERATOR (+) 
+     MODULE PROCEDURE addition_CC
+  END INTERFACE
+
+  !! Returns a Cartesian state, which is the difference of the two
+  !! given Cartesian states (ecliptic or equatorial).
+  INTERFACE OPERATOR (-) 
+     MODULE PROCEDURE subtraction_CC
+  END INTERFACE
+
+  INTERFACE opposite
+     MODULE PROCEDURE opposite_CC
+  END INTERFACE
+
+  INTERFACE partialsScoordWrtCcoord
+     MODULE PROCEDURE partialsScoordWrtCcoord_CC
+  END INTERFACE
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a CartesianCoordinates-object. Position and velocity
+  !! are zero-vectors. Coordinate frame is ecliptic.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position       = (/ 0.0_bp, 0.0_bp, 0.0_bp /)
+    this%velocity       = (/ 0.0_bp, 0.0_bp, 0.0_bp /)
+    this%frame          = "ecliptic"
+    CALL NULLIFY(this%t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a CartesianCoordinates-object using a given
+  !! coordinates, coordinate frame, and epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_CC_coordinates(this, coordinates, frame, t)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6), INTENT(in)         :: coordinates
+    CHARACTER(len=*), INTENT(in)               :: frame
+    TYPE (Time), INTENT(in)                    :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position = coordinates(1:3)
+    this%velocity = coordinates(4:6)
+
+    IF (TRIM(frame) /= "equatorial" .AND. &
+         TRIM(frame) /= "ecliptic") THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Wrong frame of reference. " // &
+            "Choose either 'equatorial' or 'ecliptic'.", 1)
+       RETURN
+    ELSE
+       this%frame       = TRIM(frame)
+    END IF
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_CC_coordinates
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a CartesianCoordinates-object using a given
+  !! SphericalCoordinates-object.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_CC_spherical(this, scoord)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    TYPE (SphericalCoordinates), INTENT(in)    :: scoord
+    REAL(bp), DIMENSION(3)                     :: position, velocity
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    position = getPosition(scoord)
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / new",&
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+    this%position(1) = position(1) * COS(position(2)) * COS(position(3))
+    this%position(2) = position(1) * SIN(position(2)) * COS(position(3))
+    this%position(3) = position(1) * SIN(position(3))
+
+    velocity = getVelocity(scoord)
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / new",&
+            "TRACE BACK 2", 1)
+       RETURN
+    END IF
+    this%velocity(1) = COS(position(2))*COS(position(3))*velocity(1) - &
+         position(1)*SIN(position(2))*COS(position(3))*velocity(2)   - &
+         position(1)*COS(position(2))*SIN(position(3))*velocity(3)
+    this%velocity(2) = SIN(position(2))*COS(position(3))*velocity(1) + &
+         position(1)*COS(position(2))*COS(position(3))*velocity(2)   - &
+         position(1)*SIN(position(2))*SIN(position(3))*velocity(3)
+    this%velocity(3) = SIN(position(3))*velocity(1) + &
+         position(1)*COS(position(3))*velocity(3)
+
+    this%frame = getFrame(scoord)
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / new",&
+            "TRACE BACK 3", 1)
+       RETURN
+    END IF
+
+    this%t = getTime(scoord)
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / new",&
+            "TRACE BACK 4", 1)
+       RETURN
+    END IF
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_CC_spherical
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a CartesianCoordinates-object using a given position,
+  !! velocity, coordinate frame, and epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_CC_values(this, position, velocity, frame, t)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(3), INTENT(in)         :: position
+    REAL(bp), DIMENSION(3), INTENT(in)         :: velocity
+    CHARACTER(len=*), INTENT(in)               :: frame
+    TYPE (Time), INTENT(in)                    :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position       = position
+    this%velocity       = velocity
+
+    IF (TRIM(frame) /= "equatorial" .AND. &
+         TRIM(frame) /= "ecliptic") THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / new", &
+            "Wrong frame of reference. " // &
+            "Choose either 'equatorial' or 'ecliptic'.", 1)
+       RETURN
+    ELSE
+       this%frame       = TRIM(frame)
+    END IF
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_CC_values
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+
+    this%position       = 0.0_bp
+    this%velocity       = 0.0_bp
+    this%frame          = " "
+    CALL NULLIFY(this%t)
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (CartesianCoordinates)             :: copy_CC
+
+    copy_CC%position       = this%position
+    copy_CC%velocity       = this%velocity
+    copy_CC%frame          = TRIM(this%frame)
+    copy_CC%t              = copy(this%t)
+    copy_CC%is_initialized = this%is_initialized
+
+  END FUNCTION copy_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether it exists or not.
+  !!
+  LOGICAL FUNCTION exist_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+
+    exist_CC = this%is_initialized
+
+  END FUNCTION exist_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds "that" to "this", and returns the sum as a new object. 
+  !! Makes sure they are given in the same frame of reference
+  !! and that they are in the same epoch before adding. Returns
+  !! a nullified object if an error occurs.
+  !!
+  !! *NOTE*:
+  !! *Do*not*use*this*function*by*name,*but*by*using*the*addition*operator*!
+  !!
+  FUNCTION addition_CC(this, that)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: that
+    TYPE (CartesianCoordinates)             :: addition_CC, this_, that_
+
+    IF (.NOT. this%is_initialized) THEN
+       CALL errorMessage("CartesianCoordinates / + (addition)", &
+            "Left object has not been initialized.", 1)
+       CALL NULLIFY(addition_CC)
+       RETURN       
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       CALL errorMessage("CartesianCoordinates / + (addition)", &
+            "Right object has not been initialized.", 1)
+       CALL NULLIFY(addition_CC)
+       RETURN       
+    END IF
+
+    IF (this%frame /= that%frame) THEN
+       CALL errorMessage("CartesianCoordinates / + (addition)", &
+            "Coordinates are not given in the same frame of reference.", 1)
+       CALL NULLIFY(addition_CC)
+       RETURN       
+    END IF
+
+    this_ = copy(this)
+    that_ = copy(that)
+
+    IF (equal(this_%t,that_%t)) THEN
+       addition_CC = copy(this_)
+       addition_CC%position = this_%position + that_%position
+       addition_CC%velocity = this_%velocity + that_%velocity
+    ELSE
+       CALL errorMessage("CartesianCoordinates / + (addition)", &
+            "Coordinatess at different epochs cannot be used in addition.", 1)
+       CALL NULLIFY(addition_CC)
+       RETURN
+    END IF
+
+  END FUNCTION addition_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes light-time-corrected epoch for object's
+  !! Cartesian coordinates given the distance to the observer.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE estimateLightTime(this, distance)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                       :: distance
+    REAL(bp)                                   :: tdt
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / estimateLightTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    tdt = getMJD(this%t, "tdt")
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / estimateLightTime", &
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(this%t)
+
+    ! Subtract the time it takes for light to travel from the target
+    ! to the observer:
+    CALL NEW(this%t, tdt - distance/sol, "tdt")
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / estimateLightTime", &
+            "TRACE BACK 2", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE estimateLightTime
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates from the ecliptical to the equatorial
+  !! coordinate frame.
+  !!
+  SUBROUTINE rotateToEquatorial_simple(w)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(6), INTENT(inout) :: w
+    REAL(bp), DIMENSION(3,3)              :: R
+
+    R(1,:) = (/ 1.0_bp,   0.0_bp,    0.0_bp /)
+    R(2,:) = (/ 0.0_bp, COS(eps), -SIN(eps) /) 
+    R(3,:) = (/ 0.0_bp, SIN(eps),  COS(eps) /)
+    w(1:3) = MATMUL(R,w(1:3))
+    w(4:6) = MATMUL(R,w(4:6))
+
+  END SUBROUTINE rotateToEquatorial_simple
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates from the equatorial to the ecliptical
+  !! coordinate frame.
+  !!
+  SUBROUTINE rotateToEcliptic_simple(w)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(6), INTENT(inout) :: w
+    REAL(bp), DIMENSION(3,3)              :: R
+
+    R(1,:) = (/ 1.0_bp,    0.0_bp,   0.0_bp /)
+    R(2,:) = (/ 0.0_bp,  COS(eps), SIN(eps) /) 
+    R(3,:) = (/ 0.0_bp, -SIN(eps), COS(eps) /)
+    w(1:3) = MATMUL(R,w(1:3))
+    w(4:6) = MATMUL(R,w(4:6))
+
+  END SUBROUTINE rotateToEcliptic_simple
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of spherical coordinates 
+  !! (ra,dec) wrt Cartesian coordinates.
+  !!
+  !! @author TL
+  !!
+  SUBROUTINE partialsSCoordWrtCCoord_CC(this, partials)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(2,6), INTENT(out)   :: partials
+    REAL(bp), DIMENSION(3) :: pos
+    REAL(bp) :: tmp1, tmp2, tmp3
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / " // &
+            "partialsSCoordWrtCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Common terms.
+    pos  = getPosition(this)
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / " // &
+            "partialsSCoordWrtCCoord", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    tmp1 = 1.0_bp/SUM(pos(1:2)**2)
+    tmp2 = SQRT(tmp1)
+    tmp3 = 1.0_bp/SUM(pos**2)
+
+    ! First row: ra
+    partials(1,1)   = -pos(2)*tmp1
+    partials(1,2)   = pos(1)*tmp1
+    partials(1,3:6) = 0.0_bp
+    ! Second row: dec
+    partials(2,1)   = -pos(1)*pos(3)*tmp2*tmp3
+    partials(2,2)   = -pos(2)*pos(3)*tmp2*tmp3
+    partials(2,3)   = tmp2*(1-pos(3)**2*tmp3)
+    partials(2,4:6) = 0.0_bp
+
+  END SUBROUTINE partialsSCoordWrtCCoord_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the coordinate frame.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=FRAME_LEN) FUNCTION getFrame_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getFrame", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getFrame_CC = TRIM(this%frame)
+
+  END FUNCTION getFrame_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the position vector as [AU,AU,AU,AU/day,AU/day,AU/day].
+  !!
+  !! Returns error if not initialized.
+  !!
+  FUNCTION getCoordinates_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)                  :: getCoordinates_CC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getCoordinates", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getCoordinates_CC(1:3) = this%position
+    getCoordinates_CC(4:6) = this%velocity
+
+  END FUNCTION getCoordinates_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian position vector as AUs.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPosition_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)                  :: getPosition_CC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getPosition", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getPosition_CC = this%position
+
+  END FUNCTION getPosition_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Transforms Cartesian coordinates to spherical coordinates and
+  !! returns them as a SphericalCoordinates object with the same frame
+  !! as the CartesianCoordinates object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getSCoord_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (SphericalCoordinates)             :: getSCoord_CC
+    REAL(bp), DIMENSION(3)                  :: position, velocity
+    REAL(bp)                                :: sin_theta, cos_theta, &
+         sin_phi, r, rv
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getSCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! rho
+    position(1) = SQRT(DOT_PRODUCT(this%position,this%position))
+    ! theta
+    sin_theta = this%position(2) / &
+         SQRT(DOT_PRODUCT(this%position(1:2),this%position(1:2)))
+    cos_theta = this%position(1) / &
+         SQRT(DOT_PRODUCT(this%position(1:2),this%position(1:2)))
+    IF (ABS(cos_theta) > 1.0_bp) cos_theta = SIGN(1.0_bp, cos_theta)
+    position(2) = ACOS(cos_theta)
+    IF (sin_theta < 0.0_bp) position(2) = two_pi - position(2)
+    ! astronomical phi (= pi/2 - mathematical phi)
+    sin_phi = this%position(3)/position(1)
+    IF (ABS(sin_phi) > 1.0_bp) sin_phi = SIGN(1.0_bp, sin_phi)
+    position(3) = ASIN(sin_phi)
+
+    r = position(1)
+    rv = DOT_PRODUCT(this%position,this%velocity)
+    velocity(1) = rv/r
+    velocity(2) = (this%position(1)*this%velocity(2) - &
+         this%velocity(1)*this%position(2)) / &
+         (this%position(1)**2.0_bp + &
+         this%position(2)**2.0_bp)
+    velocity(3) = (r**2.0_bp*this%velocity(3) - rv*this%position(3)) / &
+         (r**2.0_bp * SQRT(this%position(1)**2.0_bp + &
+         this%position(2)**2.0_bp))
+
+    CALL NEW(getSCoord_CC, position, velocity, this%frame, copy(this%t))
+    IF (error) THEN
+       CALL errorMessage("CartesianCoordinates / getSCoord", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getSCoord_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Time-object corresponding to this state.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTime_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (Time)                             :: getTime_CC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getTime_CC = copy(this%t)
+
+  END FUNCTION getTime_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian velocity vector as AUs per day.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getVelocity_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)                  :: getVelocity_CC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / getVelocity", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getVelocity_CC = this%velocity
+
+  END FUNCTION getVelocity_CC
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes the opposite Cartesian coordinates, e.g., position and
+  !! velocity multiplied by -1.
+  !!
+  !! Returns error. 
+  !!
+  FUNCTION opposite_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (CartesianCoordinates)             :: opposite_CC
+
+    opposite_CC = copy(this)
+    opposite_CC%position = -1.0_bp * this%position
+    opposite_CC%velocity = -1.0_bp * this%velocity
+
+  END FUNCTION opposite_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of CartesianCoordinates-objects by
+  !! copying only the initialized objects to the new array.
+  !!
+  !! *Usage*:
+  !!
+  !! myccoords => reallocate(myccoords)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_CC(array)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: reallocate_CC, array
+    INTEGER :: i, j, n, err
+
+    n = 0
+    DO i=1,SIZE(array)
+       IF (exist(array(i))) THEN
+          n = n + 1
+       END IF
+    END DO
+    IF (n == 0) THEN
+       reallocate_CC => NULL()
+    ELSE
+       ALLOCATE(reallocate_CC(n), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("CartesianCoordinates / reallocate", &
+               "Could not allocate memory.", 1)
+          DEALLOCATE(array)
+          reallocate_CC => NULL()
+          RETURN
+       END IF
+       j = 0
+       DO i=1,SIZE(array)
+          IF (exist(array(i))) THEN
+             j = j + 1
+             reallocate_CC(j) = copy(array(i))
+             IF (error) THEN
+                DEALLOCATE(array)
+                CALL errorMessage("CartesianCoordinates / reallocate", &
+                     "TRACE BACK", 1)
+                RETURN          
+             END IF
+          END IF
+       END DO
+    END IF
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of CartesianCoordinates-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myccoords => reallocate(myccoords,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_CC_1(array, n)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: reallocate_CC_1, array
+    INTEGER, INTENT(in)                   :: n
+    INTEGER                               :: i, nold, err
+
+    ALLOCATE(reallocate_CC_1(n), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_CC_1 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    DO i=1, MIN(n,nold)
+       reallocate_CC_1(i) = copy(array(i))
+       IF (error) THEN
+          CALL errorMessage("CartesianCoordinates / reallocate", &
+               "TRACE BACK", 1)
+          RETURN          
+       END IF
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_CC_1
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of CartesianCoordinates-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myccoords => reallocate(myccoords,4,2)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_CC_2(array, n, m)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), DIMENSION(:,:), POINTER :: reallocate_CC_2, array
+    INTEGER, INTENT(in)                   :: n, m
+    INTEGER                               :: i, j, nold, mold, err
+
+    ALLOCATE(reallocate_CC_2(n,m), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_CC_2 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    mold = SIZE(array,dim=2)
+    DO i=1, MIN(n,nold)
+       DO j=1, MIN(m,mold)
+          reallocate_CC_2(i,j) = copy(array(i,j))
+       END DO
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_CC_2
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates to the ecliptic coordinate frame, if not
+  !! already the case.
+  !!
+  SUBROUTINE rotateToEcliptic_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6)                     :: coord
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / rotateToEcliptic", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%frame /= "ecliptic") THEN
+       coord(1:3) = this%position
+       coord(4:6) = this%velocity
+       CALL rotateToEcliptic(coord)
+       this%position = coord(1:3)
+       this%velocity = coord(4:6)
+       this%frame = "ecliptic"
+    END IF
+
+  END SUBROUTINE rotateToEcliptic_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates to the equatorial coordinate frame, if not
+  !! already the case.
+  !!
+  SUBROUTINE rotateToEquatorial_CC(this)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6)                     :: coord
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("CartesianCoordinates / rotateToEquatorial", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%frame /= "equatorial") THEN
+       coord(1:3) = this%position
+       coord(4:6) = this%velocity
+       CALL rotateToEquatorial(coord)
+       this%position = coord(1:3)
+       this%velocity = coord(4:6)
+       this%frame = "equatorial"
+    END IF
+
+  END SUBROUTINE rotateToEquatorial_CC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Subtracts "that" from "this", and returns the difference as a new
+  !! object. Makes sure they are given in the same frame of reference
+  !! and that they are in the same epoch before subtracting. Returns
+  !! a nullified object if an error occurs.
+  !!
+  !! *NOTE*:
+  !! *Do*not*use*this*function*by*name,*but*by*using*the*subtraction*operator*!
+  !!
+  FUNCTION subtraction_CC(this, that)
+
+    IMPLICIT NONE
+    TYPE (CartesianCoordinates), INTENT(in) :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: that
+    TYPE (CartesianCoordinates)             :: subtraction_CC, this_, that_
+
+    IF (.NOT. this%is_initialized) THEN
+       CALL errorMessage("CartesianCoordinates / - (subtraction)", &
+            "Left object has not been initialized.", 1)
+       CALL NULLIFY(subtraction_CC)
+       RETURN       
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       CALL errorMessage("CartesianCoordinates / - (subtraction)", &
+            "Right object has not been initialized.", 1)
+       CALL NULLIFY(subtraction_CC)
+       RETURN       
+    END IF
+
+    IF (this%frame /= that%frame) THEN
+       CALL errorMessage("CartesianCoordinates / - (subtraction)", &
+            "Coordinates are not given in the same frame of reference.", 1)
+       CALL NULLIFY(subtraction_CC)
+       RETURN       
+    END IF
+
+    this_ = copy(this)
+    that_ = copy(that)
+
+    IF (equal(this_%t,that_%t)) THEN
+       subtraction_CC = copy(this_)
+       subtraction_CC%position = this_%position - that_%position
+       subtraction_CC%velocity = this_%velocity - that_%velocity
+    ELSE
+       CALL errorMessage("CartesianCoordinates / - (subtraction)", &
+            "Coordinatess at different times can not be used in subtraction.", 1)
+       CALL NULLIFY(subtraction_CC)
+       RETURN          
+    END IF
+
+  END FUNCTION subtraction_CC
+
+
+
+
+
+END MODULE CartesianCoordinates_cl
Index: trunk/mops/oorb/classes/File_class.f90
===================================================================
--- trunk/mops/oorb/classes/File_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/File_class.f90	(revision 34646)
@@ -0,0 +1,1431 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012   !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Defines a File-object and the basic file handling routines like open, 
+!! close, read (character string), write (character string) etc. 
+!!
+!! *Example*:
+!!
+!! <pre>
+!!program myprog
+!!
+!! use File_cl
+!! implicit none
+!! type (File) :: f1, f2
+!! character(len=32) :: str
+!!
+!! call new(f1, "myfile1.txt")
+!! if (error) stop "Error 1"
+!!
+!! call open(f1)
+!! if (error) stop "Error 2"
+!!
+!! frmt = "(A20)"
+!! call readString(f1, trim(frmt), str)
+!! if (error) stop "Error 3"
+!!
+!! call nullify(f1)
+!! if (error) stop "Error 4"
+!!
+!! call new(f2, "myfile2.txt")
+!! if (error) stop "Error 5"
+!!
+!! call open(f2)
+!! if (error) stop "Error 6"
+!!
+!! frmt = "('Copy from myfile1.txt: ',A)"
+!! call writeString(f2, trim(frmt), str)
+!! if (error) stop "Error 7"
+!!
+!! call nullify(f2)
+!! if (error) stop "Error 8"
+!!
+!!end program myprog
+!! </pre>
+!!
+!! @author  MG
+!! @version 2012-01-17
+!! 
+!! @see Observations_class
+!! @see Time_class
+!!
+MODULE File_cl
+
+  USE Base_cl
+  USE Unit_cl
+
+  USE utilities
+
+  IMPLICIT NONE
+  PRIVATE :: new_F_scratch
+  PRIVATE :: new_F_name
+  PRIVATE :: nullify_F
+  PRIVATE :: copy_F
+  PRIVATE :: writeString_unformatted
+  PRIVATE :: writeString_formatted
+  PRIVATE :: readString_unformatted
+  PRIVATE :: readString_formatted
+  PRIVATE :: getUnit_F
+
+  TYPE File
+     PRIVATE
+     TYPE (Unit) :: lu                   ! Logical unit.
+     CHARACTER(len=FNAME_LEN) :: fname   ! File name.
+     CHARACTER(len=16) :: open_access    ! File access (SEQUENTIAL/DIRECT).
+     CHARACTER(len=16) :: open_action    ! Action (READWRITE/READ/WRITE).
+     CHARACTER(len=16) :: open_form      ! Form (FORMATTED/UNFORMATTED/BINARY).
+     CHARACTER(len=16) :: open_position  ! Position (ASIS/APPEND/REWIND).
+     CHARACTER(len=16) :: open_status    ! File status (UNKOWN/SCRATCH/OLD/NEW).
+     INTEGER :: open_recl                ! Record length in bytes (max length for sequential files).
+     LOGICAL :: opened         = .FALSE. ! File opened? (true=yes, false=no) 
+     LOGICAL :: is_initialized = .FALSE. ! Object initialized? (true=yes, false=no)
+  END TYPE File
+
+  !! Initializes a File-object. Can be 
+  !! used with or without a filename.
+  INTERFACE NEW
+     MODULE PROCEDURE new_F_scratch
+     MODULE PROCEDURE new_F_name
+  END INTERFACE NEW
+
+  !! Nullifies a File-object, e.g. closes the file.
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_F
+  END INTERFACE NULLIFY
+
+  !! Makes a copy of a File-object.
+  INTERFACE copy
+     MODULE PROCEDURE copy_F
+  END INTERFACE copy
+
+  !! Returns the status of the object, i.e. whether
+  !! it exists or not.
+  INTERFACE exist
+     MODULE PROCEDURE exist_F
+  END INTERFACE exist
+
+  !! Writes a formatted or list-directed 
+  !! character string to a file.
+  INTERFACE writeString
+     MODULE PROCEDURE writeString_unformatted
+     MODULE PROCEDURE writeString_formatted
+  END INTERFACE writeString
+
+  !! Reads a formatted or list-directed 
+  !! character string from a file.
+  INTERFACE readString
+     MODULE PROCEDURE readString_unformatted
+     MODULE PROCEDURE readString_formatted
+  END INTERFACE readString
+
+  !! Returns logical unit of a file object.
+  INTERFACE getUnit
+     MODULE PROCEDURE getUnit_F
+  END INTERFACE getUnit
+
+
+
+
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a simple File instance, i.e. a scratchfile with 
+  !! sequential access, and both read and write permissions.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call new(myfile)
+  !!
+  SUBROUTINE new_F_scratch(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / new", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%fname          = ""
+    this%open_access    = "sequential"
+    this%open_action    = "readwrite"
+    this%open_form      = "formatted"
+    this%open_position  = "asis"
+    this%open_recl      = -1
+    this%open_status    = "scratch"
+    this%opened         = .FALSE.
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_F_scratch
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new File instance. It's a named file (either old
+  !! or new) with sequential access, and both read and write permissions.
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if the file name is too long (more than 64 letters)
+  !! 
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call new(myfile, "myfile.dat")
+  !!
+  SUBROUTINE new_F_name(this, file_name)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: file_name
+
+    CALL NEW(this)
+    IF (error) THEN
+       CALL errorMessage("File / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    this%is_initialized = .FALSE.
+    this%open_status = "unknown"
+    IF (LEN_TRIM(file_name) > FNAME_LEN) THEN
+       error = .TRUE.
+       CALL errorMessage("File / new", &
+            "Filename (" // TRIM(file_name) // &
+            ") too long; adjust parameters.", 1)
+       RETURN
+    ELSE
+       this%fname    = TRIM(file_name)
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_F_name
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Closes a file. Returns _error_ =
+  !!     - _false_, if the file is properly closed, or if it 
+  !!                has not been opened.
+  !!     - _true_,  if an error occurs during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call closeFile(myfile) 
+  !!
+  SUBROUTINE nullify_F(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (this%opened) THEN
+       CALL NULLIFY(this%lu)
+       IF (error) THEN
+          CALL errorMessage("File / nullify", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+    END IF
+    this%opened         = .FALSE.
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_F
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_F(this)
+
+    IMPLICIT NONE
+    TYPE (File) :: this
+    TYPE (File) :: copy_F
+
+    copy_F%lu             = copy(this%lu)
+    copy_F%fname          = this%fname
+    copy_F%open_status    = this%open_status
+    copy_F%open_access    = this%open_access
+    copy_F%open_action    = this%open_action
+    copy_F%open_form      = this%open_form
+    copy_F%open_position  = this%open_position
+    copy_F%open_recl      = this%open_recl
+    copy_F%opened         = this%opened
+    copy_F%is_initialized = this%is_initialized
+
+  END FUNCTION copy_F
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_F(this)
+
+    IMPLICIT NONE
+    TYPE (File) :: this
+
+    exist_F = this%is_initialized
+
+  END FUNCTION exist_F
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the name of the file connected to this object. Returns
+  !! _error_ =
+  !!     - _false_, no errors occur.
+  !!     - _true_, if an error occurs during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! character(len=FNAME_LEN) :: fname
+  !!
+  !! ...
+  !!
+  !! fname = getFileName(myfile)
+  !!
+  CHARACTER(len=FNAME_LEN) FUNCTION getFileName(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getFileName", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getFileName = TRIM(this%fname)
+
+  END FUNCTION getFileName
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Counts the number of columns in a file based on the first row and
+  !! assuming an empty space as the column delimiter. Returns _error_ =
+  !!     - _false_, no errors occur.
+  !!     - _true_, if an error occurs during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! integer :: nr_of_columns
+  !!
+  !! ...
+  !!
+  !! nr_of_columns = getNrOfColumns(myfile, error) 
+  !!
+  INTEGER FUNCTION getNrOfColumns(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+    CHARACTER(len=4096)     :: line, line_
+    INTEGER                 :: i, err, indx
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfColumns", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfColumns", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    REWIND(getUnit(this), iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfColumns", &
+            "Error while rewinding the file.", 1)
+       RETURN
+    END IF
+
+    line = " "
+    READ(getUnit(this), "(A)", iostat=err) line
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfColumns", &
+            "Error while reading first line of file " // TRIM(this%fname), 1)
+       RETURN
+    END IF
+
+    REWIND(getUnit(this), iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfColumns", &
+            "Error while rewinding the file.", 1)
+       RETURN
+    END IF
+
+    i = 0
+    DO WHILE (LEN_TRIM(line) /= 0)
+       Line_ = " "
+       IF (line(1:1) /= " ") THEN
+          i = i + 1
+          indx = INDEX(line," ")
+          line_ = line(indx:)
+          line = " "
+          line = line_
+       ELSE
+          line_ = line(2:)
+          line = " "
+          line = line_          
+       END IF
+    END DO
+
+    getNrOfColumns = i
+
+  END FUNCTION getNrOfColumns
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Counts the number of lines in a file. Returns _error_ =
+  !!     - _false_, no errors occur.
+  !!     - _true_, if an error occurs during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! integer :: nr_of_lines
+  !!
+  !! ...
+  !!
+  !! nr_of_lines = getNrOfLines(myfile, error) 
+  !!
+  INTEGER FUNCTION getNrOfLines(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+    CHARACTER(len=5)        :: line
+    INTEGER                 :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfLines", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfLines", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    REWIND(getUnit(this), iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfLines", &
+            "Error while rewinding the file.", 1)
+       RETURN
+    END IF
+
+    i = 0
+    DO
+       READ(getUnit(this), "(a)", iostat=err) line
+       IF (err == 0) THEN
+          i = i + 1
+       ELSE IF (err < 0) THEN
+          ! It's the end-of-file: 
+          EXIT
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("File / getNrOfLines", &
+               "Error while counting lines in file.", 1)
+          RETURN
+       END IF
+    END DO
+
+    REWIND(getUnit(this), iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / getNrOfLines", &
+            "Error while rewinding the file.", 1)
+       RETURN
+    END IF
+
+    getNrOfLines = i
+
+  END FUNCTION getNrOfLines
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !!  - record length, if the file has been opened for direct access.
+  !!  - maximum record length, if the file has been opened for
+  !!    sequential access.
+  !!  - 0, if the file has not been opened, or it does not exist.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! integer :: reclen
+  !!
+  !! ...
+  !!
+  !! recl = getRecordLength(myfile) 
+  !! 
+  INTEGER FUNCTION getRecordLength(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+    INTEGER                 :: record_length, err
+
+    IF (.NOT. this%is_initialized) THEN
+       CALL errorMessage("File / getRecordLength", &
+            "Object has not yet been initialized.", 1)
+       getRecordLength = 0
+       RETURN
+    END IF
+
+    IF (LEN_TRIM(this%fname) /= 0) THEN 
+       INQUIRE(file=TRIM(this%fname), recl=record_length, iostat=err)
+       IF (err == 0) THEN
+          getRecordLength = record_length
+       ELSE
+          getRecordLength = 0
+       END IF
+    ELSE
+       getRecordLength = 0
+    END IF
+
+  END FUNCTION getRecordLength
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !!     - logical unit number, if the file has been opened.
+  !!     - -1, if the file has not been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! integer :: logical_unit
+  !!
+  !! ...
+  !!
+  !! logical_unit = getUnit(myfile) 
+  !!
+  INTEGER FUNCTION getUnit_F(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       getUnit_F = -1
+    ELSE IF (.NOT. this%opened) THEN
+       getUnit_F = -1
+    ELSE
+       getUnit_F = getUnit(this%lu)
+    END IF
+
+  END FUNCTION getUnit_F
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !!     - _true_, if the file has been opened.
+  !!     - _false_, if the file has not been opened
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! logical :: open
+  !!
+  !! ...
+  !!
+  !! open = isOpen(myfile) 
+  !!
+  LOGICAL FUNCTION isOpen(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: this
+
+    isOpen = this%opened
+
+  END FUNCTION isOpen
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Opens a file. Open specifiers can be altered with the 
+  !! _set_ routines (see below). Returns _error_ =
+  !!  - _false_, if the file is opened, or if it already has been
+  !!             opened.
+  !!  - _true_,  if an error occurs during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call openFile(myfile) 
+  !!
+  SUBROUTINE OPEN(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+    CHARACTER(len=8)           :: str
+    INTEGER                    :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / open", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       CALL NEW(this%lu)
+       IF (error) THEN
+          CALL errorMessage("File / open", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+       IF (this%open_recl == -1) THEN
+          IF (this%open_position == "none") THEN
+             OPEN(unit=getUnit(this%lu), file=TRIM(this%fname), form=TRIM(this%open_form), &
+                  access=TRIM(this%open_access), status=TRIM(this%open_status), &
+                  action=TRIM(this%open_action), iostat=err)
+          ELSE
+             OPEN(unit=getUnit(this%lu), file=TRIM(this%fname), form=TRIM(this%open_form), &
+                  access=TRIM(this%open_access), status=TRIM(this%open_status), &
+                  position=TRIM(this%open_position), action=TRIM(this%open_action), iostat=err)
+          END IF
+       ELSE
+          IF (this%open_position == "none") THEN
+             OPEN(unit=getUnit(this%lu), file=TRIM(this%fname), form=TRIM(this%open_form), &
+                  access=TRIM(this%open_access), status=TRIM(this%open_status), &
+                  recl=this%open_recl, action=TRIM(this%open_action), iostat=err)
+          ELSE
+             OPEN(unit=getUnit(this%lu), file=TRIM(this%fname), form=TRIM(this%open_form), &
+                  access=TRIM(this%open_access), status=TRIM(this%open_status), &
+                  position=TRIM(this%open_position), recl=this%open_recl, &
+                  action=TRIM(this%open_action), iostat=err)
+          END IF
+       END IF
+       IF (err == 0) THEN
+          this%opened = .TRUE.
+       ELSE
+          this%opened = .FALSE.
+          CALL NULLIFY(this%lu)
+          CALL toString(err, str, error)
+          error = .TRUE.
+          CALL errorMessage("File / open", &
+               "Could not open file (" // TRIM(this%fname) // &
+               "). Error code " // TRIM(str) // ".", 1)
+          RETURN     
+       END IF
+    END IF
+
+  END SUBROUTINE OPEN
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads a formatted (_len_ = *) character string (_len_ = *) from 
+  !! file and moves to the following line. Returns _error_ = 
+  !!     - _false_, if the file has been opened and 
+  !!       no errors occured during the procedure.
+  !!     - _true_, if the file has not been opened, or
+  !!       an error occured during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! character(len=20) :: mystring
+  !!
+  !! character(len=20) :: myformat = "(a30)"
+  !!
+  !! ...
+  !!
+  !! call readString(myfile, trim(myformat), mystring) 
+  !!
+  SUBROUTINE readString_formatted(this, frmt, str)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in)       :: this
+    CHARACTER(len=*), INTENT(in)  :: frmt
+    CHARACTER(len=*), INTENT(out) :: str
+    INTEGER                       :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    READ(getUnit(this%lu), fmt=TRIM(frmt), iostat=err) str
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "Could not read string from file.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE readString_formatted
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads a singel, list-directed character string (_len_ = *) 
+  !! from file and moves to the following line. Returns _error_ = 
+  !!     - _false_, if the file has been opened and 
+  !!       no errors occured during the procedure.
+  !!     - _true_, if the file has not been opened, or
+  !!       an error occured during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! character(len=20) :: mystring
+  !!
+  !! ...
+  !!
+  !! call readString(myfile, mystring) 
+  !!
+  SUBROUTINE readString_unformatted(this, str)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in)       :: this
+    CHARACTER(len=*), INTENT(out) :: str
+    INTEGER                       :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    READ(getUnit(this%lu), *, iostat=err) str
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / readString", &
+            "Could not read string from file.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE readString_unformatted
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Allows unformatted direct access with a record length of 
+  !! _record___length_ bytes for this File-instance. Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! integer :: reclen = 2
+  !!
+  !! ...
+  !!
+  !! call setAccessDirect(myfile, reclen) 
+  !!
+  SUBROUTINE setAccessDirect(this, record_length)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+    INTEGER, INTENT(in)        :: record_length
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setAccessDirect", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setAccessDirect", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_access = "direct"
+    this%open_form   = "unformatted"
+    this%open_recl   = record_length
+    this%open_position = "none"
+
+  END SUBROUTINE setAccessDirect
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Allows formatted sequential access for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setAccessSequential(myfile) 
+  !!
+  SUBROUTINE setAccessSequential(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setAccessSequential", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setAccessSequential", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_access = "sequential"
+    this%open_form   = "formatted"
+    this%open_recl   = -1
+
+
+  END SUBROUTINE setAccessSequential
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _only_reading_allowed_ for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setActionRead(myfile) 
+  !!
+  SUBROUTINE setActionRead(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionRead", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionRead", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_action = "read"
+
+  END SUBROUTINE setActionRead
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _both_reading_and_writing_allowed_
+  !! for this File-instance. Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setActionReadWrite(myfile) 
+  !!
+  SUBROUTINE setActionReadWrite(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionReadWrite", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionReadWrite", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_action = "readwrite"
+
+  END SUBROUTINE setActionReadWrite
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _only_writing_allowed_ for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setActionWrite(myfile) 
+  !!
+  SUBROUTINE setActionWrite(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionWrite", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setActionWrite", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_action = "write"
+
+  END SUBROUTINE setActionWrite
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets position flag _append_ for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setPositionAppend(myfile) 
+  !!
+  SUBROUTINE setPositionAppend(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionAppend", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionAppend", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_position = "append"
+    this%open_access   = "sequential"
+
+  END SUBROUTINE setPositionAppend
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets position flag _asis_ (default) for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setPositionAsis(myfile) 
+  !!
+  SUBROUTINE setPositionAsis(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionAsis", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionAsis", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_position = "asis"
+    this%open_access   = "sequential"
+
+  END SUBROUTINE setPositionAsis
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets position flag _rewind_ for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setPositionRewind(myfile)
+  !!
+  SUBROUTINE setPositionRewind(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionRewind", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setPositionRewind", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_position = "rewind"
+    this%open_access   = "sequential"
+
+  END SUBROUTINE setPositionRewind
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _file_must_not_exist for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setStatusNew(myfile) 
+  !!
+  SUBROUTINE setStatusNew(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusNew", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusNew", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_status = "new"
+
+  END SUBROUTINE setStatusNew
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _file_must_exist_ for this File-instance. 
+  !! Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setStatusOld(myfile) 
+  !!
+  SUBROUTINE setStatusOld(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusOld", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusOld", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_status = "old"
+
+  END SUBROUTINE setStatusOld
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets flag _this_file_replaces_an_existing_file_ 
+  !! for this File-instance. Returns _error_ =
+  !!     - _false_, if the file has not yet been opened.
+  !!     - _true_, if the file has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! ...
+  !!
+  !! call setStatusReplace(myfile) 
+  !!
+  SUBROUTINE setStatusReplace(this)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusReplace", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / setStatusReplace", &
+            "File has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%open_status = "replace"
+
+  END SUBROUTINE setStatusReplace
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Writes a formatted (_len_ = *) string (_len_ = *) to 
+  !! file and moves to the following line. Returns _error_ =
+  !!     - _false_, if the file has been opened and 
+  !!       no errors occured during the procedure.
+  !!     - _true_, if the file has not been opened, or
+  !!       an error occured during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! character(len=20) :: mystring = "Hello!"
+  !!
+  !! character(len=20) :: myformat = "(a10)"
+  !!
+  !! ...
+  !!
+  !! call writeString(myfile, myformat, mystring) 
+  !!
+  SUBROUTINE writeString_formatted(this, frmt, str)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: frmt
+    CHARACTER(len=*), INTENT(in) :: str
+    INTEGER                      :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    WRITE(getUnit(this%lu), TRIM(frmt), iostat=err) TRIM(str)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "Could not write string to file.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE writeString_formatted
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Writes a string (_len_ = *) to file and moves 
+  !! to the following line. Returns _error_ = 
+  !!     - _false_, if the file has been opened and 
+  !!       no errors occured during the procedure.
+  !!     - _true_, if the file has not been opened, or
+  !!       an error occured during the procedure.
+  !!
+  !! *Usage*:
+  !!
+  !! type (File) :: myfile
+  !!
+  !! character(len=20) :: mystring = "Hello!"
+  !!
+  !! ...
+  !!
+  !! call writeString(myfile, mystring) 
+  !!
+  SUBROUTINE writeString_unformatted(this, str)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: str
+    INTEGER                      :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. this%opened) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "File has not yet been opened.", 1)
+       RETURN
+    END IF
+
+    WRITE(getUnit(this%lu), *, iostat=err) TRIM(str)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("File / writeString", &
+            "Could not write string to file.", 1)
+       RETURN       
+    END IF
+
+  END SUBROUTINE writeString_unformatted
+
+
+
+
+
+END MODULE File_cl
+
+
+
+
+
Index: trunk/mops/oorb/classes/Makefile
===================================================================
--- trunk/mops/oorb/classes/Makefile	(revision 34646)
+++ trunk/mops/oorb/classes/Makefile	(revision 34646)
@@ -0,0 +1,52 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# This is a makefile for Fortran 90/95 classes.
+#
+# Author: MG
+# Date:   2009-11-09
+
+include ../make.config
+include ../Makefile.include
+OBJECTFILES := $(notdir $(patsubst %.f90,%.o,$(F90_CLASS_SOURCES)))
+
+# Make everything:
+all: modules $(OBJECTFILES)
+
+# Compile object files:
+%.o : %.f90
+	$(FC) -c $(FCOPTIONS) $(FC_INC)../modules $<
+
+modules:
+	cd ../$(MODULEPATH) ; $(MAKE) all
+
+# Remove compiled classes and modules:
+clean:
+	rm -f *.o *.mod *~
+
+
+
+
+
+
+
Index: trunk/mops/oorb/classes/Observation_class.f90
===================================================================
--- trunk/mops/oorb/classes/Observation_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Observation_class.f90	(revision 34646)
@@ -0,0 +1,2000 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!
+!! Generic type and routines for an astrometric observation, which can
+!! be presented with spherical coordinates and their time derivatives.
+!!  
+!! @see Observations_class 
+!!  
+!! @author  MG, JV 
+!! @version 2012-02-15
+!!  
+MODULE Observation_cl
+
+  USE Base_cl
+  USE Time_cl
+  USE Observatory_cl
+  USE SphericalCoordinates_cl
+  USE CartesianCoordinates_cl
+
+  USE utilities
+
+  IMPLICIT NONE
+  PRIVATE :: NEW_Obs
+  PRIVATE :: NULLIFY_Obs
+  PRIVATE :: copy_Obs
+  PRIVATE :: exist_Obs
+  PRIVATE :: reallocate_a1_Obs
+  PRIVATE :: reallocate_a2_Obs
+  PRIVATE :: addMultinormalDeviate_Obs
+  PRIVATE :: addUniformDeviate_Obs
+  PRIVATE :: setDesignation_Obs
+  PRIVATE :: equal_Obs
+  PRIVATE :: getRA_Obs
+  PRIVATE :: getDec_Obs
+  PRIVATE :: getNumber_Obs
+  PRIVATE :: getTime_Obs
+  PRIVATE :: getCode_Obs
+  PRIVATE :: getCovarianceMatrix_Obs
+  PRIVATE :: getObservationMask_Obs
+  PRIVATE :: getObservatory_Obs
+  PRIVATE :: getObservatoryCCoord_Obs
+  PRIVATE :: getObservatoryCode_Obs
+  PRIVATE :: getStandardDeviations_Obs
+  PRIVATE :: setNumber_Obs
+
+  TYPE Observation
+     PRIVATE
+     INTEGER                        :: number
+     CHARACTER(len=DESIGNATION_LEN) :: designation
+     LOGICAL                        :: discovery
+     CHARACTER(len=1)               :: note1, note2, mode
+     CHARACTER(len=2)               :: filter
+     TYPE (SphericalCoordinates)    :: obs_scoord
+     REAL(bp), DIMENSION(6,6)       :: covariance
+     LOGICAL, DIMENSION(6)          :: obs_mask
+     REAL(bp)                       :: mag
+     REAL(bp)                       :: mag_unc
+     REAL(bp)                       :: s2n
+     CHARACTER(len=DESIGNATION_LEN) :: secret_name
+     TYPE (Observatory)             :: obsy
+     TYPE (CartesianCoordinates)    :: obsy_ccoord
+     TYPE (CartesianCoordinates)    :: satellite_ccoord
+     INTEGER                        :: coord_unit
+     LOGICAL                        :: is_initialized = .FALSE.
+  END TYPE Observation
+
+  INTERFACE NEW
+     MODULE PROCEDURE NEW_Obs
+  END INTERFACE NEW
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE NULLIFY_Obs
+  END INTERFACE NULLIFY
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_Obs
+  END INTERFACE copy
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_Obs
+  END INTERFACE exist
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_a1_Obs
+     MODULE PROCEDURE reallocate_a2_Obs
+  END INTERFACE reallocate
+
+  INTERFACE addMultinormalDeviate
+     MODULE PROCEDURE addMultinormalDeviate_Obs
+  END INTERFACE addMultinormalDeviate
+
+  INTERFACE addUniformDeviate
+     MODULE PROCEDURE addUniformDeviate_Obs
+  END INTERFACE addUniformDeviate
+
+  INTERFACE getDesignation
+     MODULE PROCEDURE getDesignation_Obs
+  END INTERFACE getDesignation
+
+  INTERFACE setDesignation
+     MODULE PROCEDURE setDesignation_Obs
+  END INTERFACE setDesignation
+
+  INTERFACE equal
+     MODULE PROCEDURE equal_Obs
+  END INTERFACE equal
+
+  INTERFACE getDec
+     MODULE PROCEDURE getDec_Obs
+  END INTERFACE getDec
+
+  INTERFACE getID
+     MODULE PROCEDURE getID_Obs
+  END INTERFACE getID
+
+  INTERFACE getNumber
+     MODULE PROCEDURE getNumber_Obs
+  END INTERFACE getNumber
+
+  INTERFACE getRA
+     MODULE PROCEDURE getRA_Obs
+  END INTERFACE getRA
+
+  INTERFACE getTime
+     MODULE PROCEDURE getTime_Obs
+  END INTERFACE getTime
+
+  INTERFACE getCode
+     MODULE PROCEDURE getCode_Obs
+  END INTERFACE getCode
+
+  INTERFACE getCovarianceMatrix
+     MODULE PROCEDURE getCovarianceMatrix_Obs
+  END INTERFACE getCovarianceMatrix
+
+  INTERFACE getObservationMask
+     MODULE PROCEDURE getObservationMask_Obs
+  END INTERFACE getObservationMask
+
+  INTERFACE getObservatory
+     MODULE PROCEDURE getObservatory_Obs
+  END INTERFACE getObservatory
+
+  INTERFACE getObservatoryCCoord
+     MODULE PROCEDURE getObservatoryCCoord_Obs
+  END INTERFACE getObservatoryCCoord
+
+  INTERFACE getObservatoryCode
+     MODULE PROCEDURE getObservatoryCode_Obs
+  END INTERFACE getObservatoryCode
+
+  INTERFACE getStandardDeviations
+     MODULE PROCEDURE getStandardDeviations_Obs
+  END INTERFACE getStandardDeviations
+
+  INTERFACE setNumber
+     MODULE PROCEDURE setNumber_Obs
+  END INTERFACE setNumber
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes this object with the given values.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE NEW_Obs(this, number, designation, discovery, note1, &
+       note2, obs_scoord, covariance, obs_mask, mag, mag_unc, filter, &
+       s2n, obsy, obsy_ccoord, satellite_ccoord, coord_unit, secret_name)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout)                 :: this
+    INTEGER, INTENT(in)                               :: number
+    CHARACTER(len=*), INTENT(in)                      :: designation
+    LOGICAL, INTENT(in)                               :: discovery
+    CHARACTER(len=*), INTENT(in)                      :: note1, note2
+    CHARACTER(len=*), INTENT(in)                      :: filter
+    TYPE (SphericalCoordinates), INTENT(in)           :: obs_scoord
+    REAL(bp), DIMENSION(6,6), INTENT(in)              :: covariance
+    LOGICAL, DIMENSION(6), INTENT(in)                 :: obs_mask
+    REAL(bp), INTENT(in)                              :: mag
+    REAL(bp), INTENT(in), OPTIONAL                    :: mag_unc
+    REAL(bp), INTENT(in), OPTIONAL                    :: s2n
+    TYPE (Observatory), INTENT(in)                    :: obsy
+    TYPE (CartesianCoordinates), INTENT(in)           :: obsy_ccoord
+    TYPE (CartesianCoordinates), INTENT(in), OPTIONAL :: satellite_ccoord
+    INTEGER, INTENT(in), OPTIONAL                     :: coord_unit
+    CHARACTER(len=*), INTENT(in), OPTIONAL            :: secret_name
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%number             = number
+    IF (LEN_TRIM(designation) <= designation_len) THEN
+       this%designation = TRIM(designation)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Observation / new", &
+            "Too many characters in designation:" // TRIM(designation), 1)
+       RETURN
+    END IF
+    this%discovery         = discovery
+    this%note1             = note1
+    this%note2             = note2
+    this%obs_scoord        = copy(obs_scoord)
+    this%covariance        = covariance
+    this%obs_mask          = obs_mask
+    this%mag               = mag
+    IF (PRESENT(mag_unc)) THEN
+       this%mag_unc        = mag_unc
+    END IF
+    this%filter              = filter
+    IF (PRESENT(s2n)) THEN
+       this%s2n            = s2n
+    END IF
+    this%obsy              = copy(obsy)
+    this%obsy_ccoord       = copy(obsy_ccoord)
+    IF ((note2 == "S" .NEQV. PRESENT(satellite_ccoord)) .OR. &
+         (note2 == "S" .NEQV. PRESENT(coord_unit))) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / new", &
+            "Input of satellite (?) observation is inconsistent.", 1)
+       RETURN
+    END IF
+    IF (PRESENT(satellite_ccoord)) THEN
+       this%satellite_ccoord = copy(satellite_ccoord)
+    END IF
+    IF (PRESENT(coord_unit)) THEN
+       this%coord_unit = coord_unit
+    END IF
+    IF (PRESENT(secret_name)) THEN
+       this%secret_name = secret_name
+    END IF
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE NEW_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE NULLIFY_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout) :: this
+
+    this%number            = 0
+    this%designation       = ""
+    this%discovery         = .FALSE.
+    this%note1             = ""
+    this%note2             = ""
+    CALL NULLIFY(this%obs_scoord)
+    this%covariance = 0.0_bp
+    this%obs_mask          = .FALSE.
+    this%mag               = 0.0_bp
+    this%mag_unc           = -1.0_bp
+    this%filter              = "  "
+    this%s2n               = -1.0_bp
+    CALL NULLIFY(this%obsy)
+    CALL NULLIFY(this%obsy_ccoord)
+    CALL NULLIFY(this%satellite_ccoord)
+    this%coord_unit        = 0
+    this%secret_name       = " "
+    this%is_initialized    = .FALSE.
+
+  END SUBROUTINE NULLIFY_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (Observation)             :: copy_Obs
+
+    copy_Obs%number            = this%number
+    copy_Obs%designation       = this%designation
+    copy_Obs%discovery         = this%discovery
+    copy_Obs%note1             = this%note1
+    copy_Obs%note2             = this%note2
+    copy_Obs%obs_scoord        = copy(this%obs_scoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / copy", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    copy_Obs%covariance = this%covariance
+    copy_Obs%obs_mask          = this%obs_mask
+    copy_Obs%mag               = this%mag
+    copy_Obs%mag_unc           = this%mag_unc
+    copy_Obs%filter              = this%filter
+    copy_Obs%s2n               = this%s2n
+    copy_Obs%obsy              = copy(this%obsy)
+    IF (error) THEN
+       CALL errorMessage("Observation / copy", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    copy_Obs%obsy_ccoord       = copy(this%obsy_ccoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / copy", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    copy_Obs%satellite_ccoord  = copy(this%satellite_ccoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / copy", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+    copy_Obs%coord_unit        = this%coord_unit
+    copy_Obs%secret_name       = this%secret_name
+    copy_Obs%is_initialized    = this%is_initialized
+
+  END FUNCTION copy_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of this object, i.e. whether it exists or not.
+  !!
+  LOGICAL FUNCTION exist_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    exist_Obs = this%is_initialized
+
+  END FUNCTION exist_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Observation-objects and
+  !! copies the existing (non-nullified) data from the old array to
+  !! the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myobservations => reallocate(myobservations,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_a1_Obs(array,n)
+
+    IMPLICIT NONE
+    TYPE (Observation), DIMENSION(:), POINTER :: reallocate_a1_Obs, array
+    INTEGER, INTENT(in), OPTIONAL             :: n
+    INTEGER                                   :: i, nn, nold, err, nonexistent
+
+    nonexistent = 0
+    IF (ASSOCIATED(array)) THEN
+       nold = SIZE(array,dim=1)
+    ELSE
+       nold = 0
+    END IF
+    IF (PRESENT(n)) THEN
+       nn = n
+    ELSE
+       nn = 0
+       DO i=1,nold
+          IF (array(i)%is_initialized) THEN
+             nn = nn + 1
+          END IF
+       END DO
+    END IF
+    IF (nn /= 0) THEN
+       ALLOCATE(reallocate_a1_Obs(nn), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / reallocate", &
+               "Could not allocate memory.", 1)
+          reallocate_a1_Obs => NULL()
+          RETURN
+       END IF
+    ELSE
+       reallocate_a1_Obs => NULL()
+       DO i=1,SIZE(array)
+          CALL NULLIFY(array(i))
+       END DO
+       DEALLOCATE(array, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / reallocate", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+
+    ! Return if there isn't anything to copy:
+    IF (.NOT.ASSOCIATED(array)) THEN
+       RETURN
+    END IF
+
+    ! Scan the whole initial array if n isn't present:
+    IF (.NOT.PRESENT(n)) THEN
+       nn = nold
+    END IF
+    DO i=1,MIN(nn,nold)
+       IF (.NOT.array(i)%is_initialized) THEN
+          nonexistent = nonexistent + 1
+          CYCLE
+       END IF
+       reallocate_a1_Obs(i-nonexistent) = copy(array(i))
+    END DO
+    DO i=1,SIZE(array)
+       CALL NULLIFY(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_a1_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Observation-objects and
+  !! copies existing data from the old array to
+  !! the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myobservations => reallocate(myobservations,4,5)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_a2_Obs(array,n,m)
+
+    IMPLICIT NONE
+    TYPE (Observation), DIMENSION(:,:), POINTER :: reallocate_a2_Obs, array
+    INTEGER, INTENT(in)                         :: n, m
+    INTEGER                                     :: i, j, nold, mold, err
+
+    nold = SIZE(array,dim=1)
+    mold = SIZE(array,dim=2)
+    ALLOCATE(reallocate_a2_Obs(n,m), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_a2_Obs => NULL()
+       RETURN
+    END IF
+
+    ! Return if there isn't anything to copy:
+    IF (.NOT.ASSOCIATED(array)) THEN
+       RETURN
+    END IF
+    DO i=1,MIN(n,nold)
+       DO j=1,MIN(m,mold)
+          reallocate_a2_Obs(i,j) = copy(array(i,j))
+       END DO
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_a2_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds multinormal deviates to the observation. The mean relative
+  !! to the original coordinates and the (optional) covariance matrix
+  !! should be given in radians for the angular space coordinates, AUs
+  !! for distance, radians per day for angular velocities and AUs per
+  !! day for line-of-sight velocity. Note that the covariance matrix
+  !! for the observational uncertainties is not correctly updated if
+  !! the original observation has a non-zero covariance matrix.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addMultinormalDeviate_Obs(this, mean, covariance)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout)    :: this
+    REAL(bp), DIMENSION(6), INTENT(in)   :: mean
+    REAL(bp), DIMENSION(6,6), INTENT(in) :: covariance
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / addMultinormalDeviate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    this%covariance = covariance
+    CALL addMultinormalDeviate(this%obs_scoord, mean, this%covariance)
+    IF (error) THEN
+       CALL errorMessage("Observation / addMultinormalDeviate", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE addMultinormalDeviate_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds uniform deviates to the observation. The center relative to
+  !! the original coordinates and the absolute values of the boundary
+  !! values ((i,1)=center, (i,2)=abs(boundary), position i=1:3 and
+  !! velocity i=4:6) should be given in radians for the angular space
+  !! coordinates, AUs for distance, radians per day for angular
+  !! velocities and AUs per day for line-of-sight velocity. Note that
+  !! the covariance matrix for the observational uncertainties is not
+  !! updated.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addUniformDeviate_Obs(this, center_and_absbound)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout)    :: this
+    REAL(bp), DIMENSION(6,2), INTENT(in) :: center_and_absbound
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / addUniformDeviate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL addUniformDeviate(this%obs_scoord, center_and_absbound)
+    IF (error) THEN
+       CALL errorMessage("Observation / addUniformDeviate", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE addUniformDeviate_Obs
+
+
+
+
+
+  LOGICAL FUNCTION equal_Obs(this, that)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (Observation), INTENT(in) :: that
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / equal", &
+            "1st object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / equal", &
+            "2nd object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Designation:
+    IF (.NOT.(this%designation == that%designation)) THEN
+       equal_Obs = .FALSE.
+       RETURN
+    END IF
+
+    ! Epoch and coordinates:
+    IF (.NOT.equal(this%obs_scoord,that%obs_scoord)) THEN
+       equal_Obs = .FALSE.
+       RETURN
+    END IF
+
+    ! Observatory
+    IF (.NOT.equal(this%obsy,that%obsy)) THEN
+       equal_Obs = .FALSE.
+       RETURN
+    END IF
+
+    ! Assuming that all of the above comparisons are true,
+    ! it can be concluded that the two objects are the same:
+    equal_Obs = .TRUE.
+
+  END FUNCTION equal_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the code of the observatory where the observation was
+  !! made.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=OBSY_CODE_LEN) FUNCTION getCode_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObsCode", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getCode_Obs = getCode(this%obsy)
+
+  END FUNCTION getCode_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  FUNCTION getCovarianceMatrix_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    REAL(bp), DIMENSION(6,6)       :: getCovarianceMatrix_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getCovarianceMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getCovarianceMatrix_Obs = this%covariance
+
+  END FUNCTION getCovarianceMatrix_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns Declination [rad].
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getDec_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getDec", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getDec_Obs = getLatitude(this%obs_scoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / getDec", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getDec_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns designation of this object.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=DESIGNATION_LEN) FUNCTION getDesignation_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getDesignation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getDesignation_Obs = TRIM(this%designation)
+
+  END FUNCTION getDesignation_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns filter.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=2) FUNCTION getFilter(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getFilter", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getFilter = this%filter
+
+  END FUNCTION getFilter
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the ID (number or designation) for an single object object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getID_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    CHARACTER(len=DESIGNATION_LEN) :: getID_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getID", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%number == 0) THEN
+       getID_Obs = this%designation
+    ELSE
+       CALL toString(this%number, getID_Obs, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getID", &
+               "Could not convert integer to string.", 1)
+          RETURN
+       END IF
+    END IF
+
+  END FUNCTION getID_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns magnitude [mag].
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getMagnitude(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getMagnitude", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getMagnitude = this%mag
+
+  END FUNCTION getMagnitude
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns magnitude uncertainty [mag].
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getMagnitudeUncertainty(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getMagnitudeUncertainty", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getMagnitudeUncertainty = this%mag_unc
+
+  END FUNCTION getMagnitudeUncertainty
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns number of the asteroid corresponding to this object. If
+  !! the asteroid is unnumbered, the function returns the default
+  !! value (usually 0).
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION getNumber_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getNumber", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getNumber_Obs = this%number
+
+  END FUNCTION getNumber_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the observation records as character strings of a given
+  !! format (old and new MPC, Bowell) containing the data of this
+  !! object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservationRecords(this, frmt, number) RESULT(records)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in)                       :: this
+    CHARACTER(len=*), INTENT(in)                         :: frmt
+    INTEGER, INTENT(in), OPTIONAL                        :: number
+    CHARACTER(len=OBS_RECORD_LEN), DIMENSION(:), POINTER :: records
+
+    TYPE (Time)                       :: t
+    TYPE (CartesianCoordinates)       :: ccoord
+    CHARACTER(len=DESIGNATION_LEN)    :: designation, secret_name
+    CHARACTER(len=12)                 :: day_str
+    CHARACTER(len=9)                  :: ra_unc, dec_unc
+    CHARACTER(len=7)                  :: number_str
+    CHARACTER(len=6)                  :: s_str, mag_str
+    CHARACTER(len=5)                  :: as_str
+    CHARACTER(len=4)                  :: obsy_code
+    CHARACTER(len=2)                  :: month_str, h_str, m_str, deg_str, am_str, filter_
+    CHARACTER(len=1)                  :: discovery, sign_dec, sign_x, sign_y, sign_z
+    REAL(bp), DIMENSION(6)            :: coord
+    REAL(bp)                          :: day, ra, s, dec, as, correlation
+    INTEGER(ihp)                      :: day_integer
+    INTEGER                           :: number_, err, year, month, h, m, &
+         deg, am, n, i, indx
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservationRecords", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    t = getTime(this)
+    IF (error) THEN
+       CALL errorMessage("Observation / getObservationRecords", &
+            "TRACE BACK (1)", 1)
+       RETURN       
+    END IF
+    ra = getRA(this)
+    IF (error) THEN
+       CALL errorMessage("Observation / getObservationRecords", &
+            "TRACE BACK (2)", 1)
+       RETURN       
+    END IF
+    dec = getDec(this)
+    IF (error) THEN
+       CALL errorMessage("Observation / getObservationRecords", &
+            "TRACE BACK (3)", 1)
+       RETURN       
+    END IF
+    obsy_code = getCode(this%obsy)
+    IF (error) THEN
+       CALL errorMessage("Observation / getObservationRecords", &
+            "TRACE BACK (4)", 1)
+       RETURN       
+    END IF
+
+    IF (TRIM(frmt) /= "des") THEN
+
+       IF (PRESENT(number)) THEN
+          number_ = number
+       ELSE
+          number_ = this%number
+       END IF
+       IF (this%discovery) THEN
+          discovery = "*"
+       ELSE
+          discovery = " "
+       END IF
+       ! The timescale used by MPC prior to year 1972 is UT1 and since
+       ! then UTC has been used. The maximum difference between UT1 and 
+       ! UTC is 0.9 seconds.
+       CALL getCalendarDate(t, "TT", year, month, day)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "TRACE BACK (5)", 1)
+          RETURN       
+       END IF
+       IF (year >= 1972) THEN
+          CALL getCalendarDate(t, "UTC", year, month, day)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "TRACE BACK (10)", 1)
+             RETURN
+          END IF
+       ELSE
+          CALL getCalendarDate(t, "UT1", year, month, day)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "TRACE BACK (15)", 1)
+             RETURN       
+          END IF
+       END IF
+       CALL toString(month, month_str, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not convert month to string.", 1)
+          WRITE(stderr,*) year, month, day, getMJD(t,"utc")
+          RETURN
+       END IF
+       IF (month < 10) THEN
+          month_str = "0" // TRIM(month_str)
+       END IF
+       CALL radiansToHMS(ra, h, m, s)
+       IF (ABS(60.0_bp-s) < 0.00001) THEN
+          m = m + 1
+          s = 0.0_bp
+       END IF
+       IF (m == 60) THEN
+          m = 0
+          h = h + 1
+       END IF
+       IF (h == 24) THEN
+          h = 0
+       END IF
+       CALL radiansToDAMAS(ABS(dec), deg, am, as)
+       IF (ABS(60.0_bp-as) < 0.00001) THEN
+          am = am + 1
+          as = 0.0_bp
+       END IF
+       IF (am == 60) THEN
+          am = 0
+          deg = deg + 1
+       END IF
+       IF (dec >= 0.0_bp) THEN
+          sign_dec = "+"
+       ELSE
+          sign_dec = "-"
+       END IF
+       CALL toString(h, h_str, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (5).", 1)
+          RETURN       
+       END IF
+       IF (h < 10) h_str = "0" // TRIM(h_str)
+       CALL toString(m, m_str, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (10).", 1)
+          RETURN       
+       END IF
+       IF (m < 10) m_str = "0" // TRIM(m_str)
+       CALL toString(s, s_str, error, frmt="(F6.3)")
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (15).", 1)
+          RETURN       
+       END IF
+       IF (s < 10.0_bp) s_str = "0" // TRIM(s_str)
+       CALL toString(deg, deg_str, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (20).", 1)
+          RETURN       
+       END IF
+       IF (deg < 10) deg_str = "0" // TRIM(deg_str)
+       CALL toString(am, am_str, error)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (25).", 1)
+          RETURN       
+       END IF
+       IF (am < 10) am_str = "0" // TRIM(am_str)
+       CALL toString(as, as_str, error, frmt="(F5.2)")
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (30).", 1)
+          RETURN       
+       END IF
+       IF (as < 10.0_bp) as_str = "0" // TRIM(as_str)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Conversion error (35).", 1)
+          RETURN       
+       END IF
+       IF (this%mag < 99.0_bp) THEN
+          CALL toString(this%mag, mag_str, error, frmt="(F6.3)")
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Conversion error (40).", 1)
+             RETURN
+          END IF
+          IF (this%mag < 10.0_bp) mag_str = " " // TRIM(mag_str)
+       ELSE
+          mag_str = " "
+       END IF
+
+    END IF
+
+    ALLOCATE(records(5))
+    records = " "
+    SELECT CASE (TRIM(frmt))
+
+    CASE ("mpc","sor")
+
+       IF (number_ == 0) THEN
+          number_str(1:5) = "     "
+       ELSE
+          CALL toString(number_, number_str, error)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert number to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          DO WHILE (LEN_TRIM(number_str) < 5)
+             number_str = "0" // TRIM(number_str)
+          END DO
+       END IF
+       n = LEN_TRIM(this%designation)
+       IF (n <= 7) THEN
+          designation = this%designation
+       ELSE
+          designation = this%designation
+          CALL MPC3DesToMPCDes(designation)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "TRACE BACK (20)", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+       END IF
+       day_integer = NINT(day*10_ihp**6,kind=ihp)
+       day = day_integer/10.0_bp**6
+       CALL toString(day, day_str, error, frmt="(F12.9)")
+       IF (day < 10.0_bp) day_str = "0" // TRIM(day_str)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not convert day to string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       err = 0
+       WRITE(records(1),"(A5,A7,3A1,I4,1X,A2,1X,A8,1X,A2,1X,A2,1X,A6," // &
+            "A1,A2,1X,A2,1X,A5,9X,A5,A2,5X,A3)", iostat=err) number_str(1:5), &
+            designation(1:7), discovery, this%note1, this%note2, year, &
+            month_str, day_str(1:8), h_str, m_str, s_str, sign_dec, &
+            deg_str, am_str, as_str, mag_str(1:5), this%filter, obsy_code
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       SELECT CASE (this%note2)
+       CASE ("S") ! Satellite-based observation
+          ccoord = copy(this%satellite_ccoord)
+          CALL rotateToEquatorial(ccoord)
+          coord = getCoordinates(ccoord)
+          IF (coord(1) >= 0.0_bp) THEN
+             sign_x = "+"
+          ELSE
+             sign_x = "-"
+          END IF
+          IF (coord(2) >= 0.0_bp) THEN
+             sign_y = "+"
+          ELSE
+             sign_y = "-"
+          END IF
+          IF (coord(3) >= 0.0_bp) THEN
+             sign_z = "+"
+          ELSE
+             sign_z = "-"
+          END IF
+          SELECT CASE (this%coord_unit)
+          CASE (1)
+             coord(1:3) = coord(1:3)*km_au
+             coord = ABS(coord)
+             WRITE(records(2),"(A5,A7,3A1,I4,1X,A2,1X,A8,1X,I1,3(1X,A1,F10.4)," // &
+                  "8X,A3)", iostat=err) number_str(1:5), designation(1:7), " ", &
+                  this%note1, "s", year, month_str, day_str(1:8), &
+                  this%coord_unit, sign_x, coord(1), sign_y, coord(2), &
+                  sign_z, coord(3), obsy_code
+          CASE (2)
+             coord = ABS(coord)
+             WRITE(records(2), &
+                  "(A5,A7,3A1,I4,1X,A2,1X,A8,1X,I1,3(1X,A1,F10.8),8X,A3)",iostat=err) &
+                  number_str(1:5), designation(1:7), " ", &
+                  this%note1, "s", year, month_str, day_str(1:8), &
+                  this%coord_unit, sign_x, coord(1), sign_y, coord(2), sign_z, coord(3), obsy_code
+          CASE default
+             error = .TRUE.
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Unit type not available.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END SELECT
+          records => reallocate(records,2)
+       CASE default
+          records => reallocate(records,1)
+       END SELECT
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+
+    CASE ("mpc2")
+
+       DO WHILE (LEN_TRIM(obsy_code) < 4)
+          obsy_code = "0" // TRIM(obsy_code)
+       END DO
+
+       IF (number_ == 0) THEN
+          number_str(1:7) = "       "
+       ELSE
+          CALL toString(number_, number_str, error)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert number to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          DO WHILE (LEN_TRIM(number_str) < 7)
+             number_str = "0" // TRIM(number_str)
+          END DO
+       END IF
+       n = LEN_TRIM(this%designation)
+       IF (n <= 9) THEN
+          designation = this%designation
+       ELSE
+          designation = this%designation(n-8:n)
+       END IF
+       day_integer = NINT(day*10_ihp**9_ihp,kind=ihp)
+       day = day_integer/10.0_bp**9.0_bp
+       CALL toString(day, day_str, error, frmt="(F12.9)")
+       IF (day < 10.0_bp) day_str = "0" // TRIM(day_str)
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not convert day to string (10).", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       IF (SQRT(this%covariance(2,2))*SQRT(this%covariance(3,3)) > EPSILON(correlation)) THEN
+          correlation = this%covariance(2,3) / &
+               (SQRT(this%covariance(2,2))*SQRT(this%covariance(3,3)))
+       ELSE
+          correlation = 0.0_bp
+       END IF
+       ! Optical:
+       IF (SQRT(this%covariance(2,2))/rad_asec > 0.01_bp .AND. &
+            SQRT(this%covariance(3,3))/rad_asec > 0.01_bp) THEN
+          WRITE(records(1),"(A7,A9,3A1,I4,1X,A2,1X,A12,1X,A2,1X,A2,1X,A6," // &
+               "3X,A1,A2,1X,A2,1X,A5,4X,A6,A2,A1,1X,A3,A1,A12,1X,A12," // & 
+               "1X,A12,A1,2A4)", iostat=err) number_str(1:7), designation(1:9), "1", &
+               discovery, this%note2, year, month_str, day_str, h_str, m_str, &
+               s_str, sign_dec, deg_str, am_str, as_str, mag_str, this%filter, &
+               " ", "   ", " ", "            ", "            ", "            ", &
+               " ", "    ", obsy_code
+
+          ! Optical (assumes zero-correlation and error estimates):
+          WRITE(records(2),"(A7,A9,3A1,I4,1X,A2,1X,A12,1X,F6.3,1X,F6.3,3X," // &
+               "F8.5,A1,A7,F12.10,F5.3,A4,A4,F5.1,I1,3X,A1,2A8,A1,2A4)", iostat=err) &
+               number_str(1:7), designation(1:9), "2", " ", this%note2, year, month_str, day_str, &
+               SQRT(this%covariance(2,2))/rad_asec, &
+               SQRT(this%covariance(3,3))/rad_asec, &
+               correlation, "X", "       ", 0.0_bp, 0.0_bp, "    ", "    ", 0.0_bp, 0, &
+               " ", "        ", "        ", " ", "    ", obsy_code
+       ELSE
+          WRITE(records(1),"(A7,A9,3A1,I4,1X,A2,1X,A12,1X,F14.12,1X," // &
+               "A1,F14.12,1X,A6,A2,A1,1X,A3,A1,A12,1X,A12," // & 
+               "1X,A12,A1,2A4)", iostat=err) number_str(1:7), designation(1:9), "1", &
+               discovery, this%note2, year, month_str, day_str, ra,  &
+               sign_dec, ABS(dec), mag_str, this%filter, &
+               " ", "   ", " ", "            ", "            ", "            ", &
+               " ", "    ", obsy_code
+          CALL toString(SQRT(this%covariance(2,2))*10000000, ra_unc, error, frmt="(F9.7)")
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert RA uncertainty to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          ra_unc(2:8) = ra_unc(3:9)
+          IF (ra_unc == "00000000") THEN
+             ra_unc = " "
+             ra_unc(1:1) = "0"
+          ELSE
+             DO i=1,8
+                IF (ra_unc(i:i) /= "0") THEN
+                   indx = i
+                   EXIT
+                END IF
+             END DO
+             ra_unc(indx+2:8) = " "
+          END IF
+          CALL toString(SQRT(this%covariance(3,3))*10000000, dec_unc, error, frmt="(F9.7)")
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert Dec uncertainty to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          dec_unc(2:8) = dec_unc(3:9)
+          IF (dec_unc == "00000000") THEN
+             dec_unc = " "
+             dec_unc(1:1) = "0"
+          ELSE
+             DO i=1,8
+                IF (dec_unc(i:i) /= "0") THEN
+                   indx = i
+                   EXIT
+                END IF
+             END DO
+             dec_unc(indx+2:8) = " "
+          END IF
+          ! Optical (assumes zero-correlation and error estimates):
+          WRITE(records(2),"(A7,A9,3A1,I4,1X,A2,1X,A12,1X,A8,A8," // &
+               "F8.5,A1,A7,F12.10,F5.3,A4,A4,F5.1,I1,3X,A1,2A8,A1,2A4)", iostat=err) &
+               number_str(1:7), designation(1:9), "2", " ", this%note2, &
+               year, month_str, day_str, ra_unc(1:8), dec_unc(1:8), correlation, "X", &
+               "       ", 0.0_bp, 0.0_bp, "    ", "    ", 0.0_bp, 0, &
+               " ", "        ", "        ", " ", "    ", obsy_code
+       END IF
+
+       SELECT CASE (this%note2)
+       CASE ("S") ! Satellite-based observation
+          records(3) = records(1)
+          records(3)(17:17) = "3"
+          ccoord = copy(this%satellite_ccoord)
+          CALL rotateToEquatorial(ccoord)
+          coord = getCoordinates(ccoord)
+          SELECT CASE (this%coord_unit)
+          CASE (1)
+             ! in km:
+             coord(1:3) = coord(1:3)*km_au
+             WRITE(records(3)(41:123),"(A,3(F18.12))", iostat=err) "0", coord(1:3)
+          CASE (2)
+             ! in AU:
+             WRITE(records(3)(41:123),"(A,3(F18.12))", iostat=err) "1", coord(1:3)
+          CASE default
+             error = .TRUE.
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Unit type not available.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END SELECT
+          records(3)(18:18) = "+"
+          records => reallocate(records,3)
+       CASE default
+          records(2)(18:18) = "+"
+          records => reallocate(records,2)
+       END SELECT
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+
+    CASE ("mpc3")
+
+       DO WHILE (LEN_TRIM(obsy_code) < 4)
+          obsy_code = "0" // TRIM(obsy_code)
+       END DO
+
+       IF (number_ == 0) THEN
+          number_str(1:7) = "       "
+       ELSE
+          CALL toString(number_, number_str, error)
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert number to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          DO WHILE (LEN_TRIM(number_str) < 7)
+             number_str = "0" // TRIM(number_str)
+          END DO
+       END IF
+       designation = " "
+       n = LEN_TRIM(this%designation)
+       IF (simulated_observations) THEN
+          designation = this%designation
+       ELSE
+          IF (n == 9) THEN
+             designation = this%designation
+          ELSE IF (n < 9 .AND. n > 0) THEN
+             designation = this%designation
+             CALL MPCDesToMPC3Des(designation)
+          ELSE IF (n > 9) THEN
+             designation = this%designation(n-8:n)
+             number_str(1:6) = number_str(2:7)
+             number_str(7:7) = this%designation(n-9:n-9)
+          END IF
+       END IF
+       day_integer = NINT(day*10_ihp**9_ihp,kind=ihp)
+       day = day_integer/10.0_bp**9.0_bp
+       CALL toString(day, day_str, error, frmt="(F12.9)")
+       IF (error) THEN
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not convert day to string (10).", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       IF (day < 10.0_bp) THEN
+          day_str = "0" // TRIM(day_str)
+       END IF
+       IF (SQRT(this%covariance(2,2))*SQRT(this%covariance(3,3)) > EPSILON(correlation)) THEN
+          correlation = this%covariance(2,3) / &
+               (SQRT(this%covariance(2,2))*SQRT(this%covariance(3,3)))
+       ELSE
+          correlation = 0.0_bp
+       END IF
+       ! Optical:
+       IF (SQRT(this%covariance(2,2))/rad_asec > 0.01_bp .AND. &
+            SQRT(this%covariance(3,3))/rad_asec > 0.01_bp) THEN
+          WRITE(records(1),"(A7,A9,2X,3A1,I4,A2,A12,1X,A2,1X,A2,1X,A6," // &
+               "3X,A1,A2,1X,A2,1X,A5,4X,A6,A2,A1,1X,A3,A1,A12,1X,A12," // & 
+               "1X,A12,A1,2A4)", iostat=err) number_str(1:7), designation(1:9), "1", &
+               discovery, this%note2, year, month_str, day_str, h_str, m_str, &
+               s_str, sign_dec, deg_str, am_str, as_str, mag_str, this%filter, &
+               " ", "   ", " ", "            ", "            ", "            ", &
+               " ", "    ", obsy_code
+
+          ! Optical (assumes zero-correlation and error estimates):
+          WRITE(records(2),"(A7,A9,2X,3A1,I4,A2,A12,1X,F6.3,1X,F6.3,3X," // &
+               "F8.5,A1,A7,F12.10,F5.3,A4,A4,F5.1,I1,3X,A1,2A8,A1,2A4)", iostat=err) &
+               number_str(1:7), designation(1:9), "2", " ", this%note2, &
+               year, month_str, day_str, &
+               SQRT(this%covariance(2,2))/rad_asec, &
+               SQRT(this%covariance(3,3))/rad_asec, &
+               correlation, "X", "       ", 0.0_bp, 0.0_bp, "    ", "    ", 0.0_bp, 0, &
+               " ", "        ", "        ", " ", "    ", obsy_code
+       ELSE
+          WRITE(records(1),"(A7,A9,2X,3A1,I4,A2,A12,1X,F14.12,1X," // &
+               "A1,F14.12,1X,A6,A2,A1,1X,A3,A1,A12,1X,A12," // & 
+               "1X,A12,A1,2A4)", iostat=err) number_str(1:7), &
+               designation(1:9), "1", discovery, this%note2, year, month_str, &
+               day_str, ra, sign_dec, ABS(dec), mag_str, this%filter, &
+               " ", "   ", " ", "            ", "            ", &
+               "            ", " ", "    ", obsy_code
+          CALL toString(SQRT(this%covariance(2,2))*10000000, ra_unc, error, frmt="(F9.7)")
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert RA uncertainty to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          ra_unc(2:8) = ra_unc(3:9)
+          IF (ra_unc == "00000000") THEN
+             ra_unc = " "
+             ra_unc(1:1) = "0"
+          ELSE
+             DO i=1,8
+                IF (ra_unc(i:i) /= "0") THEN
+                   indx = i
+                   EXIT
+                END IF
+             END DO
+             ra_unc(indx+2:8) = " "
+          END IF
+          CALL toString(SQRT(this%covariance(3,3))*10000000, dec_unc, error, frmt="(F9.7)")
+          IF (error) THEN
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Could not convert Dec uncertainty to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+          dec_unc(2:8) = dec_unc(3:9)
+          IF (dec_unc == "00000000") THEN
+             dec_unc = " "
+             dec_unc(1:1) = "0"
+          ELSE
+             DO i=1,8
+                IF (dec_unc(i:i) /= "0") THEN
+                   indx = i
+                   EXIT
+                END IF
+             END DO
+             dec_unc(indx+2:8) = " "
+          END IF
+          ! Optical (assumes zero-correlation and error estimates):
+          WRITE(records(2),"(A7,A9,2X,3A1,I4,A2,A12,1X,A8,A8," // &
+               "F8.5,A1,A7,F12.10,F5.3,A4,A4,F5.1,I1,3X,A1,2A8,A1,2A4)", &
+               iostat=err) number_str(1:7), designation(1:9), "2", &
+               " ", this%note2, year, month_str, day_str, ra_unc(1:8), &
+               dec_unc(1:8), correlation, "X", "       ", 0.0_bp, 0.0_bp, &
+               "    ", "    ", 0.0_bp, 0, " ", "        ", "        ", &
+               " ", "    ", obsy_code
+       END IF
+
+       SELECT CASE (this%note2)
+       CASE ("S") ! Satellite-based observation
+          records(3) = records(1)
+          records(3)(19:19) = "3"
+          ccoord = copy(this%satellite_ccoord)
+          CALL rotateToEquatorial(ccoord)
+          coord = getCoordinates(ccoord)
+          SELECT CASE (this%coord_unit)
+          CASE (1)
+             ! in km:
+             coord(1:3) = coord(1:3)*km_au
+             WRITE(records(3)(41:123),"(A,3(F18.12))", iostat=err) "0", coord(1:3)
+          CASE (2)
+             ! in AU:
+             WRITE(records(3)(41:123),"(A,3(F18.12))", iostat=err) "1", coord(1:3)
+          CASE default
+             error = .TRUE.
+             CALL errorMessage("Observation / getObservationRecords", &
+                  "Unit type not available.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END SELECT
+          records(3)(20:20) = "+"
+          records => reallocate(records,3)
+       CASE default
+          records(2)(20:20) = "+"
+          records => reallocate(records,2)
+       END SELECT
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+
+    CASE ("elgb")
+
+       IF (number_ == 0) THEN
+          n = LEN_TRIM(this%designation)
+          IF (n <= 8) THEN
+             designation = this%designation
+          ELSE
+             designation = this%designation(n-7:n)
+          END IF
+       ELSE
+          CALL toString(number_, designation, error)
+          IF (error) THEN
+             CALL errorMessage("Observation / getELGBString", &
+                  "Could not convert number to string.", 1)
+             DEALLOCATE(records, stat=err)
+             RETURN
+          END IF
+       END IF
+
+       err = 0
+       WRITE(records(1),"(I4,1X,A2,2X,A8,2X,A2,1X,A2,1X,A6,2X,A1,A2," // &
+            "1X,A2,1X,A5,2X,A4,A1,1X,A8,A1,1X,A3,2X,A1,A6)",iostat=err) &
+            year, month_str, day_str(1:8), h_str, m_str, s_str, sign_dec, &
+            deg_str, am_str, as_str, mag_str(1:4), TRIM(this%filter), &
+            designation(1:8), discovery, obsy_code, this%note2, "      "
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getELGBString", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       records => reallocate(records,1)
+
+    CASE ("des")
+
+       filter_ = this%filter
+       IF (LEN_TRIM(filter_) == 0) THEN
+          filter_ = "X"
+       END IF
+       IF (LEN_TRIM(this%secret_name) == 0) THEN
+          secret_name = "X"
+       ELSE
+          secret_name = this%secret_name
+       END IF
+       IF (this%number /= 0) THEN
+          WRITE(records(1),"(I0,1X,F16.10,1X,A,3(1X,F14.10)," // &
+               "2(1X,A),2(1X,F14.10),1X,F14.10,1X,E14.7,1X,A)", iostat=err) & 
+               this%number, getMJD(t, "UTC"), "O", &
+               ra/rad_deg, dec/rad_deg, this%mag, filter_, &
+               TRIM(obsy_code), SQRT(this%covariance(2,2))/rad_asec, &
+               SQRT(this%covariance(3,3))/rad_asec, this%mag_unc, &
+               this%s2n, TRIM(secret_name) 
+       ELSE IF (LEN_TRIM(this%designation) /= 0) THEN
+          WRITE(records(1),"(A,1X,F16.10,1X,A,3(1X,F14.10)," // &
+               "2(1X,A),2(1X,F14.10),1X,F14.10,1X,E14.7,1X,A)", iostat=err) & 
+               TRIM(this%designation), getMJD(t, "UTC"), "O", &
+               ra/rad_deg, dec/rad_deg, this%mag, filter_, &
+               TRIM(obsy_code), SQRT(this%covariance(2,2))/rad_asec, &
+               SQRT(this%covariance(3,3))/rad_asec, this%mag_unc, &
+               this%s2n, TRIM(secret_name) 
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords / des", &
+               "Number and designation missing for this record.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observation / getObservationRecords / des", &
+               "Could not write output string.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+       records => reallocate(records,1)
+
+    END SELECT
+
+  END FUNCTION getObservationRecords
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the observation mask to be used with the spherical
+  !! coordinates. Elements set to true corresponds to coordinates that
+  !! have been initialized.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservationMask_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    LOGICAL, DIMENSION(6)          :: getObservationMask_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservationMask", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservationMask_Obs = this%obs_mask
+
+  END FUNCTION getObservationMask_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the spherical observation coordinates (can be any, or
+  !! all, of rho, RA, Dec, drho/dt, dRA/dt, dDec/dt) and epoch of
+  !! this observation.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservationSCoord(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (SphericalCoordinates)    :: getObservationSCoord
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservationSCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservationSCoord = copy(this%obs_scoord)
+
+  END FUNCTION getObservationSCoord
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Observatory object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservatory_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (Observatory)             :: getObservatory_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservatory", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservatory_Obs = copy(this%obsy)
+
+  END FUNCTION getObservatory_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian heliocentric coordinates of the observatory 
+  !! at the epoch when the observation was made.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservatoryCCoord_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (CartesianCoordinates)    :: getObservatoryCCoord_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservatoryCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservatoryCCoord_Obs = copy(this%obsy_ccoord)
+
+  END FUNCTION getObservatoryCCoord_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the IAU designated observatory code for the observatory
+  !! where this particular observation was made.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=OBSY_CODE_LEN) FUNCTION getObservatoryCode_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getObservatoryCode", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservatoryCode_Obs = getCode(this%obsy)
+
+  END FUNCTION getObservatoryCode_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns Right Ascension [rad].
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getRA_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getRA", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getRA_Obs = getLongitude(this%obs_scoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / getRA", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getRA_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns solar elongation [rad].
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getSolarElongation(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+
+    TYPE (SphericalCoordinates) :: scoord
+    REAL(bp), DIMENSION(6) :: coord1, coord2
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getSolarElongation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    coord1 = getCoordinates(this%obs_scoord)
+    scoord = getSCoord(opposite(this%obsy_ccoord))
+    IF (getFrame(this%obs_scoord) == "equatorial") THEN
+       CALL rotateToEquatorial(scoord)
+    ELSE
+       CALL rotateToEcliptic(scoord)
+    END IF
+    coord2 = getCoordinates(scoord)
+    CALL NULLIFY(scoord)
+    getSolarElongation = angularDistance(coord1(2), coord1(3), &
+         coord2(2), coord2(3))
+
+  END FUNCTION getSolarElongation
+
+
+
+
+
+  !! *Description*:
+  !!
+  FUNCTION getStandardDeviations_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)         :: getStandardDeviations_Obs
+    INTEGER                        :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getStandardDeviations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,6
+       getStandardDeviations_Obs(i) = SQRT(this%covariance(i,i))
+    END DO
+    WHERE (.NOT.this%obs_mask)
+       getStandardDeviations_Obs = 0.0_bp
+    END WHERE
+
+  END FUNCTION getStandardDeviations_Obs
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns epoch as a Time object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTime_Obs(this)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(in) :: this
+    TYPE (Time)                    :: getTime_Obs
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / getTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getTime_Obs = getTime(this%obs_scoord)
+    IF (error) THEN
+       CALL errorMessage("Observation / getTime", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getTime_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  SUBROUTINE setCovarianceMatrix(this, covariance)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout)    :: this
+    REAL(bp), DIMENSION(6,6), INTENT(in) :: covariance
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / setCovarianceMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    this%covariance = covariance
+
+  END SUBROUTINE setCovarianceMatrix
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Set designation of object. The length of the designation
+  !! string must be smaller or equal to the DESIGNATION_LEN parameter.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setDesignation_Obs(this, designation)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout) :: this
+    CHARACTER(len=*), INTENT(in)      :: designation
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / setDesignation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (LEN_TRIM(designation) > DESIGNATION_LEN) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / setDesignation", &
+            "New designation too long.", 1)
+       RETURN
+    END IF
+
+    this%designation = TRIM(designation)
+
+  END SUBROUTINE setDesignation_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  SUBROUTINE setNumber_Obs(this, number)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout) :: this
+    INTEGER, INTENT(in)               :: number
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / setNumber", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    this%number = number
+
+  END SUBROUTINE setNumber_Obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Set the spherical observation coordinates (can be any, or
+  !! all, of rho, RA, Dec, drho/dt, dRA/dt, dDec/dt) and epoch of
+  !! this observation.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationSCoord(this, obs_scoord)
+
+    IMPLICIT NONE
+    TYPE (Observation), INTENT(inout)       :: this
+    TYPE (SphericalCoordinates), INTENT(in) :: obs_scoord
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observation / setObservationSCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL NULLIFY(this%obs_scoord)
+    this%obs_scoord = copy(obs_scoord)
+
+  END SUBROUTINE setObservationSCoord
+
+
+
+
+
+END MODULE Observation_cl
+
+
+
+
+
Index: trunk/mops/oorb/classes/Observations_class.f90
===================================================================
--- trunk/mops/oorb/classes/Observations_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Observations_class.f90	(revision 34646)
@@ -0,0 +1,5536 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!
+!! This class provides a datatype and routines for handling
+!! observations. Only optical astrometric observations given in the
+!! old and new <a
+!! href="http://cfa-www.harvard.edu/iau/info/OpticalObs.html">MPC</a>
+!! formats, the Data Exchange Standard (DES) format, the Lowell
+!! format, and the preliminary GAIA formats are supported for the time
+!! being. Besides the observations file, indirectly this class also
+!! needs a file containing codes and coordinates for observatories
+!! (usually OBSCODE.dat).
+!!  
+!! *Example*: 
+!!  
+!! <pre> 
+!! use Base_cl 
+!! use Observations_cl 
+!! implicit none 
+!! type (Observations) :: obss 
+!! type (File) :: myfile 
+!! .  
+!! .  
+!! .  
+!! call new(myfile,"myfilen.ame") 
+!! call open(myfile) 
+!! call new(obss,myfile) 
+!! if (error) stop 
+!! call nullify(obss) 
+!! </pre> 
+!!  
+!! @see StochasticOrbit_class 
+!!  
+!! @author  MG, JV 
+!! @version 2011-08-18
+!!  
+MODULE Observations_cl
+
+  USE Base_cl
+  USE File_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  USE CartesianCoordinates_cl
+  USE Observation_cl
+  USE Observatories_cl
+  USE Orbit_cl
+
+  USE utilities
+  USE sort
+  USE linal
+  !$ use omp_lib
+
+  IMPLICIT NONE
+  PRIVATE :: NEW_Obss
+  PRIVATE :: NEW_Obss_file
+  PRIVATE :: NEW_Obss_obs
+  PRIVATE :: NEW_Obss_obs_arr
+  PRIVATE :: NULLIFY_Obss
+  PRIVATE :: copy_Obss
+  PRIVATE :: exist_Obss
+  PRIVATE :: addMultinormalDeviates_Obss
+  PRIVATE :: addUniformDeviates_Obss
+  PRIVATE :: addition_Obss
+  PRIVATE :: setDesignation_Obss
+  PRIVATE :: clean_Obss
+  PRIVATE :: getNumber_Obss
+  PRIVATE :: getDeclinations_Obss
+  PRIVATE :: setNumber_Obss
+  PRIVATE :: sortObservations
+  PRIVATE :: getDates_Obss
+  PRIVATE :: getMinAndMaxValues_Obss
+  PRIVATE :: getObservationMasks_Obss
+  PRIVATE :: getObservatoryCodes_Obss
+  PRIVATE :: getStandardDeviations_Obss
+  !  PRIVATE :: readGaiaFile
+  PRIVATE :: reallocate_a1_Obss
+
+  TYPE Observations
+     PRIVATE
+     !! Observations.
+     TYPE (Observation), DIMENSION(:), POINTER :: obs_arr => NULL()
+     !! Different objects in this Observations object.
+     CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER  :: objects => NULL()
+     !! Sorting criteria (epochs as tdt and mjd).
+     REAL(bp), DIMENSION(:), POINTER           :: criteria => NULL()  
+     !! Index vector which puts the observations in ascending order.
+     INTEGER, DIMENSION(:), POINTER            :: ind => NULL()  
+     !! Number of observations.
+     INTEGER                                   :: nobs = 0
+     !! Number of different objects in this Observations object.
+     INTEGER                                   :: nobjects = 0
+     !! If _true_, then this object has been initialized.
+     LOGICAL                                   :: is_initialized = .FALSE.
+     !! Place for additional information related to observations,
+     !! E.g., notes from observation file: additional mask + obs.pair flags
+     CHARACTER(len=4), DIMENSION(:), POINTER   :: obs_note_arr => NULL()
+  END TYPE Observations
+
+  !! Initializes an Observations-object.
+  INTERFACE NEW
+     MODULE PROCEDURE NEW_Obss
+     MODULE PROCEDURE NEW_Obss_file
+     MODULE PROCEDURE NEW_Obss_obs
+     MODULE PROCEDURE NEW_Obss_obs_arr
+  END INTERFACE NEW
+
+  !! Nullifies an Observations-object.
+  INTERFACE NULLIFY
+     MODULE PROCEDURE NULLIFY_Obss
+  END INTERFACE NULLIFY
+
+  !! Makes a copy of an Observations-object:
+  INTERFACE copy
+     MODULE PROCEDURE copy_Obss
+  END INTERFACE copy
+
+  !! Returns state of an Observations-object:
+  INTERFACE exist
+     MODULE PROCEDURE exist_Obss
+  END INTERFACE exist
+
+  !! Adds Gaussian noise to the observations. 
+  INTERFACE addMultinormalDeviates
+     MODULE PROCEDURE addMultinormalDeviates_Obss
+  END INTERFACE addMultinormalDeviates
+
+  !! Adds uniform noise to the observations. 
+  INTERFACE addUniformDeviates
+     MODULE PROCEDURE addUniformDeviates_Obss
+  END INTERFACE addUniformDeviates
+
+  !! Returns MJDs in UTC for all observations in this object.
+  INTERFACE getDates
+     MODULE PROCEDURE getDates_Obss
+  END INTERFACE getDates
+
+  !! Returns the declinations of all observations in this object.
+  INTERFACE getDeclinations
+     MODULE PROCEDURE getDeclinations_Obss
+  END INTERFACE getDeclinations
+
+  !! Changes the designation for all observations in this object.
+  INTERFACE getDesignation
+     MODULE PROCEDURE getDesignation_Obss
+  END INTERFACE getDesignation
+
+  !! Changes the designation for all observations in this object.
+  INTERFACE setDesignation
+     MODULE PROCEDURE setDesignation_Obss
+  END INTERFACE setDesignation
+
+  !! Removes multiple observations from this object:
+  INTERFACE clean
+     MODULE PROCEDURE clean_Obss
+  END INTERFACE clean
+
+  INTERFACE getID
+     MODULE PROCEDURE getID_Obss
+  END INTERFACE getID
+
+  !! Gets the end (read documentation) values of this object. 
+  INTERFACE getMinAndMaxValues
+     MODULE PROCEDURE getMinAndMaxValues_Obss
+  END INTERFACE getMinAndMaxValues
+
+  !! Returns the number of this object assuming that the set contains only one object.. 
+  INTERFACE getNumber
+     MODULE PROCEDURE getNumber_Obss
+  END INTERFACE getNumber
+
+  INTERFACE getObservationMasks
+     MODULE PROCEDURE getObservationMasks_Obss
+  END INTERFACE getObservationMasks
+
+  INTERFACE getObservatoryCodes
+     MODULE PROCEDURE getObservatoryCodes_Obss
+  END INTERFACE getObservatoryCodes
+
+  !! Returns an Observations-object containing the combined 
+  !! observations from two given Observations-objects.
+  INTERFACE OPERATOR (+) 
+     MODULE PROCEDURE addition_Obss
+  END INTERFACE OPERATOR (+)
+
+  INTERFACE getStandardDeviations
+     MODULE PROCEDURE getStandardDeviations_Obss
+  END INTERFACE getStandardDeviations
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_a1_Obss
+  END INTERFACE reallocate
+
+  INTERFACE setNumber
+     MODULE PROCEDURE setNumber_Obss
+  END INTERFACE setNumber
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new Observations instance with default values.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object already has been initialized or 
+  !!               something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! .
+  !! .
+  !! .
+  !! call new(obss)
+  !! </pre>
+  SUBROUTINE NEW_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%obs_arr => NULL()
+    this%objects => NULL()
+    this%criteria => NULL()
+    this%ind => NULL()
+    this%nobs = 0
+    this%nobjects = 0
+    this%obs_note_arr => NULL()
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE NEW_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new Observations instance. Reads the given 
+  !! observations file, transforms the dates to a Julian dates, 
+  !! target coordinates to radians and observatory codes to 
+  !! geocentric equatorial coordinates in AUs of the observatories.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object already has been initialized or 
+  !!               something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! type (File)         :: myfile
+  !! .
+  !! .
+  !! .
+  !! call new(myfile,"myfilen.ame")
+  !! call open(myfile)
+  !! call new(obss, myfile)
+  !! </pre>
+  !!
+  SUBROUTINE NEW_Obss_file(this, f1, stdev, orb_sim)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)           :: this
+    TYPE (File), INTENT(in)                      :: f1
+    REAL(bp), DIMENSION(6), OPTIONAL, INTENT(in) :: stdev
+    TYPE (Orbit), OPTIONAL, INTENT(inout)        :: orb_sim
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(stdev)) THEN
+       IF (PRESENT(orb_sim)) THEN
+          CALL readObservationFile(this, f1, stdev, orb_sim=orb_sim)
+       ELSE
+          CALL readObservationFile(this, f1, stdev)
+       END IF
+    ELSE
+       IF (PRESENT(orb_sim)) THEN
+          CALL readObservationFile(this, f1, orb_sim=orb_sim)
+       ELSE
+          CALL readObservationFile(this, f1)
+       END IF
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    ! Update number and names of different objects:
+    CALL sortObservations(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE NEW_Obss_file
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new Observations instance using the given
+  !! Observation object.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object already has been initialized or
+  !!               something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! type (Observation)  :: myobs
+  !! .
+  !! .
+  !! .
+  !! call new(obss, myobs)
+  !! </pre>
+  !!
+  SUBROUTINE NEW_Obss_obs(this, obs)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    TYPE (Observation), INTENT(in)     :: obs
+    TYPE (Time)                        :: t
+    CHARACTER(len=DESIGNATION_LEN)     :: str
+    INTEGER                            :: err, number
+
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%nobs = 1 
+    ALLOCATE(this%obs_arr(this%nobs), this%objects(this%nobs), &
+         this%criteria(this%nobs), this%ind(this%nobs), &
+         this%obs_note_arr(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    this%obs_arr(1) = copy(obs)
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (5)", 1)
+       CALL NULLIFY(this)
+       RETURN
+    END IF
+    this%nobjects = 1
+    IF (getNumber(obs) /= 0) THEN
+       number = getNumber(obs)
+       IF (error) THEN
+          CALL errorMessage("Observations / new", &
+               "TRACE BACK (10)", 1)
+          CALL NULLIFY(this)
+          RETURN
+       END IF
+       CALL toString(number, str, error)
+       IF (error) THEN
+          CALL errorMessage("Observations / new", &
+               "TRACE BACK (15)", 1)
+          CALL NULLIFY(this)
+          RETURN
+       END IF
+       DO WHILE (LEN_TRIM(str) < 7)
+          str = "0" // TRIM(str)
+       END DO
+       this%objects(this%nobjects) = TRIM(str)
+    ELSE
+       this%objects(this%nobjects) = getDesignation(obs)
+       IF (error) THEN
+          CALL errorMessage("Observations / new", &
+               "TRACE BACK (20)", 1)
+          CALL NULLIFY(this)
+          RETURN
+       END IF
+    END IF
+    t = getTime(obs)
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (25)", 1)
+       CALL NULLIFY(this)
+       RETURN
+    END IF
+    this%criteria(1) = getMJD(t, "tdt")
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (30)", 1)
+       CALL NULLIFY(this)
+       RETURN
+    END IF
+    this%ind(1) = 1
+    this%obs_note_arr = " "
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE NEW_Obss_obs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new Observations instance using the given
+  !! array of Observation objects.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object already has been initialized or
+  !!               something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! type (Observation), dimension(7) :: myobs_arr
+  !! .
+  !! .
+  !! .
+  !! call new(obss, myobs_arr)
+  !! </pre>
+  !!
+  SUBROUTINE NEW_Obss_obs_arr(this, obs_arr)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    TYPE (Observation), DIMENSION(:), INTENT(in) :: obs_arr
+    INTEGER                            :: err, i
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%nobs = SIZE(obs_arr,dim=1)
+    ALLOCATE(this%obs_arr(this%nobs), this%objects(this%nobs), &
+         this%criteria(this%nobs), this%ind(this%nobs), &
+         this%obs_note_arr(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Could not allocate memory.", 1)
+       CALL NULLIFY(this)
+       RETURN
+    END IF
+    DO i=1,this%nobs
+       this%obs_arr(i) = copy(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / new", &
+               "TRACE BACK (5)", 1)
+          CALL NULLIFY(this)
+          RETURN
+       END IF
+    END DO
+
+    ! Update number and names of different objects:
+    CALL sortObservations(this, force_full=.TRUE.)
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "TRACE BACK (10)", 1)
+       CALL NULLIFY(this)
+       RETURN
+    END IF
+    this%obs_note_arr = " "
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE NEW_Obss_obs_arr
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object, i.e. deallocates arrays and 
+  !! sets default values to parameters.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! .
+  !! .
+  !! .
+  !! call nullify(obss)
+  !! </pre>
+  SUBROUTINE NULLIFY_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    INTEGER :: i, err
+
+    IF (ASSOCIATED(this%obs_arr)) THEN
+       DO i=1,SIZE(this%obs_arr,dim=1)
+          CALL NULLIFY(this%obs_arr(i))
+       END DO
+       DEALLOCATE(this%obs_arr, stat=err)
+       IF (err /= 0) THEN
+          NULLIFY(this%obs_arr)
+       END IF
+    END IF
+    IF (ASSOCIATED(this%ind)) THEN 
+       DEALLOCATE(this%ind, stat=err)
+       IF (err /= 0) THEN
+          NULLIFY(this%ind)
+       END IF
+    END IF
+    IF (ASSOCIATED(this%criteria)) THEN
+       DEALLOCATE(this%criteria, stat=err)
+       IF (err /= 0) THEN
+          NULLIFY(this%criteria)
+       END IF
+    END IF
+    IF (ASSOCIATED(this%objects)) THEN
+       DEALLOCATE(this%objects, stat=err)
+       IF (err /= 0) THEN
+          NULLIFY(this%objects)
+       END IF
+    END IF
+    IF (ASSOCIATED(this%obs_note_arr)) THEN
+       DEALLOCATE(this%obs_note_arr, stat=err)
+       IF (err /= 0) THEN
+          NULLIFY(this%obs_note_arr)
+       END IF
+    END IF
+    this%nobjects =  0
+    this%nobs =  0
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE NULLIFY_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  !! Returns error if allocation fails.
+  !!
+  FUNCTION copy_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    TYPE (Observations)             :: copy_Obss
+    INTEGER                         :: i, err
+
+    copy_Obss%nobs = this%nobs
+    copy_Obss%nobjects = this%nobjects
+    IF (ASSOCIATED(this%obs_arr)) THEN
+       ALLOCATE(copy_Obss%obs_arr(this%nobs), &
+            copy_Obss%objects(this%nobjects), &
+            copy_Obss%ind(this%nobs), &
+            copy_Obss%criteria(this%nobs), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / copy", &
+               "Could not allocate memory (5).", 1)
+          CALL NULLIFY(copy_Obss)
+          RETURN
+       END IF
+       DO i=1,SIZE(this%obs_arr)
+          copy_Obss%obs_arr(i) = copy(this%obs_arr(i))
+          IF (error) THEN
+             CALL errorMessage("Observations / Observations", &
+                  "TRACE BACK", 1)
+             CALL NULLIFY(copy_Obss)
+             RETURN
+          END IF
+       END DO
+       copy_Obss%objects = this%objects
+       copy_Obss%ind = this%ind
+       copy_Obss%criteria = this%criteria
+    END IF
+    IF (ASSOCIATED(this%obs_note_arr)) THEN
+       ALLOCATE(copy_Obss%obs_note_arr(this%nobs), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / copy", &
+               "Could not allocate memory (10).", 1)
+          CALL NULLIFY(copy_Obss)
+          RETURN
+       END IF
+       copy_Obss%obs_note_arr = this%obs_note_arr
+    END IF
+    copy_Obss%is_initialized = this%is_initialized
+
+  END FUNCTION copy_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether it exists or not.
+  !!
+  LOGICAL FUNCTION exist_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+
+    exist_Obss = this%is_initialized
+
+  END FUNCTION exist_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds Gaussian deviates to the observations, optionally using a
+  !! mask. The new center relative to the original coordinates and the
+  !! covariance matrices should be given in radians for the angular
+  !! space coordinates, AUs for distance, radians per day for angular
+  !! velocities and AUs per day for line-of-sight velocity. If mask is
+  !! present, apply only for observations for which mask is true.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addMultinormalDeviates_Obss(this, mean_arr, covariance_arr, mask_arr)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)          :: this
+    REAL(bp), DIMENSION(:,:), INTENT(in)        :: mean_arr
+    REAL(bp), DIMENSION(:,:,:), INTENT(in)      :: covariance_arr
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: mask_arr
+    LOGICAL, DIMENSION(:), ALLOCATABLE          :: mask_arr_
+    INTEGER                                     :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addMultinormalDeviates", &
+            "Object has not been initialized.", 1)
+       RETURN       
+    END IF
+
+    IF (SIZE(this%obs_arr) /= SIZE(mean_arr,dim=1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addMultinormalDeviates", &
+            "Number of observations and length of mean_arr are not compatible.", 1)
+       RETURN
+    END IF
+    IF (SIZE(this%obs_arr) /= SIZE(covariance_arr,dim=1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addMultinormalDeviates", &
+            "Number of observations and length of covariance_arr are not compatible.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(mask_arr_(SIZE(this%obs_arr)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addMultinormalDeviate", &
+            "Could not allocate memory.", 1)
+       DEALLOCATE(mask_arr_, stat=err)
+       RETURN
+    END IF
+
+    IF (PRESENT(mask_arr)) THEN
+       IF (SIZE(this%obs_arr) /= SIZE(mask_arr,dim=1)) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / addMultinormalDeviates", &
+               "Number of observations and length of mask_arr are not compatible.", 1)
+          RETURN
+       END IF
+       mask_arr_ = mask_arr 
+    ELSE 
+       mask_arr_(:) = .TRUE.
+    END IF
+
+    DO i=1,SIZE(this%obs_arr)
+       IF (mask_arr_(i)) THEN
+          CALL addMultinormalDeviate(this%obs_arr(this%ind(i)), mean_arr(i,:), covariance_arr(i,:,:))
+          IF (error) THEN
+             CALL errorMessage("Observations / addMultinormalDeviate", &
+                  "TRACE BACK", 1)
+             DEALLOCATE(mask_arr_, stat=err)
+             RETURN
+          END IF
+       END IF
+    END DO
+
+    DEALLOCATE(mask_arr_, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addMultinormalDeviate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE addMultinormalDeviates_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds uniform deviates to the observations (i), optionally using a
+  !! mask. The center relative to the original state and the absolute
+  !! values of the boundary values ((i,j,1)=center,
+  !! (i,j,2)=abs(boundary), position j=1:3 and velocity j=4:6) should
+  !! be given in radians for the angular space coordinates, AUs for
+  !! distance, radians per day for angular velocities and AUs per day
+  !! for line-of-sight velocity.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addUniformDeviates_Obss(this, center_and_absbound_arr, mask_arr)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)          :: this
+    REAL(bp), DIMENSION(:,:,:), INTENT(in)      :: center_and_absbound_arr
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: mask_arr
+    LOGICAL, DIMENSION(:), ALLOCATABLE          :: mask_arr_
+    INTEGER                                     :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addUniformDeviates", &
+            "Object has not been initialized.", 1)
+       RETURN       
+    END IF
+    IF (SIZE(this%obs_arr) /= SIZE(center_and_absbound_arr,dim=1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addUniformDeviates", &
+            "Number of observations and length of center_and_absbound_arr are not compatible.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(mask_arr_(SIZE(this%obs_arr)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addUniformDeviates", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(mask_arr)) THEN
+       IF (SIZE(this%obs_arr) /= SIZE(mask_arr,dim=1)) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / addMultinormalDeviates", &
+               "Number of observations and length of mask_arr are not compatible.", 1)
+          RETURN
+       END IF
+       mask_arr_ = mask_arr 
+    ELSE 
+       mask_arr_(:) = .TRUE.
+    END IF
+
+    DO i=1,SIZE(this%obs_arr)
+       IF (mask_arr_(i)) THEN
+          CALL addUniformDeviate(this%obs_arr(this%ind(i)), center_and_absbound_arr(i,:,:))
+          IF (error) THEN
+             CALL errorMessage("Observations / addUniformDeviates", &
+                  "TRACE BACK", 1)
+             DEALLOCATE(mask_arr_, stat=err)
+             RETURN       
+          END IF
+       END IF
+    END DO
+
+    DEALLOCATE(mask_arr_, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addUniformDeviates", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE addUniformDeviates_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the sum of two objects, i.e. one object that contains all
+  !! observations from both original objects.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION addition_Obss(this, that)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    TYPE (Observations), INTENT(in) :: that
+    TYPE (Observations)             :: addition_Obss
+    INTEGER                         :: err, i
+
+    IF (.NOT. this%is_initialized) THEN
+       CALL errorMessage("Observations / + (addition)", &
+            "Left object has not been initialized.", 1)
+       CALL NULLIFY(addition_Obss)
+       RETURN       
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       CALL errorMessage("Observations / + (addition)", &
+            "Right object has not been initialized.", 1)
+       CALL NULLIFY(addition_Obss)
+       RETURN       
+    END IF
+
+    ! Add observations:
+    ALLOCATE(addition_Obss%obs_arr(this%nobs+that%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addition", &
+            "Could not allocate astrometric array.", 1)
+       CALL NULLIFY(addition_Obss)
+       RETURN
+    END IF
+    DO i=1, this%nobs
+       addition_Obss%obs_arr(i) = copy(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / addition", &
+               "TRACE BACK (5)", 1)
+          CALL NULLIFY(addition_Obss)
+          RETURN
+       END IF
+    END DO
+    DO i=1, that%nobs
+       addition_Obss%obs_arr(this%nobs+i) = copy(that%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / addition", &
+               "TRACE BACK (10)", 1)
+          CALL NULLIFY(addition_Obss)
+          RETURN
+       END IF
+    END DO
+
+    ! Use number of observations, and number and names 
+    ! of different objects corresponding to "this" as such:
+    addition_Obss%nobs = this%nobs
+    addition_Obss%nobjects = this%nobjects
+    ALLOCATE(addition_Obss%objects(this%nobjects), &
+         addition_Obss%ind(this%nobs), &
+         addition_Obss%criteria(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addition", &
+            "Could not allocate memory.", 1)
+       CALL NULLIFY(addition_Obss)
+       RETURN
+    END IF
+    addition_Obss%objects  = this%objects
+    addition_Obss%ind      = this%ind
+    addition_Obss%criteria = this%criteria
+
+    ! Add obs_note_arr if present in either of the objects:
+    IF (ASSOCIATED(this%obs_note_arr) .OR. &
+         ASSOCIATED(that%obs_note_arr)) THEN
+       ALLOCATE(addition_Obss%obs_note_arr(this%nobs+that%nobs), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / addition", &
+               "Could not allocate obs_note array.", 1)
+          CALL NULLIFY(addition_Obss)
+          RETURN
+       END IF
+       IF (ASSOCIATED(this%obs_note_arr)) THEN
+          addition_Obss%obs_note_arr(1:this%nobs) = &
+               this%obs_note_arr(1:this%nobs)
+       ELSE
+          addition_Obss%obs_note_arr(1:this%nobs) = " "
+       END IF
+       IF (ASSOCIATED(that%obs_note_arr)) THEN
+          addition_Obss%obs_note_arr(this%nobs+1:) = &
+               that%obs_note_arr(1:that%nobs)
+       ELSE
+          addition_Obss%obs_note_arr(this%nobs+1:) = " "
+       END IF
+    END IF
+
+    ! Add number of observations, and number and names 
+    ! of different objects corresponding to "that":
+    CALL sortObservations(addition_Obss)
+    IF (error) THEN
+       CALL errorMessage("Observations / addition", &
+            "TRACE BACK", 1)
+       CALL NULLIFY(addition_Obss)
+       RETURN
+    END IF
+
+    addition_Obss%is_initialized = .TRUE.
+
+  END FUNCTION addition_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds a single observation to this object.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addObservation(this, obs, sort, note)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    TYPE (Observation), INTENT(in)     :: obs
+    LOGICAL, INTENT(in), OPTIONAL      :: sort
+    CHARACTER(4), INTENT(in), OPTIONAL :: note
+    INTEGER :: nobs
+    LOGICAL                            :: sort_
+
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addObservation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obs)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / addObservation", &
+            "Observation to be added has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (ASSOCIATED(this%obs_arr)) THEN
+       nobs = SIZE(this%obs_arr)
+    ELSE
+       nobs = 0
+    END IF
+    this%obs_arr => reallocate(this%obs_arr, nobs+1)
+    this%obs_arr(nobs+1) = copy(obs)
+    this%obs_note_arr => reallocate(this%obs_note_arr, nobs+1)
+    IF (PRESENT(note)) THEN
+       this%obs_note_arr(nobs+1) = note
+    ELSE
+       this%obs_note_arr(nobs+1) = " "
+    END IF
+    ! Update number of observations, and number and names 
+    ! of different objects as default behaviour:
+    IF (PRESENT(sort)) THEN
+       sort_ = sort
+    ELSE
+       sort_ = .TRUE.
+    END IF
+    IF (sort_) THEN
+       CALL sortObservations(this)
+       IF (error) THEN
+          CALL errorMessage("Observations / addObservation", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+    ELSE
+       this%nobs = nobs + 1
+       this%nobjects = 0
+    END IF
+
+  END SUBROUTINE addObservation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Set designation for all observations within this object.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setDesignation_Obss(this, designation)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    CHARACTER(len=*), INTENT(in)       :: designation
+    INTEGER                            :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / setDesignation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(this%obs_arr)
+       CALL setDesignation(this%obs_arr(i), TRIM(designation))
+       IF (error) THEN
+          CALL errorMessage("Observations / setDesignation", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    END DO
+
+    ! Update number and names of different objects:
+    this%nobjects = 0
+    CALL sortObservations(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / setDesignation", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setDesignation_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Removes multiple instances of the identical observations,
+  !! reallocates the observation arrays, and sorts the data according
+  !! to (1) designations and (2) numbers..
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE clean_Obss(this)
+
+    TYPE (Observations), INTENT(inout) :: this
+    INTEGER :: i, j
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / clean", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    clean1:DO i=1,SIZE(this%obs_arr,dim=1)
+       IF (.NOT.exist(this%obs_arr(this%ind(i)))) CYCLE clean1
+       clean2:DO j=i+1,SIZE(this%obs_arr,dim=1)
+          IF (.NOT.exist(this%obs_arr(this%ind(j)))) CYCLE clean2
+          IF (equal(this%obs_arr(this%ind(i)),this%obs_arr(this%ind(j)))) THEN
+             CALL NULLIFY(this%obs_arr(this%ind(j)))
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Observations / clean", &
+                  "TRACE BACK (5)", 1)
+             RETURN
+          END IF
+       END DO clean2
+    END DO clean1
+    this%obs_arr => reallocate(this%obs_arr)
+
+    ! Update number and names of different objects:
+    this%nobjects = 0
+    CALL sortObservations(this,primary_sort="designation")
+    IF (error) THEN
+       CALL errorMessage("Observations / clean", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE clean_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns true, if there are different coordinates for simultaneous
+  !! observations from the same observatory code.
+  !!
+  LOGICAL FUNCTION containsInconsistencies(this)
+
+    TYPE (Observations), INTENT(in) :: this
+    TYPE (SphericalCoordinates), DIMENSION(:), ALLOCATABLE :: scoord_arr
+    TYPE (Time), DIMENSION(:), ALLOCATABLE :: t_arr
+    TYPE (Observatory), DIMENSION(:), ALLOCATABLE :: obsy_arr
+    INTEGER :: i, j, nobs, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / containsInconsistencies", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = SIZE(this%obs_arr,dim=1)
+    ALLOCATE(scoord_arr(nobs), t_arr(nobs), obsy_arr(nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / containsInconsistencies", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    DO i=1,nobs
+       scoord_arr(i) = getObservationSCoord(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / containsInconsistencies", &
+               "TTRACE BACK (5)", 1)
+          DEALLOCATE(scoord_arr, stat=err)
+          DEALLOCATE(t_arr, stat=err)
+          DEALLOCATE(obsy_arr, stat=err)
+          RETURN
+       END IF
+       t_arr(i) = getTime(scoord_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / containsInconsistencies", &
+               "TTRACE BACK (10)", 1)
+          DEALLOCATE(scoord_arr, stat=err)
+          DEALLOCATE(t_arr, stat=err)
+          DEALLOCATE(obsy_arr, stat=err)
+          RETURN
+       END IF
+       obsy_arr(i) = getObservatory(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / containsInconsistencies", &
+               "TTRACE BACK (15)", 1)
+          DEALLOCATE(scoord_arr, stat=err)
+          DEALLOCATE(t_arr, stat=err)
+          DEALLOCATE(obsy_arr, stat=err)
+          RETURN
+       END IF
+    END DO
+
+    containsInconsistencies = .FALSE.
+    ci:DO i=1,nobs
+       DO j=i+1,nobs
+          IF (.NOT.equal(scoord_arr(i), scoord_arr(j)) .AND. &
+               equal(t_arr(i), t_arr(j)) .AND. &
+               equal(obsy_arr(i), obsy_arr(j))) THEN
+             containsInconsistencies = .TRUE.
+             EXIT ci
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Observations / containsInconsistencies", &
+                  "TTRACE BACK (20)", 1)
+             DEALLOCATE(scoord_arr, stat=err)
+             DEALLOCATE(t_arr, stat=err)
+             DEALLOCATE(obsy_arr, stat=err)
+             RETURN
+          END IF
+       END DO
+    END DO ci
+    DEALLOCATE(scoord_arr, t_arr, obsy_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(scoord_arr, stat=err)
+       DEALLOCATE(t_arr, stat=err)
+       DEALLOCATE(obsy_arr, stat=err)
+       CALL errorMessage("Observations / containsInconsistencies", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION containsInconsistencies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the blocks of the block diagonal information matrix
+  !! containing all observations in this object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! block_diagonal_information_matrix =>
+  !! getBlockDiagonalInformationMatrix(myobservations)
+  !!
+  FUNCTION getBlockDiagInformationMatrix(this)
+
+    TYPE (Observations), INTENT(in)     :: this
+    REAL(bp), DIMENSION(:,:,:), POINTER :: getBlockDiagInformationMatrix
+
+    REAL(bp), DIMENSION(:,:,:), POINTER :: covariance_matrices
+    INTEGER :: i, j, err
+    LOGICAL, DIMENSION(6) :: obs_mask
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getBlockDiagInformationMatrix(this%nobs,6,6), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    covariance_matrices => getCovarianceMatrices(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(covariance_matrices, stat=err)
+       DEALLOCATE(getBlockDiagInformationMatrix, stat=err)
+       RETURN
+    END IF
+    getBlockDiagInformationMatrix = 0.0_bp
+    DO i=1,this%nobs
+       ! The covariance matrix can be inverted separately for
+       ! each observation by using the properties of block diagonal
+       ! matrices:
+       obs_mask = getObservationMask(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(covariance_matrices, stat=err)
+          DEALLOCATE(getBlockDiagInformationMatrix, stat=err)
+          RETURN
+       END IF
+       DO j=1,6
+          IF (.NOT.obs_mask(j)) THEN
+             covariance_matrices(i,j,j) = 1.0_bp
+          END IF
+       END DO
+       getBlockDiagInformationMatrix(i,1:6,1:6) = &
+            matinv(covariance_matrices(i,:,:), errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / " // &
+               "getBlockDiagInformationMatrix", &
+               "Could not invert covariance matrix for observations " // &
+               TRIM(errstr), 1)
+          DEALLOCATE(covariance_matrices, stat=err)
+          DEALLOCATE(getBlockDiagInformationMatrix, stat=err)
+          RETURN
+       END IF
+       DO j=1,6
+          IF (.NOT.obs_mask(j)) THEN
+             getBlockDiagInformationMatrix(i,j,j) = 0.0_bp
+          END IF
+       END DO
+    END DO
+    DEALLOCATE(covariance_matrices, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getBlockDiagInformationMatrix", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+
+  END FUNCTION getBlockDiagInformationMatrix
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array containing covariance matrices for all
+  !! observations in this object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! covariance_matrices => getCovarianceMatrices(myobservations)
+  !!
+  FUNCTION getCovarianceMatrices(this)
+
+    TYPE (Observations), INTENT(in)     :: this
+    REAL(bp), DIMENSION(:,:,:), POINTER :: getCovarianceMatrices
+    INTEGER                             :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getCovarianceMatrices", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getCovarianceMatrices", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getCovarianceMatrices(this%nobs,6,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getCovarianceMatrices", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getCovarianceMatrices(i,:,:) = getCovarianceMatrix(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getCovarianceMatrices", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getCovarianceMatrices, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getCovarianceMatrices
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns MJDs in UTC for all observations within this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getDates_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER :: getDates_Obss
+    TYPE (Time)                     :: t
+    INTEGER                         :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDates", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDates", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getDates_Obss(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDates", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+       t = getTime(this%obs_arr(i))
+       getDates_Obss(i) = getMJD(t, "UTC")
+       IF (error) THEN
+          CALL errorMessage("Observations / getDates", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getDates_Obss, stat=err)
+          RETURN
+       END IF
+       CALL NULLIFY(t)
+    END DO
+
+  END FUNCTION getDates_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns declinations for all observations within this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getDeclinations_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER :: getDeclinations_Obss
+    INTEGER                         :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDeclinations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDeclinations", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getDeclinations_Obss(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDeclinations", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+       getDeclinations_Obss(i) = getDec(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getDeclinations", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getDeclinations_Obss, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getDeclinations_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns designations for all observations within this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getDesignations(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)                       :: this
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: getDesignations
+    INTEGER                                               :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDesignations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDesignations", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getDesignations(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDesignations", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+       getDesignations(i) = getDesignation(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getDesignations", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getDesignations, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getDesignations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the _only_ designation for all observations within this
+  !! object. If more than one designations exist, an error occurs.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getDesignation_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    CHARACTER(len=DESIGNATION_LEN)  :: getDesignation_Obss
+
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: designations
+    INTEGER                                               :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDesignation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getDesignation", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    designations => getDesignations(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / getDesignation", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    DO i=2,this%nobs
+       IF (designations(1) /= designations(i)) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / getDesignation", &
+               "More than one designation.", 1)
+          DEALLOCATE(designations, stat=err)
+          RETURN
+       END IF
+    END DO
+    getDesignation_Obss = designations(1)
+    DEALLOCATE(designations, stat=err)
+
+  END FUNCTION getDesignation_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns filters for observations.
+  !!
+  !! *Usage*:
+  !!
+  !! filters => getFilters(myobservations)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getFilters(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)         :: this
+    CHARACTER(len=2), DIMENSION(:), POINTER :: getFilters
+    INTEGER                                 :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getFilters", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getFilters", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getFilters(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getFilters", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getFilters(i) = getFilter(this%obs_arr(this%ind(i))) 
+       IF (error) THEN
+          CALL errorMessage("Observations / getFilters", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getFilters, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getFilters
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the ID (number or designation) for an single object object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getID_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    CHARACTER(len=DESIGNATION_LEN)  :: getID_Obss
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getID", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1 .OR. .NOT.ASSOCIATED(this%objects)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getID", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    IF (SIZE(this%objects, dim=1) == 1) THEN
+       getID_Obss = this%objects(1)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Observations / getID", &
+            "Contains more than one objects.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getID_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the complete information matrix containing all
+  !! observations in this object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! information_matrix => getInformationMatrix(myobservations)
+  !!
+  FUNCTION getInformationMatrix(this)
+
+    TYPE (Observations), INTENT(in)     :: this
+    REAL(bp), DIMENSION(:,:), POINTER   :: getInformationMatrix
+    REAL(bp), DIMENSION(:,:,:), POINTER :: covariance_matrices
+    INTEGER                             :: i, j, k, err
+    LOGICAL, DIMENSION(6)               :: obs_mask
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getInformationMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getInformationMatrix", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getInformationMatrix(this%nobs*6,this%nobs*6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getInformationMatrix", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    covariance_matrices => getCovarianceMatrices(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / getInformationMatrix", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(getInformationMatrix, stat=err)
+       DEALLOCATE(covariance_matrices, stat=err)
+       RETURN
+    END IF
+    getInformationMatrix = 0.0_bp
+    DO i=1,this%nobs
+       ! The covariance matrix can be inverted separately for
+       ! each observation by using the properties of block diagonal
+       ! matrices:
+       j = (i-1)*6
+       obs_mask = getObservationMask(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getInformationMatrix", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(getInformationMatrix, stat=err)
+          DEALLOCATE(covariance_matrices, stat=err)
+          RETURN
+       END IF
+       DO k=1,6
+          IF (.NOT.obs_mask(k)) THEN
+             covariance_matrices(i,k,k) = 1.0_bp
+          END IF
+       END DO
+       getInformationMatrix(j+1:j+6,j+1:j+6) = &
+            matinv(covariance_matrices(i,:,:), errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / " // &
+               "getInformationMatrix", &
+               "Could not invert covariance matrix for observations " // &
+               TRIM(errstr), 1)
+          DEALLOCATE(getInformationMatrix, stat=err)
+          DEALLOCATE(covariance_matrices, stat=err)
+          RETURN
+       END IF
+       DO k=1,6
+          IF (.NOT.obs_mask(k)) THEN
+             getInformationMatrix(j+k,j+k) = 0.0_bp
+          END IF
+       END DO
+    END DO
+    DEALLOCATE(covariance_matrices, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getInformationMatrix", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+
+  END FUNCTION getInformationMatrix
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns magnitudes for observations [mag].
+  !!
+  !! *Usage*:
+  !!
+  !! mags => getMagnitudes(myobservations)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getMagnitudes(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER :: getMagnitudes
+    INTEGER                         :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudes", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudes", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getMagnitudes(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudes", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getMagnitudes(i) = getMagnitude(this%obs_arr(this%ind(i))) 
+       IF (error) THEN
+          CALL errorMessage("Observations / getMagnitudes", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getMagnitudes, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getMagnitudes
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns magnitude uncertainties for observations [mag].
+  !!
+  !! *Usage*:
+  !!
+  !! mag_uncs => getMagnitudeUncertainties(myobservations)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getMagnitudeUncertainties(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER :: getMagnitudeUncertainties
+    INTEGER                         :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudeUncertainties", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudeUncertainties", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getMagnitudeUncertainties(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMagnitudeUncertainties", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getMagnitudeUncertainties(i) = getMagnitudeUncertainty(this%obs_arr(this%ind(i))) 
+       IF (error) THEN
+          CALL errorMessage("Observations / getMagnitudeUncertainties", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getMagnitudeUncertainties, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getMagnitudeUncertainties
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns two onedimensional arrays containing the minimum and maximum values
+  !! for R.A., Dec. and Julian date (UTC). The values does not necessarily correspond
+  !! to the same observation. They are just the minima and maxima of this particular
+  !! Observations object.
+  !!
+  !! *OBS*! _For_ R.A. (index=2) the extremes are given as
+  !! a minimum for the rightmost coordinate, and maximum for the leftmost. In other
+  !! words: if the object contains R.A. coordinates from 23h to 1h, then 23h will 
+  !! be the minimum and 1h the maximum. If there are only 2 coordinates, the minimum
+  !! and maximum value will be defined by requiring ABS(&Delta(R.A.)) to be as small
+  !! as possible.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object has not been initialized or something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! real(bp), dimension(:,:), pointer :: minmax
+  !! .
+  !! .
+  !! .
+  !! minmax => getMinAndMaxValues(obss)
+  !! </pre>
+  FUNCTION getMinAndMaxValues_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)       :: this
+    REAL(bp), DIMENSION(:,:), POINTER     :: getMinAndMaxValues_Obss
+    TYPE (Time)                           :: t
+    TYPE (CartesianCoordinates)           :: ccoord
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: obs_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE   :: tmp
+    REAL(bp)                              :: ra_min1, ra_max1, &
+         ra_min2, ra_max2
+    INTEGER                               :: i, no, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE    :: mask_array
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMinAndMaxValues", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMinAndMaxValues", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getMinAndMaxValues_Obss(3,2), &
+         obs_arr(this%nobs,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMinAndMaxValues", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+
+       ! Observation date MJD (UTC):
+       t = getTime(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getMinAndMaxValues", &
+               "TRACE BACK 1", 1)
+          DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(t)
+          RETURN
+       END IF
+       obs_arr(i,1) = getMJD(t, "utc")
+       IF (error) THEN
+          CALL errorMessage("Observations / getMinAndMaxValues", &
+               "TRACE BACK 2", 1)
+          DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(t)
+          RETURN
+       END IF
+
+       ! Right Ascension (rad):
+       obs_arr(i,2) = getRA(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getMinAndMaxValues", &
+               "TRACE BACK 3", 1)
+          DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(t)
+          RETURN
+       END IF
+
+       ! Declination (rad):
+       obs_arr(i,3) = getDec(this%obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getMinAndMaxValues", &
+               "TRACE BACK 4", 1)
+          DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(t)
+          RETURN
+       END IF
+
+       ! Observatory coordinates (heliocentric equatorial Cartesian coordinates
+       ! in AU's) 
+       ccoord = getObservatoryCCoord(this%obs_arr(i))
+       obs_arr(i,4:6) = getPosition(ccoord)
+       CALL NULLIFY(ccoord)
+       CALL NULLIFY(t)
+       IF (error) THEN
+          CALL errorMessage("Observations / getMinAndMaxValues", &
+               "TRACE BACK 5", 1)
+          DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+          DEALLOCATE(obs_arr, stat=err)
+          RETURN
+       END IF
+
+    END DO
+
+    ! Find the extreme values:
+    ! Julian date (UTC):
+    getMinAndMaxValues_Obss(1,1) = MINVAL(obs_arr(:,1))
+    getMinAndMaxValues_Obss(1,2) = MAXVAL(obs_arr(:,1))
+
+    ! Right ascension:
+    ! If there are more than one observation and R.A. goes from, for 
+    ! instance, 23h -> 1h, we have a problem since it seems like 1h
+    ! would be the minimum instead of 23h. So we ca not make an easy
+    ! substitution, but must make a work-around: 
+    ALLOCATE(mask_array(SIZE(obs_arr,1)), &
+         tmp(SIZE(obs_arr,1)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getMinAndMaxValues", &
+            "Could not allocate memory for temporary arrays.", 1)
+       DEALLOCATE(getMinAndMaxValues_Obss, stat=err)
+       DEALLOCATE(obs_arr, stat=err)
+       DEALLOCATE(tmp, stat=err)
+       DEALLOCATE(mask_array, stat=err)
+       RETURN
+    END IF
+    mask_array = .FALSE.
+    ! Choose observations with R.A. in 
+    ! the interval [0,pi[ ([0h,12h[):
+    tmp = obs_arr(:,2) + pi
+    WHERE (tmp < two_pi) mask_array = .TRUE.
+    ! Count them:
+    no = 0
+    DO i=1, SIZE(mask_array)
+       IF (mask_array(i)) no = no + 1
+    END DO
+    ! If there are observations, find the extremes in 
+    ! the interval [0,pi[ ([0h,12h[):
+    IF (no > 0) THEN
+       ra_min1 = -pi + MINVAL(tmp, mask=mask_array)
+       ra_max1 = -pi + MAXVAL(tmp, mask=mask_array)
+    ELSE ! Else put a mark:
+       ra_min1 = -1.0_bp
+    END IF
+    mask_array = .FALSE.
+    ! Choose observations with R.A. in 
+    ! the interval [pi,2pi[ ([12h,24h[):
+    tmp = obs_arr(:,2) - pi
+    WHERE (tmp >= 0.0_bp) mask_array = .TRUE.
+    ! Count them:
+    no = 0
+    DO i=1, SIZE(mask_array)
+       IF (mask_array(i)) no = no + 1
+    END DO
+    ! If there are observations, find the extremes in 
+    ! the interval [pi,2pi[ ([12h,24h[):
+    IF (no > 0) THEN
+       ra_min2 = pi + MINVAL(tmp, mask=mask_array)
+       ra_max2 = pi + MAXVAL(tmp, mask=mask_array)
+    ELSE ! Else put a mark:
+       ra_min2 = -1.0_bp
+    END IF
+
+    ! Choose the extremes:
+    IF (ra_min1 < 0.0_bp) THEN
+       ! There are observations only in 
+       ! the interval [pi,2pi[: 
+       getMinAndMaxValues_Obss(2,1) = ra_min2
+       getMinAndMaxValues_Obss(2,2) = ra_max2
+    ELSE IF (ra_min2 < 0.0_bp) THEN
+       ! There are observations only in 
+       ! the interval [0,pi[: 
+       getMinAndMaxValues_Obss(2,1) = ra_min1
+       getMinAndMaxValues_Obss(2,2) = ra_max1
+    ELSE
+       ! There are observations in both intervals:
+       IF ((ra_min2 - ra_max1) <= &
+            ((two_pi + ra_min1) - ra_max2)) THEN
+          ! The distance ra_max1 -> ra_min2 is
+          ! shorter than the distance from
+          ! ra_max2 -> ra_min1:
+          getMinAndMaxValues_Obss(2,1) = ra_min1
+          getMinAndMaxValues_Obss(2,2) = ra_max2
+       ELSE
+          ! The distance ra_max2 -> ra_min1 is
+          ! shorter than the distance from
+          ! ra_max1 -> ra_min2:
+          getMinAndMaxValues_Obss(2,1) = ra_min2
+          getMinAndMaxValues_Obss(2,2) = ra_max1
+       END IF
+    END IF
+
+    ! Declination:
+    getMinAndMaxValues_Obss(3,1) = MINVAL(obs_arr(:,3))
+    getMinAndMaxValues_Obss(3,2) = MAXVAL(obs_arr(:,3))
+
+    DEALLOCATE(tmp, mask_array, obs_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(obs_arr, stat=err)
+       DEALLOCATE(tmp, stat=err)
+       DEALLOCATE(mask_array, stat=err)
+       CALL errorMessage("Observations / getMinAndMaxValues", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getMinAndMaxValues_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the number of different objects in an Observations
+  !! object.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object has not been initialized or 
+  !!               something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! integer :: different_objects
+  !! .
+  !! .
+  !! .
+  !! different_objects = getNrOfObjects(obss)
+  !! </pre>
+  INTEGER FUNCTION getNrOfObjects(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getNrOfObjects", &
+            "Astrometric observations (MPC) have already been initialized.", 1)
+       RETURN
+    END IF
+
+    getNrOfObjects = this%nobjects
+
+  END FUNCTION getNrOfObjects
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the total number of observations.
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION getNrOfObservations(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getNrOfObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getNrOfObservations = this%nobs
+
+  END FUNCTION getNrOfObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the number of this object.
+  !!
+  !! Returns error if there are more than one numbers.
+  !!
+  INTEGER FUNCTION getNumber_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)  :: this
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getNumber", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getNumber", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    getNumber_Obss = getNumber(this%obs_arr(1))
+    DO i=2,this%nobs
+       IF (getNumber_Obss /= getNumber(this%obs_arr(i))) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / getNumber", &
+               "Different numbers in this set of observations.", 1)
+          RETURN          
+       END IF
+    END DO
+
+  END FUNCTION getNumber_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the number of observations.
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION getNumberOfObservations(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)  :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getNumberOfObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getNumberOfObservations = this%nobs
+
+  END FUNCTION getNumberOfObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the id's of different objects in an Observations
+  !! object.
+  !!
+  !! Returns error.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! character(len=16), dimension(:), pointer :: objects
+  !! .
+  !! .
+  !! .
+  !! objects => getObjects(obss)
+  !! </pre>
+  FUNCTION getObjects(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)                    :: this
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: getObjects 
+    INTEGER                                               :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObjects", &
+            "Astrometric observations (MPC) have already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobjects < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObjects", &
+            "Objects missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObjects(this%nobjects), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObjects", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    getObjects = this%objects
+
+  END FUNCTION getObjects
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the observation indicated by index i in this
+  !! object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! obs = getObservation(myobservations, 2)
+  !!
+  FUNCTION getObservation(this, i)
+
+    TYPE (Observations), INTENT(in) :: this
+    INTEGER, INTENT(in)             :: i
+    TYPE (Observation)              :: getObservation
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < i) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservations", &
+            "Number of observation is too large.", 1)
+       RETURN
+    END IF
+
+    getObservation = copy(this%obs_arr(this%ind(i)))
+    IF (error) THEN
+       CALL errorMessage("Observations / getObservations", &
+            "TRACE BACK", 1)
+       CALL NULLIFY(getObservation)
+       RETURN
+    END IF
+
+  END FUNCTION getObservation
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the the angular arc (radians) between 
+  !! the first and the last observation.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getObservationalAngularArc(this)
+
+    TYPE (Observations), INTENT(in) :: this
+    REAL(bp)                        :: ra1, dec1, ra2, dec2, cos_alpha
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationalAngularArc", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ra1  = getRA(this%obs_arr(this%ind(1)))
+    dec1 = getDec(this%obs_arr(this%ind(1)))
+    ra2  = getRA(this%obs_arr(this%ind(this%nobs)))
+    dec2 = getDec(this%obs_arr(this%ind(this%nobs)))
+    cos_alpha = COS(ra2-ra1)*COS(dec1)*COS(dec2) + SIN(dec1)*SIN(dec2)
+    IF (ABS(cos_alpha) > 1.0_bp) THEN
+       cos_alpha = SIGN(1.0_bp, cos_alpha)
+    END IF
+    getObservationalAngularArc = ACOS(cos_alpha)
+
+  END FUNCTION getObservationalAngularArc
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the observational timespan
+  !! (&DeltaT) from the first to the last observation
+  !! in [Julian] days.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getObservationalTimespan(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationalTimespan", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationalTimespan", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    getObservationalTimespan = this%criteria(this%ind(this%nobs)) - this%criteria(this%ind(1))
+    IF (getObservationalTimespan < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationalTimespan", &
+            "Negative time arc: check code.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getObservationalTimespan
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array containing masks for all observations in this
+  !! object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! obs_masks => getObservationMasks(myobservations)
+  !!
+  !FUNCTION getObservationMasks_Obss(this)
+  FUNCTION getObservationMasks_Obss(this, use_notes)
+
+    TYPE (Observations), INTENT(in)  :: this
+    LOGICAL, INTENT(in), OPTIONAL    :: use_notes
+    LOGICAL, DIMENSION(:,:), POINTER :: getObservationMasks_Obss
+    LOGICAL                          :: use_notes_
+    INTEGER                          :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationMasks", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationMasks", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservationMasks_Obss(this%nobs,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationMasks", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(use_notes)) THEN
+       use_notes_ = use_notes
+    ELSE
+       use_notes_ = .FALSE.
+    END IF
+
+    DO i=1, this%nobs
+       !IF (this%obs_note_arr(this%ind(i)) == "#") THEN
+       IF (use_notes_ .AND. this%obs_note_arr(this%ind(i)) == "#") THEN
+          getObservationMasks_Obss(i,1:6) = .FALSE.
+       ELSE
+          getObservationMasks_Obss(i,1:6) = getObservationMask(this%obs_arr(this%ind(i)))
+          IF (error) THEN
+             CALL errorMessage("Observations / getObservationMasks", &
+                  "TRACE BACK", 1)
+             DEALLOCATE(getObservationMasks_Obss, stat=err)
+             RETURN
+          END IF
+       END IF
+    END DO
+
+  END FUNCTION getObservationMasks_Obss
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array containing notes for all observations in this
+  !! object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! obs_notes => getObservationNotes(myobservations)
+  !!
+  FUNCTION getObservationNotes(this)
+
+    TYPE (Observations), INTENT(in)  :: this
+    CHARACTER(4), DIMENSION(:), POINTER :: getObservationNotes
+    INTEGER                          :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationNotes", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationNotes", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservationNotes(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationNotes", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getObservationNotes(i) = this%obs_note_arr(this%ind(i))
+    END DO
+
+  END FUNCTION getObservationNotes
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array containing all observations in this
+  !! object.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! obs => getObservations(myobservations)
+  !!
+  FUNCTION getObservations(this)
+
+    TYPE (Observations), INTENT(in)           :: this
+    TYPE (Observation), DIMENSION(:), POINTER :: getObservations
+    INTEGER                                   :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / get", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservations(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservations", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getObservations(i) = copy(this%obs_arr(this%ind(i)))
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / getObservations", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getObservations, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+
+  !! Returns observation weights for all 6 observables (distance, ra,
+  !! dec, and their time derivatives) based on the relative standard
+  !! deviations (stdev): the observation with the smallest stdev gets
+  !! weight=1, while the largest stdevs corresponds to smaller
+  !! weights. A negative value indicates that a measurement does not
+  !! exist (cfg. obs_mask = .false.).
+  !!
+  !! Example:
+  !!
+  !! obs1_stdev_ra = 0.10''  obs1_stdev_dec = 0.05''
+  !! obs2_stdev_ra = 0.50''  obs2_stdev_dec = 0.10''
+  !!
+  !! ==> 
+  !!
+  !! obs1_weight_ra = 1.0   obs1_weight_dec = 1.0
+  !! obs2_weight_ra = 0.2   obs2_weight_dec = 0.5
+  !!
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! weights => getObservationWeights(myobservations)
+  !!
+  FUNCTION getObservationWeights(this)
+
+    TYPE (Observations), INTENT(in)   :: this
+    REAL(bp), DIMENSION(:,:), POINTER :: getObservationWeights
+    REAL(bp)                          :: stdev_min
+    INTEGER                           :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationWeights", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationWeights", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    getObservationWeights => getStandardDeviations(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / getObservationWeights", &
+            "TRACE BACK", 1)
+       DEALLOCATE(getObservationWeights, stat=err)
+       RETURN
+    END IF
+
+    ! For each observable..
+    DO i=1,6
+       ! Find the smallest stdev: 
+       stdev_min = MINVAL(ABS(getObservationWeights(:,i)))
+       ! The weight is equal to the inverse of the ratio of the stdev
+       ! and the smallest stdev:
+       getObservationWeights(:,i) = stdev_min / getObservationWeights(:,i)
+    END DO
+
+  END FUNCTION getObservationWeights
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array of spherical coordinates corresponding to the
+  !! observations.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! scoords => getObservationSCoords(myobservations)
+  !!
+  FUNCTION getObservationSCoords(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)                    :: this
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: getObservationSCoords
+    INTEGER                                            :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationSCoords", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationSCoords", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservationSCoords(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservationSCoords", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getObservationSCoords(i) = getObservationSCoord(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getObservationSCoords", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getObservationSCoords, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getObservationSCoords
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an array of Cartesian coordinates corresponding to the
+  !! heliocentric locations of the observers at times corresponding to
+  !! the observations.
+  !!
+  !! Returns error.
+  !!
+  !!
+  !! *Usage*:
+  !!
+  !! ccoords => getObservatoryCCoords(myobservations)
+  !!
+  FUNCTION getObservatoryCCoords(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)                    :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: getObservatoryCCoords
+    INTEGER                                            :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCCoords", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCCoords", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservatoryCCoords(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCCoords", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getObservatoryCCoords(i) = getObservatoryCCoord(this%obs_arr(this%ind(i))) 
+       IF (error) THEN
+          CALL errorMessage("Observations / getObservatoryCCoords", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getObservatoryCCoords, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getObservatoryCCoords
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the observatory codes for the observatories where these observations were made.
+  !!
+  !! Returns error.
+  !!
+  !!
+  !! *Usage*:
+  !!
+  !! codes => getObservatoryCodes(myobservations)
+  !!
+  FUNCTION getObservatoryCodes_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)                    :: this
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), POINTER :: getObservatoryCodes_Obss
+    INTEGER                                            :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCodes", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCodes", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservatoryCodes_Obss(this%nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getObservatoryCodes", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobs
+       getObservatoryCodes_Obss(i) = getObservatoryCode(this%obs_arr(this%ind(i))) 
+       IF (error) THEN
+          CALL errorMessage("Observations / getObservatoryCodes", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getObservatoryCodes_Obss, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getObservatoryCodes_Obss
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an Observations array containing the
+  !! input Observations object separated into Observations objects
+  !! with different (1) numbers or (2) designations.
+  !!
+  !! Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if this object has not been initialized or something goes wrong.
+  !! 
+  !! *Usage*:
+  !!
+  !! <pre>
+  !! type (Observations) :: obss
+  !! type (Observations), dimension(:), pointer :: separated_sets
+  !! .
+  !! .
+  !! .
+  ! separated_sets => getSeparatedSets(obss)
+  !! </pre>
+  !!
+  FUNCTION getSeparatedSets(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)         :: this
+    TYPE (Observations), DIMENSION(:), POINTER :: getSeparatedSets
+    CHARACTER(len=DESIGNATION_LEN)             :: id
+    INTEGER                                    :: i, j, err, number
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getSeparatedSets", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getSeparatedSets", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getSeparatedSets(this%nobjects), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getSeparatedSets", &
+            "Could not allocate memory for separated objects.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%nobjects
+       CALL NULLIFY(getSeparatedSets(i))
+       CALL NEW(getSeparatedSets(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / getSeparatedSets", &
+               "TRACE BACK 2", 1)
+          DEALLOCATE(getSeparatedSets, stat=err)
+          RETURN
+       END IF
+    END DO
+
+    DO i=1, this%nobs
+
+       ! (1) number or (2) designation: 
+       number = getNumber(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getSeparatedSets", &
+               "TRACE BACK 3", 1)
+          DEALLOCATE(getSeparatedSets, stat=err)
+          RETURN
+       END IF
+       IF (number /= 0) THEN
+          CALL toString(number, id, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / getSeparatedSets", &
+                  "TRACE BACK 4", 1)
+             DEALLOCATE(getSeparatedSets, stat=err)
+             RETURN
+          END IF
+          DO WHILE (LEN_TRIM(id) < 7)
+             id = "0" // TRIM(id)
+          END DO
+       ELSE
+          id = getDesignation(this%obs_arr(this%ind(i)))
+          IF (error) THEN
+             CALL errorMessage("Observations / getSeparatedSets", &
+                  "TRACE BACK 5", 1)
+             DEALLOCATE(getSeparatedSets, stat=err)
+             RETURN
+          END IF
+       END IF
+       DO j=1, this%nobjects
+          IF (id == this%objects(j)) EXIT
+       END DO
+       CALL addObservation(getSeparatedSets(j), &
+            this%obs_arr(this%ind(i)), &
+            note=this%obs_note_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getSeparatedSets", &
+               "TRACE BACK 6", 1)
+          DEALLOCATE(getSeparatedSets, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getSeparatedSets
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! 
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getStandardDeviations_Obss(this)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)   :: this
+    REAL(bp), DIMENSION(:,:), POINTER :: getStandardDeviations_Obss
+    INTEGER                           :: i, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getStandardDeviations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getStandardDeviations", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getStandardDeviations_Obss(this%nobs,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / getStandardDeviations", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+       getStandardDeviations_Obss(i,1:6) = getStandardDeviations(this%obs_arr(this%ind(i)))
+       IF (error) THEN
+          CALL errorMessage("Observations / getStandardDeviations", &
+               "TRACE BACK", 1)
+          DEALLOCATE(getStandardDeviations_Obss, stat=err)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getStandardDeviations_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Groups a set of observations into subgroups based on observation
+  !! date and number of observations.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE groupObservations(this, time_interval, nobs_max, obss_arr, tdt_arr)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in)   :: this
+    REAL(bp), INTENT(in) :: time_interval
+    INTEGER, INTENT(in) :: nobs_max
+    TYPE (Observations), DIMENSION(:), POINTER :: obss_arr
+    REAL(bp), DIMENSION(:,:), POINTER :: tdt_arr
+    REAL(bp) :: tdt_, tdt_sum 
+    INTEGER  :: i, j, nobs, nobs_max_, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / groupObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs < 1) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / groupObservations", &
+            "Observations missing.", 1)
+       RETURN
+    END IF
+
+    IF (nobs_max < 0) THEN
+       nobs_max_ = HUGE(nobs_max_)
+    ELSE
+       nobs_max_ = nobs_max
+    END IF
+
+    tdt_ = this%criteria(this%ind(1))
+    i = 0
+    j = 0
+    DO
+       IF (j+1 > this%nobs) THEN
+          EXIT
+       END IF
+       i = i + 1
+       tdt_arr => reallocate(tdt_arr,i,2)
+       tdt_arr(i,2) = tdt_
+       obss_arr => reallocate(obss_arr,i)
+       CALL NULLIFY(obss_arr(i))
+       CALL NEW(obss_arr(i))
+       IF (error) THEN
+          CALL errorMessage("Observations / groupObservations", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(tdt_arr, stat=err)
+          DEALLOCATE(obss_arr, stat=err)
+          RETURN
+       END IF
+       nobs = 0
+       tdt_sum = 0.0_bp
+       DO
+          IF (j+1 > this%nobs) THEN
+             EXIT
+          ELSE IF (this%criteria(this%ind(j+1)) - tdt_ > time_interval &
+               .OR. nobs+1 > nobs_max_) THEN
+             tdt_ = this%criteria(this%ind(j+1))
+             EXIT
+          ELSE
+             nobs = nobs + 1
+             j = j + 1
+             tdt_sum = tdt_sum + this%criteria(this%ind(j))
+             CALL addObservation(obss_arr(i), this%obs_arr(this%ind(j)))
+             IF (error) THEN
+                CALL errorMessage("Observations / groupObservations", &
+                     "TRACE BACK (5)", 1)
+                DEALLOCATE(tdt_arr, stat=err)
+                DEALLOCATE(obss_arr, stat=err)
+                RETURN
+             END IF
+          END IF
+       END DO
+       tdt_arr(i,1) = tdt_sum/REAL(nobs,bp)
+       tdt_arr(i,2) = this%criteria(this%ind(j)) - tdt_arr(i,2)
+    END DO
+    tdt_arr(:,1) = tdt_arr(:,1) - tdt_arr(1,1)
+
+  END SUBROUTINE groupObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Intrinsic routine that reads a file of the given format.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE readObservationFile(this, obsf, stdev, orb_sim)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)           :: this
+    TYPE (File), INTENT(in)                      :: obsf
+    REAL(bp), DIMENSION(6), INTENT(in), OPTIONAL :: stdev
+    TYPE (Orbit), INTENT(inout), OPTIONAL        :: orb_sim
+
+    TYPE (File) :: orbfile
+    TYPE (Orbit) :: orb
+    TYPE (Observatories) :: obsies
+    TYPE (Observatory) :: obsy
+    TYPE (Time) :: t, t0
+    TYPE (SphericalCoordinates) :: obs_scoord, ephemeris
+    TYPE (CartesianCoordinates) :: obsy_ccoord, geocenter_ccoord, &
+         satellite_ccoord
+    CHARACTER(len=FNAME_LEN) :: fname, suffix
+    CHARACTER(len=DESIGNATION_LEN) :: designation
+    CHARACTER(len=132), DIMENSION(5) :: records
+    CHARACTER(len=132) :: record
+    CHARACTER(len=124) :: line1, line2, line_, str, filter, obstype
+    CHARACTER(len=4) :: timescale, obsy_code
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: element_arr
+    REAL(bp), DIMENSION(6,6) :: covariance
+    REAL(bp), DIMENSION(6) :: coordinates, stdev_, mean
+    REAL(bp), DIMENSION(3) :: position, velocity
+    REAL(bp) :: day, sec, arcsec, mag, ra, dec, jd, mjd_utc, dt, &
+         ecl_lon, ecl_lat, angscan, pos_unc_along, pos_unc_across, &
+         vel_unc_along, vel_unc_across, rot_angle, correlation, &
+         rmin, rarcmin, mag_unc, s2n
+    INTEGER :: i, j, err, nr, year, month, hour, min, deg, arcmin, &
+         nlines, coord_unit, indx, iobs, irecord, norb
+    LOGICAL, DIMENSION(6) :: obs_mask
+    LOGICAL :: discovery, converttonewformat
+
+    converttonewformat = .FALSE.
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readObservationFile", &
+            "Astrometric observations (MPC) have already been initialized.", 1)
+       RETURN
+    END IF
+
+    nlines = getNrOfLines(obsf)
+    IF (error) THEN
+       CALL errorMessage("Observations / readObservationFile", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(this%obs_arr(nlines), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readObservationFile", &
+            "Could not allocate memory for the observations.", 1)
+       RETURN
+    END IF
+
+    CALL NEW(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readObservationFile", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(this%obs_note_arr(nlines), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readObservationFile", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    this%obs_note_arr = " "
+
+    ! Decide which routine should read the input 
+    ! file by checking the suffix:
+    fname = getFileName(obsf)
+    indx = INDEX(fname, ".", back=.TRUE.)
+    IF (indx == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / new", &
+            "Suffix required in file name.",1)
+    END IF
+    suffix = fname(indx+1:LEN_TRIM(fname))
+    CALL locase(suffix, error)
+    IF (error) THEN
+       CALL errorMessage("Observations / new", &
+            "The suffix string contains forbidden characters.", 1)
+       RETURN
+    END IF
+
+    IF (info_verb >= 1 .AND. PRESENT(stdev) .AND. &
+         suffix == "mpc2") THEN
+       WRITE(stdout,"(1X,A)") "WARNING! Overriding " // &
+            "observation uncertainties given in the " // &
+            "observation file with the ones given in " // &
+            "the option file."
+    END IF
+
+    SELECT CASE (TRIM(suffix))
+
+    CASE ("des")
+
+       ! This is the Data Exchange Standard adopted by MOPS.
+
+       ! Read first line to check if the header exists:
+       READ(getUnit(obsf), "(A)", iostat=err) line1
+       IF (.NOT.(line1(1:2) == "!!" .OR. line1(1:1) == "#")) THEN
+          REWIND(getUnit(obsf))
+       END IF
+       i = 0
+       DO
+          designation = " "
+          covariance = 0.0
+          READ(getUnit(obsf), *, iostat=err) designation, mjd_utc, &
+               obstype, ra, dec, mag, filter, obsy_code, &
+               covariance(2,2), covariance(3,3), mag_unc, s2n, str
+          IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Error while reading DES observations from file.", 1)
+             RETURN
+          ELSE IF (err < 0) THEN ! end-of-file
+             EXIT
+          ELSE IF (designation(1:1) == "!" .OR. designation(1:1) == "#") THEN
+             CYCLE
+          END IF
+          CALL NEW(t, mjd_utc, "UTC")
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (15)", 1)
+             RETURN
+          END IF
+          CALL NEW(obs_scoord, ra*rad_deg, dec*rad_deg, t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+          IF (PRESENT(stdev)) THEN
+             DO j=1,6
+                covariance(j,j) = stdev(j)**2.0_bp
+             END DO
+          ELSE
+             covariance(2,2) = (covariance(2,2)*rad_asec)**2.0_bp
+             covariance(3,3) = (covariance(3,3)*rad_asec)**2.0_bp
+          END IF
+          IF (obstype == "O" .OR. obstype == "o") THEN
+             obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+          END IF
+          obsy = getObservatory(obsies, obsy_code)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (25)", 1)
+             RETURN
+          END IF
+          obsy_ccoord = getObservatoryCCoord(obsies, obsy_code, t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (30)", 1)
+             RETURN
+          END IF
+          IF (filter == "X") THEN
+             filter = " "
+          END IF
+          i = i + 1
+          CALL NEW(this%obs_arr(i), number=0, designation=designation, &
+               discovery=.FALSE., note1="", note2="", &
+               obs_scoord=obs_scoord, covariance=covariance, &
+               obs_mask=obs_mask, mag=mag, mag_unc=mag_unc, &
+               filter=filter, s2n=s2n, obsy=obsy, &
+               obsy_ccoord=obsy_ccoord, secret_name=TRIM(str))
+          CALL NULLIFY(t)
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(obsy_ccoord)
+       END DO
+
+    CASE ("mpc") ! Minor Planet Center old format
+
+       ! This is the file format (http://cfa-www.harvard.edu/iau/info/OpticalObs.html):
+       ! to be read from the observations file:
+       !
+       ! Nr.,Des.,New       Time                R.A.                 
+       !   ---15---- --------17--------- --------12---------      
+       ! "(I5,A7,3A1,I4,1X,I2,1X,F8.5,1X,I2,1X,I2,1X,F5.2,1X," // &
+       !         Dec.           Mag.,Filter   Obs. 
+       !  --------12---------    ---6---    -3-
+       ! "I3,1X,I2,1X,F4.1,1X,9X,F5.3,A1,6X,A3)"
+
+       obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+       i = 0
+       DO
+
+          READ(getUnit(obsf), "(A124)", iostat=err) line_
+          IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Error while reading observations from file.", 1)
+             RETURN
+          ELSE IF (err < 0) THEN ! end-of-file
+             EXIT
+          END IF
+
+          IF (info_verb >= 4) THEN
+             WRITE(stdout,"(A80)") line_
+          END IF
+
+          ! If the line is empty or marked with "#", read the next line:
+          IF (LEN_TRIM(line_) == 0 .OR. line_(1:1) == "#") THEN
+             CYCLE
+          END IF
+          ! Skip observation if line contains radar observations
+          IF (line_(15:15) == "r" .OR. line_(15:15) == "R") THEN
+             CYCLE
+          END IF
+          ! Skip observation if line contains "Roving Observer" observations
+          IF (line_(15:15) == "v" .OR. line_(15:15) == "V") THEN
+             CYCLE
+          END IF
+
+          i = i + 1
+
+          ! Read additional note from file
+          IF (line_(1:1) == "!") THEN
+             str = line_(2:2)
+             CALL removeLeadingBlanks(str)
+             this%obs_note_arr(i) = TRIM(str)
+             line1 = line_(3:)
+          ELSE
+             this%obs_note_arr(i) = " "
+             line1 = line_
+          END IF
+
+          IF (line1(1:1) /= " ") THEN
+             DO j=0,34
+                IF (mpc_conv_table(j) == line1(1:1)) THEN
+                   EXIT
+                END IF
+             END DO
+             CALL toInt(line1(2:5), nr, error)
+             nr = j*10000 + nr
+          ELSE
+             nr = 0
+          END IF
+          IF (line1(13:13) == "*") THEN
+             discovery = .TRUE.
+          ELSE
+             discovery = .FALSE.
+          END IF
+          CALL toInt(line1(16:19), year, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (5).", 1)
+             RETURN
+          END IF
+          CALL toInt(line1(21:22), month, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (10).", 1)
+             RETURN
+          END IF
+          CALL toReal(line1(24:32), day, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (15).", 1)
+             RETURN
+          END IF
+          CALL toInt(line1(33:34), hour, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (20).", 1)
+             RETURN
+          END IF
+          CALL toInt(line1(36:37), min, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (25).", 1)
+             RETURN
+          END IF
+          CALL toReal(line1(39:44), sec, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (30).", 1)
+             RETURN
+          END IF
+          CALL toInt(line1(46:47), deg, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (35).", 1)
+             RETURN
+          END IF
+          CALL toInt(line1(49:50), arcmin, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (40).", 1)
+             RETURN
+          END IF
+          CALL toReal(line1(52:56), arcsec, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (45).", 1)
+             RETURN
+          END IF
+          IF (LEN_TRIM(line1(66:70)) /= 0) THEN
+             CALL toReal(line1(66:70), mag, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (50).", 1)
+                RETURN
+             END IF
+          ELSE
+             mag = 99.9_bp
+          END IF
+
+          ! R.A. and Dec. + epoch:
+          !
+          ! The timescale used by MPC prior to year 1972 is UT1 and since
+          ! then UTC has been used:  
+          IF (year < 1972) THEN
+             timescale = "UT1"
+          ELSE
+             timescale = "UTC"
+          END IF
+          ! Create epoch object:
+          CALL NEW(t, year, month, day, timescale)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (35)", 1)
+             RETURN
+          END IF
+          IF (line1(45:45) == "-" .AND. deg /= 0) THEN
+             deg = -1 * deg
+          ELSE IF (line1(45:45) == "-" .AND. deg == 0 .AND. arcmin /= 0) THEN
+             arcmin = -1 * arcmin
+          ELSE IF (line1(45:45) == "-" .AND. deg == 0 .AND. arcmin == 0) THEN
+             arcsec = -1.0_bp * arcsec
+          END IF
+          ! Create observation object containing R.A. and Dec. + epoch:
+          CALL NEW(obs_scoord, hour, min, sec, deg, arcmin, arcsec, t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (40)", 1)
+             RETURN
+          END IF
+          IF (PRESENT(stdev)) THEN
+             stdev_ = stdev
+          ELSE
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Standard deviation for MPC format must be explicitly given.", 1)             
+             RETURN
+          END IF
+          covariance = 0.0_bp
+          covariance(2,2) = stdev_(2)**2.0_bp
+          covariance(3,3) = stdev_(3)**2.0_bp
+
+          ! Compute the heliocentric position of the observer at epoch t:
+          obsy_code = " "
+          obsy_code(1:3) = line1(78:80)
+          SELECT CASE (obsy_code(1:3))
+          CASE (" -3")
+             obsy_code = "500"
+          END SELECT
+          obsy = getObservatory(obsies, TRIM(obsy_code))
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (45)", 1)
+             RETURN
+          END IF
+
+          ! Change old type descriptions to new ones
+          SELECT CASE (line1(15:15))
+          CASE ("c", " ")
+             line1(15:15) = "C"
+          END SELECT
+
+          designation = line1(6:12)
+!!$          CALL MPCDesToMPC3Des(designation)
+!!$          IF (error) THEN
+!!$             CALL errorMessage("Observations / readObservationFile", &
+!!$                  "TRACE BACK (50)", 1)
+!!$             RETURN
+!!$          END IF
+
+          ! Create observation object:
+          CALL NULLIFY(this%obs_arr(i))
+          SELECT CASE (line1(15:15))
+          CASE ("S")
+             READ(getUnit(obsf), "(A80)", iostat=err) line2
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Error while reading satellite coordinates from file.", 1)
+                RETURN
+             END IF
+             CALL toReal(line2(36:46), position(1), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (55).", 1)
+                RETURN
+             END IF
+             IF (line2(35:35) == "-") THEN
+                position(1) = -1.0_bp*position(1)
+             END IF
+             CALL toReal(line2(48:58), position(2), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (60).", 1)
+                RETURN
+             END IF
+             IF (line2(47:47) == "-") THEN
+                position(2) = -1.0_bp*position(2)
+             END IF
+             CALL toReal(line2(60:70), position(3), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (50).", 1)
+                RETURN
+             END IF
+             IF (line2(59:59) == "-") THEN
+                position(3) = -1.0_bp*position(3)
+             END IF
+             SELECT CASE (line2(33:33))
+             CASE ("1", "2")
+                ! 
+                IF (line2(33:33) == "1") THEN
+                   coord_unit = 1
+                   position(1:3) = position(1:3)/km_au
+                ELSE
+                   coord_unit = 2
+                END IF
+                geocenter_ccoord = getObservatoryCCoord(obsies, "500", t)
+                CALL rotateToEquatorial(geocenter_ccoord)
+                coordinates = getCoordinates(geocenter_ccoord)
+                coordinates(1:3) = coordinates(1:3) + position(1:3)
+                CALL NEW(obsy_ccoord, coordinates, "equatorial", t)
+                coordinates = 0.0_bp
+                coordinates(1:3) = position(1:3)
+                CALL NEW(satellite_ccoord, coordinates, "equatorial", t)
+             CASE ("3")
+                coordinates = 0.0_bp
+                coordinates(1:3) = position(1:3)
+                CALL NEW(obsy_ccoord, coordinates, "ecliptic", t)
+                CALL rotateToEquatorial(obsy_ccoord)
+                geocenter_ccoord = getObservatoryCCoord(obsies, "500", t)
+                CALL rotateToEcliptic(geocenter_ccoord)
+                coordinates = getCoordinates(geocenter_ccoord)
+                coordinates(1:3) = position(1:3) - coordinates(1:3)
+                CALL NEW(satellite_ccoord, coordinates, "ecliptic", t)
+                CALL rotateToEquatorial(satellite_ccoord)
+                coord_unit = 2
+             END SELECT
+             CALL NEW(this%obs_arr(i), nr, designation, discovery, &
+                  line1(14:14), line1(15:15), obs_scoord, covariance, &
+                  obs_mask, mag, -1.0_bp, line1(71:71), -1.0_bp, &
+                  obsy, obsy_ccoord, &
+                  satellite_ccoord=satellite_ccoord, coord_unit=coord_unit)
+          CASE default
+             obsy_ccoord = getObservatoryCCoord(obsies, obsy_code, t)
+             IF (PRESENT(orb_sim)) THEN
+                CALL NULLIFY(obs_scoord)
+                CALL getEphemeris(orb_sim, obsy_ccoord, obs_scoord)
+                mean = 0.0_bp
+                CALL addMultinormalDeviate(obs_scoord, mean, covariance)
+                this%obs_note_arr(i) = "S"
+             END IF
+             CALL NEW(this%obs_arr(i), number=nr, &
+                  designation=designation, discovery=discovery, &
+                  note1=line1(14:14), note2=line1(15:15), &
+                  obs_scoord=obs_scoord, covariance=covariance, &
+                  obs_mask=obs_mask, mag=mag, filter=line1(71:71), &
+                  obsy=obsy, obsy_ccoord=obsy_ccoord)
+          END SELECT
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (55)", 1)
+             RETURN
+          END IF
+
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(t)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(geocenter_ccoord)
+          CALL NULLIFY(obsy_ccoord)
+          CALL NULLIFY(satellite_ccoord)
+
+       END DO
+
+    CASE ("mpc2") ! Minor Planet Center new format (20060601->)
+
+       obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+       iobs = 0
+       obsloop: DO
+
+          records = " "
+          irecord = 0
+          recordloop: DO
+             record = " "
+             READ(getUnit(obsf), "(A132)", iostat=err) record
+             IF (err > 0) THEN ! error
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Error while reading observations from file: " // TRIM(fname), 1)
+                RETURN
+             ELSE IF (err < 0 .AND. irecord > 0) THEN ! problematic end-of-file
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Observation file " // TRIM(fname) // " ended abruptly.", 1)
+                RETURN
+             ELSE IF (err < 0 .AND. irecord == 0) THEN ! end-of-file
+                EXIT obsloop
+             END IF
+             ! If the line is empty or marked with "#", read the next line:
+             IF (LEN_TRIM(record) == 0 .OR. record(1:1) == "#") THEN
+                CYCLE recordloop
+             END IF
+             irecord = irecord + 1
+             IF (irecord /= 1 .AND. (record(17:17) == "1" .OR. record(17:17) == "A")) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Records missing from observation file.", 1)
+                RETURN
+             END IF
+             IF (irecord > 5) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "End-of-record sign missing from observation record.", 1)
+                RETURN
+             END IF
+             IF (record(17:17) == "1") iobs = iobs + 1
+             records(irecord) = record 
+             IF (records(irecord)(18:18) == "+") EXIT ! all available records for this observation read  
+          END DO recordloop
+
+          IF (info_verb >= 4) THEN
+             DO irecord=1,5
+                IF (LEN_TRIM(records(irecord)) /= 0) WRITE(stdout,"(A132)") records(irecord)
+             END DO
+          END IF
+
+          CALL toInt(records(1)(1:7), nr, error)
+
+          IF (records(1)(18:18) == "*") THEN
+             discovery = .TRUE.
+          ELSE
+             discovery = .FALSE.
+          END IF
+          CALL toInt(records(1)(20:23), year, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (5).", 1)
+             RETURN
+          END IF
+          CALL toInt(records(1)(25:26), month, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (10).", 1)
+             RETURN
+          END IF
+          CALL toReal(records(1)(28:40), day, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (15).", 1)
+             RETURN
+          END IF
+          ! Create epoch object:
+          ! The timescale used by MPC prior to year 1972 is UT1 and since
+          ! then UTC has been used:  
+          IF (year < 1972) THEN
+             timescale = "UT1"
+          ELSE
+             timescale = "UTC"
+          END IF
+          CALL NEW(t, year, month, day, timescale)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (60)", 1)
+             RETURN
+          END IF
+          IF (records(1)(43:43) == " ") THEN
+             CALL toInt(records(1)(41:42), hour, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (20).", 1)
+                RETURN
+             END IF
+             CALL toInt(records(1)(44:45), min, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (25).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(1)(47:52), sec, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (30).", 1)
+                RETURN
+             END IF
+             CALL toInt(records(1)(57:58), deg, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (35).", 1)
+                RETURN
+             END IF
+             CALL toInt(records(1)(60:61), arcmin, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (40).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(1)(63:67), arcsec, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (45).", 1)
+                RETURN
+             END IF
+             IF (records(1)(56:56) == "-" .AND. deg /= 0) THEN
+                deg = -1 * deg
+             ELSE IF (records(1)(56:56) == "-" .AND. deg == 0 .AND. arcmin /= 0) THEN
+                arcmin = -1 * arcmin
+             ELSE IF (records(1)(56:56) == "-" .AND. deg == 0 .AND. arcmin == 0) THEN
+                arcsec = -1.0_bp * arcsec
+             END IF
+             ! Create observation object containing R.A. and Dec. + epoch:
+             CALL NEW(obs_scoord, hour, min, sec, deg, arcmin, arcsec, t)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "TRACE BACK (65)", 1)
+                RETURN
+             END IF
+          ELSE
+             CALL toReal(records(1)(41:55), ra, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (50).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(1)(56:71), dec, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (55).", 1)
+                RETURN
+             END IF
+             ! Create observation object containing R.A. and Dec. + epoch:
+             CALL NEW(obs_scoord, longitude=ra, latitude=dec, t=t)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "TRACE BACK (70)", 1)
+                RETURN
+             END IF
+          END IF
+          IF (LEN_TRIM(records(1)(72:77)) /= 0) THEN
+             CALL toReal(records(1)(72:77), mag, error)
+          ELSE
+             mag = 99.9_bp
+          END IF
+
+          ! Uncertainties:
+          stdev_ = 0.0_bp
+          IF (PRESENT(stdev)) THEN
+             stdev_ = stdev
+             correlation = 0.0_bp
+          ELSE
+             IF (records(2)(43:43) == ".") THEN
+                CALL toReal(records(2)(41:46), stdev_(2), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (60).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(2)(48:53), stdev_(3), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (65).", 1)
+                   RETURN
+                END IF
+                stdev_ = stdev_*rad_asec
+             ELSE
+                CALL toReal(records(2)(41:41) // "." // &
+                     records(2)(42:48), stdev_(2), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (70).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(2)(49:49) // "." // &
+                     records(2)(50:56), stdev_(3), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (75).", 1)
+                   RETURN
+                END IF
+                ! Transform units to radians from 10**(-7) radians:
+                stdev_ = stdev_*0.0000001_bp
+             END IF
+             CALL toReal(records(2)(57:64), correlation, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (77).", 1)
+                RETURN
+             END IF
+          END IF
+          covariance = 0.0_bp
+          covariance(2,2) = stdev_(2)**2.0_bp
+          covariance(3,3) = stdev_(3)**2.0_bp
+          covariance(2,3) = correlation*stdev_(2)*stdev_(3)
+          covariance(3,2) = covariance(2,3)
+
+          designation = records(1)(8:16)
+          IF (converttonewformat .AND. LEN_TRIM(ADJUSTL(designation)) < 9) THEN
+             CALL MPCDesToMPC3Des(designation)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "TRACE BACK (75)", 1)
+                RETURN
+             END IF
+          END IF
+
+          ! Compute the heliocentric position of the observer at epoch t:
+          obsy_code = records(1)(129:132)
+          IF (obsy_code(1:1) == "0") THEN
+             obsy_code = obsy_code(2:4)
+             obsy_code(4:4) = " "
+          END IF
+          obsy = getObservatory(obsies, obsy_code)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (80)", 1)
+             RETURN
+          END IF
+
+          ! Create observation object:
+          CALL NULLIFY(this%obs_arr(iobs))
+          SELECT CASE (records(1)(19:19))
+          CASE (" ", "C", "A", "T", "M", "P")
+             obsy_ccoord = getObservatoryCCoord(obsies, obsy_code, t)
+             CALL NEW(this%obs_arr(iobs), number=nr, designation=designation, &
+                  discovery=discovery, note1=records(1)(124:124), &
+                  note2=records(1)(19:19), obs_scoord=obs_scoord, &
+                  covariance=covariance, obs_mask=obs_mask, &
+                  mag=mag, filter=records(1)(78:79), obsy=obsy, &
+                  obsy_ccoord=obsy_ccoord)
+          CASE ("S")
+             IF (LEN_TRIM(records(3)) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "No satellite coordinates available in observation file.", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(42:59), position(1), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (80).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(60:77), position(2), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (85).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(78:95), position(3), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (90).", 1)
+                RETURN
+             END IF
+             SELECT CASE (records(3)(41:41))
+             CASE ("0")
+                coord_unit = 1
+                position(1:3) = position(1:3)/km_au
+             CASE ("1")
+                coord_unit = 2
+             CASE default
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Unit type "" // records(3)(41:41) // "" not available.", 1)
+                RETURN
+             END SELECT
+             obsy_ccoord = getObservatoryCCoord(obsies, "500", t)
+             CALL rotateToEquatorial(obsy_ccoord)
+             coordinates = getCoordinates(obsy_ccoord)
+             CALL NULLIFY(obsy_ccoord)
+             coordinates(1:3) = coordinates(1:3) + position(1:3)
+             CALL NEW(obsy_ccoord, coordinates, "equatorial", t)
+             coordinates = 0.0_bp
+             coordinates(1:3) = position(1:3)
+             CALL NEW(satellite_ccoord, coordinates, "equatorial", t)
+             CALL NEW(this%obs_arr(iobs), number=nr, designation=designation, &
+                  discovery=discovery, note1=records(1)(124:124), &
+                  note2=records(1)(19:19), obs_scoord=obs_scoord, &
+                  covariance=covariance, obs_mask=obs_mask, &
+                  mag=mag, filter=records(1)(78:79), obsy=obsy, &
+                  obsy_ccoord=obsy_ccoord, satellite_ccoord=satellite_ccoord, &
+                  coord_unit=coord_unit)
+          CASE default
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "No such (" // records(1)(19:19) // ") option available.", 1)
+             IF (err_verb >= 1) THEN
+                WRITE(stderr,"(A)") records(1)
+             END IF
+             RETURN
+          END SELECT
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (85)", 1)
+             RETURN
+          END IF
+
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(t)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(geocenter_ccoord)
+          CALL NULLIFY(obsy_ccoord)
+          CALL NULLIFY(satellite_ccoord)
+
+       END DO obsloop
+
+       i = iobs
+
+    CASE ("mpc3","sor","vov","kep") ! Minor Planet Center new format (20060601->)
+
+       obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+       iobs = 0
+       obsloop_mpc3: DO
+
+          records = " "
+          irecord = 0
+          recordloop_mpc3: DO
+             READ(getUnit(obsf), "(A132)", iostat=err) record
+             IF (err > 0) THEN ! error
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Error while reading observations from file: " // TRIM(fname), 1)
+                RETURN
+             ELSE IF (err < 0 .AND. irecord > 0) THEN ! problematic end-of-file
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Observation file " // TRIM(fname) // " ended abruptly.", 1)
+                RETURN
+             ELSE IF (err < 0 .AND. irecord == 0) THEN ! end-of-file
+                EXIT obsloop_mpc3
+             END IF
+             ! If the line is empty or marked with "#", read the next line:
+             IF (LEN_TRIM(record) == 0 .OR. record(1:1) == "#" .OR. &
+                  record(7:7) == "X") THEN
+                records = " "
+                irecord = 0
+                CYCLE recordloop_mpc3
+             END IF
+             irecord = irecord + 1
+             IF (irecord /= 1 .AND. (record(19:19) == "1" .OR. record(19:19) == "A")) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Records missing from observation file.", 1)
+                RETURN
+             END IF
+             IF (irecord > 5) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "End-of-record sign missing from observation record.", 1)
+                RETURN
+             END IF
+             IF (record(19:19) == "1") THEN
+                iobs = iobs + 1
+             END IF
+             records(irecord) = record 
+             IF (records(irecord)(20:20) == "+") THEN
+                ! All available records for this observation read  
+                EXIT
+             END IF
+          END DO recordloop_mpc3
+
+          IF (info_verb >= 4) THEN
+             DO irecord=1,5
+                IF (LEN_TRIM(records(irecord)) /= 0) THEN
+                   WRITE(stdout,"(A132)") records(irecord)
+                END IF
+             END DO
+          END IF
+
+          nr = 0
+          SELECT CASE (records(1)(7:7))
+          CASE ("C", "P", "D", "X", "A")
+             CALL toInt(records(1)(1:6), nr, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string (" // records(1)(1:7) &
+                     // ") to number.", 1)
+                RETURN
+             END IF
+             designation = records(1)(7:16)
+          CASE default
+             CALL toInt(records(1)(1:7), nr, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string (" // records(1)(1:7) &
+                     // ") to number.", 1)
+                RETURN
+             END IF
+             designation = records(1)(8:16)
+          END SELECT
+          IF (records(1)(20:20) == "*") THEN
+             discovery = .TRUE.
+          ELSE
+             discovery = .FALSE.
+          END IF
+          CALL toInt(records(1)(22:25), year, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string (" // records(1)(22:25) &
+                  // ") to number.", 1)
+             RETURN
+          END IF
+          CALL toInt(records(1)(26:27), month, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (10).", 1)
+             RETURN
+          END IF
+          CALL toReal(records(1)(28:39), day, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (15).", 1)
+             RETURN
+          END IF
+          ! Create epoch object:
+          ! The timescale used by MPC prior to year 1972 is UT1 and since
+          ! then UTC has been used:  
+          IF (year < 1972) THEN
+             timescale = "UT1"
+          ELSE
+             timescale = "UTC"
+          END IF
+          CALL NEW(t, year, month, day, timescale)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (90)", 1)
+             RETURN
+          END IF
+          IF (records(1)(43:43) == " ") THEN
+             CALL toInt(records(1)(41:42), hour, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (20).", 1)
+                RETURN
+             END IF
+             IF (LEN_TRIM(records(1)(47:52)) == 0 .OR. records(1)(46:46) == ".") THEN
+                CALL toReal(records(1)(44:52), rmin, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (22).", 1)
+                   RETURN
+                END IF
+                min = FLOOR(rmin)
+                sec = 60.0_bp*(rmin-min)
+             ELSE
+                CALL toInt(records(1)(44:45), min, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (25).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(1)(47:52), sec, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (30).", 1)
+                   RETURN
+                END IF
+             END IF
+             CALL toInt(records(1)(57:58), deg, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (35).", 1)
+                RETURN
+             END IF
+             IF (LEN_TRIM(records(1)(63:67)) == 0 .OR. records(1)(62:62) == ".") THEN
+                CALL toReal(records(1)(60:67), rarcmin, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (32).", 1)
+                   RETURN
+                END IF
+                arcmin = FLOOR(rarcmin)
+                arcsec = 60.0_bp*(rarcmin-arcmin)
+             ELSE
+                CALL toInt(records(1)(60:61), arcmin, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (40).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(1)(63:67), arcsec, error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (45).", 1)
+                   RETURN
+                END IF
+             END IF
+             IF (records(1)(56:56) == "-" .AND. deg /= 0) THEN
+                deg = -1 * deg
+             ELSE IF (records(1)(56:56) == "-" .AND. deg == 0 .AND. arcmin /= 0) THEN
+                arcmin = -1 * arcmin
+             ELSE IF (records(1)(56:56) == "-" .AND. deg == 0 .AND. arcmin == 0) THEN
+                arcsec = -1.0_bp * arcsec
+             END IF
+             ! Create observation object containing R.A. and Dec. + epoch:
+             CALL NEW(obs_scoord, hour, min, sec, deg, arcmin, arcsec, t)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "TRACE BACK (95)", 1)
+                RETURN
+             END IF
+          ELSE
+             CALL toReal(records(1)(41:55), ra, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (50).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(1)(56:71), dec, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (55).", 1)
+                RETURN
+             END IF
+             ! Create observation object containing R.A. and Dec. + epoch:
+             CALL NEW(obs_scoord, longitude=ra, latitude=dec, t=t)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "TRACE BACK (100)", 1)
+                RETURN
+             END IF
+          END IF
+          IF (LEN_TRIM(records(1)(72:77)) /= 0) THEN
+             CALL toReal(records(1)(72:77), mag, error)
+          ELSE
+             mag = 99.9_bp
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number (57).", 1)
+             RETURN
+          END IF
+
+          ! Uncertainties:
+          stdev_ = 0.0_bp
+          IF (PRESENT(stdev)) THEN
+             stdev_ = stdev
+             correlation = 0.0_bp
+          ELSE
+             IF (records(2)(43:43) == ".") THEN
+                CALL toReal(records(2)(41:46), stdev_(2), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (60).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(2)(48:53), stdev_(3), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (65).", 1)
+                   RETURN
+                END IF
+                stdev_ = stdev_*rad_asec
+             ELSE
+                CALL toReal(records(2)(41:41) // "." // &
+                     records(2)(42:48), stdev_(2), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (70).", 1)
+                   RETURN
+                END IF
+                CALL toReal(records(2)(49:49) // "." // &
+                     records(2)(50:56), stdev_(3), error)
+                IF (error) THEN
+                   CALL errorMessage("Observations / readObservationFile", &
+                        "Could not convert string to number (75).", 1)
+                   RETURN
+                END IF
+                ! Transform units to radians from 10**(-7) radians:
+                stdev_ = stdev_*0.0000001_bp
+             END IF
+             CALL toReal(records(2)(57:64), correlation, error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (77).", 1)
+                RETURN
+             END IF
+          END IF
+          covariance = 0.0_bp
+          covariance(2,2) = stdev_(2)**2.0_bp
+          covariance(3,3) = stdev_(3)**2.0_bp
+          covariance(2,3) = correlation*stdev_(2)*stdev_(3)
+          covariance(3,2) = covariance(2,3)
+
+          ! Compute the heliocentric position of the observer at epoch t:
+          obsy_code = records(1)(129:132)
+          IF (obsy_code(1:1) == "0") THEN
+             obsy_code = obsy_code(2:4)
+             obsy_code(4:4) = " "
+          END IF
+          obsy = getObservatory(obsies, obsy_code)
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (105)", 1)
+             RETURN
+          END IF
+
+          ! Create observation object:
+          CALL NULLIFY(this%obs_arr(iobs))
+          SELECT CASE (records(1)(21:21))
+          CASE (" ", "C", "A", "T", "M", "P", "c")
+             obsy_ccoord = getObservatoryCCoord(obsies, obsy_code, t)
+             CALL NEW(this%obs_arr(iobs), number=nr, designation=designation, &
+                  discovery=discovery, note1=records(1)(124:124), &
+                  note2=records(1)(21:21), obs_scoord=obs_scoord, &
+                  covariance=covariance, obs_mask=obs_mask, &
+                  mag=mag, filter=records(1)(78:79), obsy=obsy, &
+                  obsy_ccoord=obsy_ccoord)
+          CASE ("S")
+             IF (LEN_TRIM(records(3)) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "No satellite coordinates available in observation file.", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(42:59), position(1), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (80).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(60:77), position(2), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (85).", 1)
+                RETURN
+             END IF
+             CALL toReal(records(3)(78:95), position(3), error)
+             IF (error) THEN
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Could not convert string to number (90).", 1)
+                RETURN
+             END IF
+             SELECT CASE (records(3)(41:41))
+             CASE ("0")
+                coord_unit = 1
+                position(1:3) = position(1:3)/km_au
+             CASE ("1")
+                coord_unit = 2
+             CASE default
+                error = .TRUE.
+                CALL errorMessage("Observations / readObservationFile", &
+                     "Unit type "" // records(3)(41:41) // "" not available.", 1)
+                RETURN
+             END SELECT
+             obsy_ccoord = getObservatoryCCoord(obsies, "500", t)
+             CALL rotateToEquatorial(obsy_ccoord)
+             coordinates = getCoordinates(obsy_ccoord)
+             CALL NULLIFY(obsy_ccoord)
+             coordinates(1:3) = coordinates(1:3) + position(1:3)
+             CALL NEW(obsy_ccoord, coordinates, "equatorial", t)
+             coordinates = 0.0_bp
+             coordinates(1:3) = position(1:3)
+             CALL NEW(satellite_ccoord, coordinates, "equatorial", t)
+             CALL NEW(this%obs_arr(iobs), number=nr, designation=designation, &
+                  discovery=discovery, note1=records(1)(124:124), &
+                  note2=records(1)(21:21), obs_scoord=obs_scoord, &
+                  covariance=covariance, obs_mask=obs_mask, &
+                  mag=mag, filter=records(1)(78:79), obsy=obsy, &
+                  obsy_ccoord=obsy_ccoord, satellite_ccoord=satellite_ccoord, &
+                  coord_unit=coord_unit)
+          CASE ("R")
+             iobs = iobs - 1
+          CASE default
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "No such (" // records(1)(21:21) // ") option available.", 1)
+             IF (err_verb >= 1) THEN
+                WRITE(stderr,"(A)") records(1)
+             END IF
+             RETURN
+          END SELECT
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "TRACE BACK (110)", 1)
+             RETURN
+          END IF
+
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(t)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(geocenter_ccoord)
+          CALL NULLIFY(obsy_ccoord)
+          CALL NULLIFY(satellite_ccoord)
+
+       END DO obsloop_mpc3
+
+       i = iobs
+
+    CASE ("gaia2")
+
+       ! Temporary solution while the dynamical model is unknown:
+       CALL NEW(orbfile,fname(1:indx) // "orb")
+       CALL OPEN(orbfile)
+       IF (error) THEN
+          CALL errorMessage("Observations / readObservationFile", &
+               "Could not open orbit file.", 1)
+          RETURN          
+       END IF
+       norb = getNrOfLines(orbfile)
+       DO i=1,2
+          READ(getUnit(orbfile),*) record
+          norb = norb - 1
+       END DO
+       ALLOCATE(element_arr(norb,10), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readObservationFile", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+       jd = 2456000.5_bp
+       CALL NEW(t0, jd-2400000.5_bp, "tdt")
+       DO i=1,norb
+          READ(getUnit(orbfile),*,iostat=err) element_arr(i,:), str
+          IF (err /= 0) THEN
+             WRITE(*,*) element_arr(i,:), str
+             STOP
+          END IF
+       END DO
+       CALL NULLIFY(orbfile)
+       element_arr(:,4:7) = element_arr(:,4:7)*rad_deg
+       obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+
+       ! Origin of observation dates: 1.0 Jan 2010 ( = JD 2455197.5 = MJD 55197.0)
+       mjd_utc = 55197.0_bp
+       i = 0
+       DO
+
+          READ(getUnit(obsf), "(A120)", iostat=err) record
+          IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Error while reading observations from file.", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          ELSE IF (err < 0) THEN ! end-of-file
+             EXIT
+          END IF
+
+          IF (info_verb >= 4) THEN
+             WRITE(stdout,"(A120)") record
+          END IF
+
+          ! If the line is empty or marked with "#", read the next line:
+          IF (LEN_TRIM(record) == 0 .OR. record(1:1) == "#") THEN
+             CYCLE
+          END IF
+
+          i = i + 1
+          IF (i == 1) THEN
+             discovery = .TRUE.
+          ELSE
+             discovery = .FALSE.
+          END IF
+          CALL toInt(record(1:6), nr, error)
+          ! Epoch of detection, in days, starting from 1.0 January 2010
+          ! (= 2455197.5):
+          CALL toReal(record(7:24), dt, error)
+          ! Ecliptic longitude - as seen by Gaia at the epoch of the
+          ! observation:
+          CALL toReal(record(25:40), ecl_lon, error)
+          ! Ecliptic latitude:
+          CALL toReal(record(41:56), ecl_lat, error)
+          ! Position angle of the ecliptic meridian (0 to 360 deg) .
+          ! Convention: (same as for double star) clockwise when seen
+          ! from outside the celestial sphere, and counterclockwise 
+          ! (= direct rotation) when seen from inside the celestial
+          ! sphere:
+          ! 
+          !                ^            /  Pole ecliptic
+          !                |          /
+          !    ____________|________/________
+          !    |           |      /
+          !    |           |angscan
+          !    |           |  /
+          !    |___________|/________________       scan circle(from outside celestial sphere).
+          !    |                                    FOV moving on the sphere from left to right
+          !    |                                    here angscan ~ +45 deg
+          !    |
+          !    |____________________________
+          ! Pole ecliptic  |
+          !     \          |
+          !    ___\________|________________
+          !    |    \      |
+          !    |    angscan
+          !    |        \  |
+          !    |__________\|_________________> scan (from inside the  celestial sphere). The
+          !    |                                 star transits from left to right.
+          !    |
+          !    |                               here angscan ~ +45 deg
+          !    |____________________________
+          !
+          !
+          CALL toReal(record(57:72), angscan, error)
+          ! Position uncertainty, in mas, in the along- and
+          ! across-scan directions, respectively. This should alway be
+          ! > 0:
+          CALL toReal(record(73:84), pos_unc_along, error)
+          IF (pos_unc_along == 0.0_bp) THEN
+             i = i - 1
+             CYCLE
+          END IF
+          CALL toReal(record(85:96), pos_unc_across, error)
+          IF (pos_unc_across == 0.0_bp) THEN
+             i = i - 1
+             CYCLE
+          END IF
+          ! Convert to radians:
+          pos_unc_along = pos_unc_along*0.001_bp*rad_asec
+          pos_unc_across = pos_unc_across*0.001_bp*rad_asec
+          ! Velocity uncertainty, in mas, in the along- and
+          ! across-scan directions, respectively. When = 0 it means
+          ! that the corresponding velocity cannot be determined (this
+          ! is very rare in the main belt, since velocity is always
+          ! low and the object remains in the CCD "windows" long
+          ! enough..).
+          CALL toReal(record(97:108), vel_unc_along, error)
+          IF (vel_unc_along == 0.0_bp) THEN
+             i = i - 1
+             CYCLE
+          END IF
+          CALL toReal(record(109:120), vel_unc_across, error)
+          IF (vel_unc_along == 0.0_bp) THEN
+             i = i - 1
+             CYCLE
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Observations / readObservationFile", &
+                  "Could not convert string to number on line:", 1)
+             IF (err_verb >= 1) WRITE(stderr,"(A)") TRIM(record)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+
+          ! True rotation angle is: 
+          ! direction of the scan w.r.t. equator = (direction of the scan
+          ! w.r.t. ecliptic pole) - (obliquity of the ecliptic)
+          rot_angle = angscan - eps
+          covariance = 0.0_bp
+          covariance(2,2) = (pos_unc_along*COS(rot_angle))**2.0_bp + &
+               (pos_unc_across*SIN(rot_angle))**2.0_bp
+          covariance(2,3) = (pos_unc_along**2.0_bp - pos_unc_across**2.0_bp)* &
+               COS(rot_angle)*SIN(rot_angle)
+          covariance(3,2) = (pos_unc_along**2.0_bp - pos_unc_across**2.0_bp)* &
+               COS(rot_angle)*SIN(rot_angle)
+          covariance(3,3) = (pos_unc_along*SIN(rot_angle))**2.0_bp + &
+               (pos_unc_across*COS(rot_angle))**2.0_bp
+
+          CALL NEW(t, mjd_utc + dt, "utc")
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK (115)", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+          obsy = getObservatory(obsies, "500")
+          IF (error) THEN
+             CALL errorMessage("Observations / readGaiaFile", &
+                  "TRACE BACK (120)", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+          obsy_ccoord = getObservatoryCCoord(obsies, "500", t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGaiaFile", &
+                  "TRACE BACK (125)", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+          ! As a temporary solution, generate positions based on given
+          ! orbital elements, while the dynamical model is uncertain:
+          DO j=1,norb
+             IF (nr == NINT(element_arr(j,1))) THEN
+                EXIT
+             END IF
+          END DO
+          CALL NEW(orb, element_arr(j,2:7), "keplerian", "ecliptic", t0)
+          ! Generate n-body observations:
+          !CALL setPropagationParameters(orb, dyn_model="n-body", &
+          !     integrator="gauss-radau", integration_step=1.0_bp)
+          !CALL setPropagationParameters(orb, dyn_model="n-body", &
+          !     integrator="bulirsch-stoer", integration_step=10.0_bp)
+          CALL getEphemeris(orb, obsy_ccoord, ephemeris)
+          CALL NULLIFY(orb)
+          ! Add Gaussian noise depending on the uncertainties:
+          mean = 0.0_bp
+          CALL addMultinormalDeviate(ephemeris, mean, covariance)
+          coordinates = getCoordinates(ephemeris)
+          CALL NULLIFY(ephemeris)
+          position = 0.0_bp
+          velocity = 0.0_bp
+          position(2:3) = coordinates(2:3)
+          CALL NEW(obs_scoord, position, velocity, "equatorial", t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK (130)", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+          CALL NULLIFY(this%obs_arr(i))
+          CALL NEW(this%obs_arr(i), number=nr, designation=" ", &
+               discovery=discovery, note1=" ", note2="C", &
+               obs_scoord=obs_scoord, covariance=covariance, &
+               obs_mask=obs_mask, mag=99.9_bp, filter=" ", &
+               obsy=obsy, obsy_ccoord=obsy_ccoord)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK (135)", 1)
+             DEALLOCATE(element_arr, stat=err)
+             RETURN
+          END IF
+
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(t)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(obsy_ccoord)
+
+       END DO
+
+       DEALLOCATE(element_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readObservationFile", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+
+    CASE ("elgb")
+
+       CALL readELGBFile(this, obsf, stdev)
+       i = getNumberOfObservations(this)
+
+    CASE default
+
+       error = .TRUE.
+       CALL errorMessage("Observations / readObservationFile", &
+            "Cannot recognize the format of the following file: " // TRIM(fname),1)
+
+    END SELECT
+
+    CALL NULLIFY(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readObservationFile", &
+            "TRACE BACK (140)", 1)
+       RETURN
+    END IF
+
+    IF (ASSOCIATED(this%obs_arr) .AND. i > 0) THEN
+       this%obs_arr => reallocate(this%obs_arr,i)
+    END IF
+    IF (ASSOCIATED(this%obs_note_arr) .AND. i > 0) THEN
+       this%obs_note_arr => reallocate(this%obs_note_arr,i)
+    END IF
+
+  END SUBROUTINE readObservationFile
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Intrisic routine that reads a file of elgb-format (used by Ted B.).
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE readELGBFile(this, elgb_file, stdev)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    TYPE (File), INTENT(in)            :: elgb_file
+    REAL(bp), DIMENSION(6), INTENT(in) :: stdev
+    TYPE (Observatories)               :: obsies
+    TYPE (Observatory)                 :: obsy
+    TYPE (Time)                        :: t
+    TYPE (SphericalCoordinates)        :: obs_scoord
+    TYPE (CartesianCoordinates)        :: obsy_ccoord, &
+         geocenter_ccoord, satellite_ccoord
+    CHARACTER(len=96)                  :: line1
+    CHARACTER(len=3)                   :: timescale, obsy_code
+    REAL(bp), DIMENSION(6,6)           :: covariance
+    REAL(bp)                           :: day, sec, arcsec, mag
+    INTEGER                            :: i, err, nr, year, &
+         month, hour, min, deg, arcmin, nlines
+    LOGICAL, DIMENSION(6)              :: obs_mask
+    LOGICAL                            :: discovery
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readELGBFile", &
+            "Astrometric observations (MPC) have already been initialized.", 1)
+       RETURN
+    END IF
+
+    nlines = getNrOfLines(elgb_file)
+    IF (error) THEN
+       CALL errorMessage("Observations / readELGBFile", &
+            "TRACE BACK 4", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(this%obs_arr(nlines), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readELGBFile", &
+            "Could not allocate memory for the observations.", 1)
+       RETURN
+    END IF
+
+    CALL NEW(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readELGBFile", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+
+    obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+
+    ! This is the file format (http://asteroid.lowell.edu/asteroid/loneos/public_obs.html):
+    ! to be read from the observations file (motions are ignored):
+    !
+    !         Date              R.A.                  Dec.          Mag.&Color
+    !  --------17------- --------13--------- ----------14---------- -----8----      
+    ! "(I4,1X,I2,2X,F8.5,2X,I2,1X,I2,1X,F6.3,2X,A1,I2,1X,I2,1X,F5.2,2X,F4.1,A1,
+    !
+    ! LONEOS Discovery  Obs.           LONEOS RA motion Dec motion
+    !   ID   Asterisk   Code  Detector Region  s/day      am/day
+    ! --9---  ----1---- --4-- ---3---- --6--- ---14---- ----6-----
+    ! 1X,A8,    A1,     1X,A3, 2X,A1,    A6,   7X,F7.1,   F6.2)"
+
+    i = 0
+    DO
+
+       READ(getUnit(elgb_file), "(A75)", iostat=err) line1
+       IF (err > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readELGBFile", &
+               "Error while reading observations from file.", 1)
+          RETURN
+       ELSE IF (err < 0) THEN ! end-of-file
+          EXIT
+       END IF
+
+       ! If the line is empty or marked with "#", read the next line:
+       IF (LEN_TRIM(line1) == 0 .OR. line1(1:1) == "#") THEN
+          CYCLE
+       END IF
+
+       i = i + 1
+       !       CALL toInt(line1(1:5), nr, error)
+       nr = 0
+       IF (line1(62:62) == "*") THEN
+          discovery = .TRUE.
+       ELSE
+          discovery = .FALSE.
+       END IF
+       CALL toInt(line1(1:4), year, error)
+       CALL toInt(line1(6:7), month, error)
+       CALL toReal(line1(10:17), day, error)
+       CALL toInt(line1(20:21), hour, error)
+       CALL toInt(line1(23:24), min, error)
+       CALL toReal(line1(26:31), sec, error)
+       CALL toInt(line1(35:36), deg, error)
+       CALL toInt(line1(38:39), arcmin, error)
+       CALL toReal(line1(41:45), arcsec, error)
+       IF (LEN_TRIM(line1(48:51)) /= 0) THEN
+          CALL toReal(line1(48:51), mag, error)
+       ELSE
+          mag = 99.9_bp
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Observations / readELGBFile", &
+               "Could not convert string to number.", 1)
+          RETURN
+       END IF
+
+       ! R.A. and Dec. + epoch:
+       !
+       ! The timescale used by MPC prior to year 1972 is UT1 and since
+       ! then UTC has been used:  
+       IF (year < 1972) THEN
+          timescale = "UT1"
+       ELSE
+          timescale = "UTC"
+       END IF
+       ! Create epoch object:
+       CALL NEW(t, year, month, day, timescale)
+       IF (error) THEN
+          CALL errorMessage("Observations / readELGBFile", &
+               "TRACE BACK 17", 1)
+          RETURN
+       END IF
+       IF (line1(34:34) == "-" .AND. deg /= 0) THEN
+          deg = -1 * deg
+       ELSE IF (line1(34:34) == "-" .AND. deg == 0 .AND. arcmin /= 0) THEN
+          arcmin = -1 * arcmin
+       ELSE IF (line1(34:34) == "-" .AND. deg == 0 .AND. arcmin == 0) THEN
+          arcsec = -1.0_bp * arcsec
+       END IF
+       ! Create observation object containing R.A. and Dec. + epoch:
+       CALL NEW(obs_scoord, hour, min, sec, deg, arcmin, arcsec, t)
+       IF (error) THEN
+          CALL errorMessage("Observations / readELGBFile", &
+               "TRACE BACK 18", 1)
+          RETURN
+       END IF
+       covariance = 0.0_bp
+       covariance(2,2) = stdev(2)**2.0_bp
+       covariance(3,3) = stdev(3)**2.0_bp
+
+       ! Compute the heliocentric position of the observer at epoch t:
+       obsy_code = line1(64:66)
+       SELECT CASE (obsy_code)
+       CASE (" -3")
+          obsy_code = "500"
+       END SELECT
+       obsy = getObservatory(obsies, obsy_code)
+       IF (error) THEN
+          CALL errorMessage("Observations / readELGBFile", &
+               "Could not convert observatory code string to integer.", 1)
+          RETURN
+       END IF
+
+       ! Create observation object:
+       CALL NULLIFY(this%obs_arr(i))
+       obsy_ccoord = getObservatoryCCoord(obsies, obsy_code, t)
+
+       CALL NEW(this%obs_arr(i), number=nr, &
+            designation=line1(54:61), discovery=discovery, & 
+            note1=" ", note2=line1(69:69), obs_scoord=obs_scoord, &
+            covariance=covariance, obs_mask=obs_mask, mag=mag, &
+            filter=line1(52:52), obsy=obsy, obsy_ccoord=obsy_ccoord)
+
+       IF (error) THEN
+          CALL errorMessage("Observations / readELGBFile", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+
+       CALL NULLIFY(obs_scoord)
+       CALL NULLIFY(t)
+       CALL NULLIFY(obsy)
+       CALL NULLIFY(geocenter_ccoord)
+       CALL NULLIFY(obsy_ccoord)
+       CALL NULLIFY(satellite_ccoord)
+
+    END DO
+
+    CALL NULLIFY(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readELGBFile", &
+            "TRACE BACK 21", 1)
+       RETURN
+    END IF
+
+    this%obs_arr => reallocate(this%obs_arr,i)
+
+  END SUBROUTINE readELGBFile
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE readGAIAFile(this, gaia_file)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)    :: this
+    TYPE (File), INTENT(in)               :: gaia_file
+    TYPE (Observatories)                  :: obsies
+    TYPE (Observatory)                    :: obsy
+    TYPE (Time)                           :: t
+    TYPE (SphericalCoordinates)           :: obs_scoord
+    TYPE (CartesianCoordinates)           :: obsy_ccoord
+    CHARACTER(len=93)                     :: line, frst_line
+    CHARACTER(len=14)                     :: empty_form, full_form
+    CHARACTER(len=13)                     :: designation
+    CHARACTER(len=5)                      :: form_, line_length, &
+         number, nobs_char
+    CHARACTER(len=3), PARAMETER           :: rec_length="14"
+    INTEGER, PARAMETER                    :: nrecords=17
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: stdevs
+    REAL(bp), DIMENSION(6,6)              :: covariance
+    REAL(bp), DIMENSION(:), ALLOCATABLE   :: dates, magnitudes, &
+         distances, longitudes, latitudes, rot_angles
+    REAL(bp), DIMENSION(3)                :: position, velocity
+    REAL(bp)                              :: mjd_utc
+    INTEGER                               :: i, err, nr, nlines, nobs, nobs_, len
+    LOGICAL, DIMENSION(6)                 :: obs_mask
+    LOGICAL                               :: discovery
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readGAIAFile", &
+            "This object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    nlines = getNrOfLines(gaia_file)
+    IF (error) THEN
+       CALL errorMessage("Observations / readGAIAFile", &
+            "TRACE BACK 2", 1)
+       RETURN
+    END IF
+
+    IF (MOD(nlines,nrecords) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / readGAIAFile", &
+            "Number of records not what's expected for GAIA data.", 1)
+       RETURN
+    END IF
+
+    CALL NEW(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readGAIAFile", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+
+    nobs = 0
+    DO
+
+       READ(getUnit(gaia_file), "(A36)", iostat=err) frst_line
+       IF (err > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 4", 1)
+          RETURN
+       ELSE IF (err < 0) THEN
+          EXIT
+       END IF
+
+       ! Maximum number of observations is assumed to be 9999
+       CALL toInt(frst_line(33:36), nobs_, error)
+       IF (error) THEN
+          CALL errorMessage("Observations / readGAIAFile", &
+               "Could not convert character string to integer (1).", 1)
+          RETURN       
+       END IF
+       CALL toInt(frst_line(11:15), nr, error)
+       IF (error) THEN
+          CALL errorMessage("Observations / readGAIAFile", &
+               "Could not convert character string to integer (2).", 1)
+          RETURN       
+       END IF
+       designation = frst_line(17:29)
+       number = frst_line(11:15)
+
+       nobs = nobs + nobs_
+       this%obs_arr => reallocate(this%obs_arr, nobs)
+       !IF (err /= 0) THEN
+       !   error = .TRUE.
+       !   CALL errorMessage("Observations / readGAIAFile", &
+       !        "Could not allocate memory for the observations.", 1)
+       !   RETURN
+       !END IF
+
+       ALLOCATE(dates(nobs_),magnitudes(nobs_),distances(nobs_),&
+            longitudes(nobs_),latitudes(nobs_),rot_angles(nobs_), &
+            stdevs(nobs_,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+
+       len = 10*nobs_+1
+       CALL toString(len, form_, error)
+       IF (error) THEN
+          CALL errorMessage("Observations / readGAIAFile", &
+               "Could not convert integer to character string.", 1)
+          RETURN       
+       END IF
+
+       line_length = ADJUSTL(form_)
+       empty_form = "(A"//TRIM(line_length)//")"
+
+       nobs_char = ADJUSTL(frst_line(33:36))
+       full_form = "("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".4)"
+
+       ! Which field of view
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 10", 1)
+          RETURN
+       END IF
+
+       ! Observation date
+       READ(getUnit(gaia_file), full_form, iostat=err) dates
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 15", 1)
+          RETURN
+       END IF
+
+       ! Transverse ordinate in degrees
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+
+       ! Apparent magnitudes
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".1)"
+       READ(getUnit(gaia_file), full_form, iostat=err) magnitudes
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 25", 1)
+          RETURN
+       END IF
+       WHERE (ABS(magnitudes) < 10.0_bp*EPSILON(magnitudes)) magnitudes = 99.9_bp
+
+       ! Angular diameter in mas
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 30", 1)
+          RETURN
+       END IF
+
+       ! Distance to earth in au
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".3)"
+       READ(getUnit(gaia_file), full_form, iostat=err) distances
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 35", 1)
+          RETURN
+       END IF
+
+       ! Radial velocity to earth in km/s
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 40", 1)
+          RETURN
+       END IF
+       ! Distance to sun in au   
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 45", 1)
+          RETURN
+       END IF
+       ! Phase angle in degrees
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 50", 1)
+          RETURN
+       END IF
+       ! Inertial speed along-scan in mas/s
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 55", 1)
+          RETURN
+       END IF
+       ! Inertial speed across-scan in mas/s
+       READ(getUnit(gaia_file), empty_form, iostat=err) line
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 60", 1)
+          RETURN
+       END IF
+
+       ! Orientation of the scan (deg)
+       !    READ(getUnit(gaia_file), empty_form, iostat=err) line
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".2)"
+       READ(getUnit(gaia_file), full_form, iostat=err) rot_angles
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 65", 1)
+          RETURN
+       END IF
+       rot_angles = rot_angles*rad_deg
+
+       ! Ecliptic longitude (deg)
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".9)"
+       READ(getUnit(gaia_file), full_form, iostat=err) longitudes
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 70", 1)
+          RETURN
+       END IF
+       longitudes = longitudes*rad_deg
+
+       ! Ecliptic latitude  (deg)
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".9)"
+       READ(getUnit(gaia_file), full_form, iostat=err) latitudes
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 75", 1)
+          RETURN
+       END IF
+       latitudes = latitudes*rad_deg
+
+       ! Along scan stdev (milli-as)
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".2)"
+       READ(getUnit(gaia_file), full_form, iostat=err) stdevs(:,1)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 80", 1)
+          RETURN
+       END IF
+       ! Across scan stdev (milli-as)
+       full_form="("//TRIM(nobs_char)//"F"//TRIM(rec_length)//".2)"
+       READ(getUnit(gaia_file), full_form, iostat=err) stdevs(:,2)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / readGAIAFile", &
+               "TRACE BACK 85", 1)
+          RETURN
+       END IF
+       stdevs = stdevs*1.0e-3_bp*rad_asec
+
+
+       ! True rotation angle is: 
+       ! direction of the scan w.r.t. equator = (direction of the scan
+       ! w.r.t. ecliptic pole) - (obliquity of the ecliptic)
+       rot_angles = rot_angles - eps
+
+       ! Do not include the distances
+       distances = 0.0_bp
+
+       obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+
+       DO i=1,nobs_
+          discovery = .FALSE.
+          ! Origin of dates: 3.5 Jan 2010, JD 2455200.d0
+          mjd_utc = 55199.5_bp
+          CALL NEW(t, mjd_utc+dates(i), "utc")
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK 90", 1)
+             RETURN
+          END IF
+          obsy = getObservatory(obsies, "500")
+          IF (error) THEN
+             CALL errorMessage("Observations / readGaiaFile", &
+                  "TRACE BACK 95", 1)
+             RETURN
+          END IF
+          obsy_ccoord = getObservatoryCCoord(obsies, "500", t)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGaiaFile", &
+                  "TRACE BACK 100", 1)
+             RETURN
+          END IF
+          ! Note: ECLIPTIC coordinates
+          position = (/ distances(i), longitudes(i), latitudes(i) /)
+          velocity = 0.0_bp
+          CALL NEW(obs_scoord, position, velocity, "ecliptic", t)
+          CALL rotateToEquatorial(obs_scoord)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK 105", 1)
+             RETURN
+          END IF
+
+          covariance = 0.0_bp
+          covariance(2,2) = (stdevs(i,1)*COS(rot_angles(i)))**2.0_bp + &
+               (stdevs(i,2)*SIN(rot_angles(i)))**2.0_bp
+          covariance(2,3) = (stdevs(i,1)**2.0_bp - stdevs(i,2)**2.0_bp)* &
+               COS(rot_angles(i))*SIN(rot_angles(i))
+          covariance(3,2) = (stdevs(i,1)**2.0_bp - stdevs(i,2)**2.0_bp)* &
+               COS(rot_angles(i))*SIN(rot_angles(i))
+          covariance(3,3) = (stdevs(i,1)*SIN(rot_angles(i)))**2.0_bp + &
+               (stdevs(i,2)*COS(rot_angles(i)))**2.0_bp
+
+          CALL NULLIFY(this%obs_arr(nobs-nobs_+i))
+          CALL NEW(this%obs_arr(nobs-nobs_+i), number=nr, &
+               designation=designation, discovery=discovery, & 
+               note1=" ", note2="C", obs_scoord=obs_scoord, &
+               covariance=covariance, obs_mask=obs_mask, &
+               mag=magnitudes(i), filter=" ", obsy=obsy, &
+               obsy_ccoord=obsy_ccoord)
+          IF (error) THEN
+             CALL errorMessage("Observations / readGAIAFile", &
+                  "TRACE BACK 110", 1)
+             RETURN
+          END IF
+
+          CALL NULLIFY(obs_scoord)
+          CALL NULLIFY(t)
+          CALL NULLIFY(obsy)
+          CALL NULLIFY(obsy_ccoord)
+
+       END DO
+
+       DEALLOCATE(dates, magnitudes, distances, longitudes, latitudes, &
+            rot_angles, stdevs, stat=err)
+
+    END DO
+
+    this%obs_arr => reallocate(this%obs_arr,nobs)
+    CALL NULLIFY(obsies)
+    IF (error) THEN
+       CALL errorMessage("Observations / readGaiaFile", &
+            "TRACE BACK 115", 1)
+       RETURN
+    END IF
+
+
+  END SUBROUTINE readGAIAFile
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Observations-objects and
+  !! copies the existing (not-nullified) data from the old array to
+  !! the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myobservations => reallocate(myobservations,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_a1_Obss(array,n)
+
+    IMPLICIT NONE
+    TYPE (Observations), DIMENSION(:), POINTER :: reallocate_a1_Obss, array
+    INTEGER, INTENT(in)                        :: n
+    INTEGER                                    :: i, nold, err, nexist
+
+    nexist = 0
+    nold = SIZE(array,dim=1)
+    ALLOCATE(reallocate_a1_Obss(n), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_a1_Obss => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    DO i=1, MIN(n,nold)
+       IF (.NOT.array(i)%is_initialized) THEN
+          CYCLE
+       END IF
+       nexist = nexist + 1
+       reallocate_a1_Obss(nexist) = copy(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_a1_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setCovarianceMatrices(this, covariance)
+
+    TYPE (Observations), INTENT(inout)   :: this
+    REAL(bp), DIMENSION(6,6), INTENT(in) :: covariance
+    INTEGER                              :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / setCovarianceMatrices", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+       CALL setCovarianceMatrix(this%obs_arr(i), covariance)
+       IF (error) THEN
+          CALL errorMessage("Observations / setCovarianceMatrices", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+    END DO
+
+  END SUBROUTINE setCovarianceMatrices
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setNumber_Obss(this, number)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout) :: this
+    INTEGER, INTENT(in)                :: number
+    INTEGER                            :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / setNumber", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,SIZE(this%obs_arr,dim=1)
+       CALL setNumber(this%obs_arr(i), number)
+       IF (error) THEN
+          CALL errorMessage("Observations / setNumber", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    END DO
+
+    this%nobjects = 0
+    CALL sortObservations(this)
+    IF (error) THEN
+       CALL errorMessage("Observations / setNumber", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setNumber_Obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Internal routine. Searches for different objects (different (1)
+  !! number or (2) designation) and updates the total number of 
+  !! observations. Updates the index vector, which is used to
+  !! sort the observations in order of ascending epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE sortObservations(this, primary_sort, force_full)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(inout)     :: this
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: primary_sort
+    LOGICAL, INTENT(in), OPTIONAL          :: force_full
+    TYPE (Time)                            :: t
+    CHARACTER(len=DESIGNATION_LEN)         :: id
+    CHARACTER(len=16)                      :: primarysort
+    REAL(bp), DIMENSION(:), ALLOCATABLE    :: tmp
+    REAL(bp)                               :: mjd_tdt
+    INTEGER                                :: i, iobs, iobj, number
+
+    id = " "
+    IF (this%nobjects == 0) THEN
+       ! Since the number of different objects is 0, 
+       ! all observations must be scanned:
+       this%nobs = 0
+    END IF
+
+    ! Force full sort if requested:
+    IF (PRESENT(force_full)) THEN
+       IF (force_full) THEN
+          this%nobjects = 0
+          this%nobs = 0
+       END IF
+    END IF
+
+    IF (PRESENT(primary_sort)) THEN
+       primarysort = primary_sort
+       CALL locase(primarysort, error)
+       IF (error) THEN
+          CALL errorMessage("Observations / sortObservations", &
+               "The primary sort string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       IF (primarysort /= "designation" .AND. &
+            primarysort /= "number") THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / sortObservations", &
+               "Cannot sort by " // TRIM(primarysort) // ".", 1)
+          RETURN
+       END IF
+    ELSE
+       ! Default:
+       primarysort = "number"
+    END IF
+
+    ! Find total number of different objects:
+    DO iobs=this%nobs+1, SIZE(this%obs_arr)
+
+       number = getNumber(this%obs_arr(iobs))
+       IF (error) THEN
+          CALL errorMessage("Observations / sortObservations", &
+               "TRACE BACK 1", 1)
+          RETURN
+       END IF
+
+       ! Use (1) number or (2) designation:
+       IF (number /= 0 .AND. primarysort == "number") THEN
+          CALL toString(number, id, error)
+          IF (error) THEN
+             CALL errorMessage("Observations / sortObservations", &
+                  "Could not convert integer to string.", 1)
+             RETURN
+          END IF
+          DO WHILE (LEN_TRIM(id) < 7)
+             id = "0" // TRIM(id)
+          END DO
+       ELSE
+          id = getDesignation(this%obs_arr(iobs))
+          IF (error) THEN
+             CALL errorMessage("Observations / sortObservations", &
+                  "TRACE BACK 2", 1)
+             RETURN
+          END IF
+       END IF
+
+       ! ...look for it among already registered objects and
+       ! exit when you find it or when you have searched through all... 
+       iobj = this%nobjects
+       DO WHILE (iobj>0)
+          IF (this%objects(iobj) == TRIM(id)) EXIT
+          iobj = iobj - 1
+       END DO
+
+       ! ...and if turns out that you did not find it, put it on the list:
+       IF (iobj == 0) THEN
+          this%nobjects = this%nobjects + 1
+          this%objects => reallocate(this%objects,this%nobjects)
+          this%objects(this%nobjects) = TRIM(id)
+       END IF
+
+    END DO
+
+    IF (ASSOCIATED(this%ind)) THEN
+       DEALLOCATE(this%ind)
+    END IF
+    ALLOCATE(this%ind(SIZE(this%obs_arr,dim=1)))
+    IF (ASSOCIATED(this%criteria)) THEN
+       ALLOCATE(tmp(SIZE(this%criteria,dim=1)))
+       tmp = this%criteria
+       DEALLOCATE(this%criteria)
+    END IF
+    ALLOCATE(this%criteria(SIZE(this%obs_arr,dim=1)))
+    IF (ALLOCATED(tmp)) THEN
+       this%criteria(1:SIZE(tmp)) = tmp
+       DEALLOCATE(tmp)
+    END IF
+
+    ! Update ascending epoch index vector:
+    DO i=this%nobs+1,SIZE(this%obs_arr)
+       t = getTime(this%obs_arr(i))
+       mjd_tdt = getMJD(t, "tdt")
+       IF (error) THEN
+          CALL errorMessage("Observations / sortObservations", &
+               "TRACE BACK 4", 1)
+          RETURN
+       END IF
+       this%criteria(i) = mjd_tdt
+       CALL NULLIFY(t)
+    END DO
+    CALL quicksort(this%criteria, this%ind, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / sortObservations", &
+            "Could not quicksort observations " // &
+            TRIM(errstr), 1)
+       RETURN
+    END IF
+
+    ! Update number of observations:
+    this%nobs = SIZE(this%obs_arr,dim=1)
+
+  END SUBROUTINE sortObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Writes the observations in specified format to the given logical unit.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE writeObservationFile(this, lu, frmt, number)
+
+    IMPLICIT NONE
+    TYPE (Observations), INTENT(in) :: this
+    CHARACTER(len=*)                :: frmt
+    INTEGER, INTENT(in)             :: lu         
+    INTEGER, INTENT(in), OPTIONAL   :: number
+    CHARACTER(len=OBS_RECORD_LEN), DIMENSION(:), POINTER :: records
+    CHARACTER(len=2)                :: note
+    INTEGER                         :: i, j, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / writeObservationFile", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%nobs == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observations / writeObservationFile", &
+            "Object does not contain any observations.", 1)
+       RETURN
+    END IF
+
+    DO i=1,this%nobs
+
+       ! Get formatted observation records:
+       IF (PRESENT(number)) THEN
+          records => getObservationRecords(this%obs_arr(this%ind(i)), TRIM(frmt), number=number)
+       ELSE
+          records => getObservationRecords(this%obs_arr(this%ind(i)), TRIM(frmt))
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Observations / writeObservationFile", &
+               "TRACE BACK 5", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+
+       ! Write a different portion of the records depending on the
+       ! observation format:
+       SELECT CASE (TRIM(frmt))
+       CASE ("mpc")
+          DO j=1,SIZE(records,dim=1)
+             IF (LEN_TRIM(this%obs_note_arr(this%ind(i))) == 0) THEN
+                WRITE(lu, "(A80)", iostat=err) records(j)(1:80)
+             ELSE IF (LEN_TRIM(this%obs_note_arr(this%ind(i))) /= 0 &
+                  .AND. j == 1) THEN
+                note = "!" // TRIM(this%obs_note_arr(this%ind(i)))
+                WRITE(lu, "(A82)", iostat=err) note // records(j)(1:80)
+             END IF
+          END DO
+       CASE ("mpc2")
+          DO j=1,SIZE(records,dim=1)
+             WRITE(lu, "(A132)", iostat=err) records(j)(1:132)
+          END DO
+       CASE ("mpc3")
+          DO j=1,SIZE(records,dim=1)
+             WRITE(lu, "(A132)", iostat=err) records(j)(1:132)
+          END DO
+       CASE ("elgb")
+          DO j=1,SIZE(records,dim=1)
+             WRITE(lu, "(A75)", iostat=err) records(j)(1:75)
+          END DO
+       CASE ("des")
+          DO j=1,SIZE(records,dim=1)
+             WRITE(lu, "(A)", iostat=err) TRIM(records(j)(:))
+          END DO
+       CASE default
+          error = .TRUE.
+          CALL errorMessage("Observations / writeObservationFile", &
+               "Unknown observation format: " // TRIM(frmt), 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END SELECT
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / writeObservationFile", &
+               "Error while writing records.", 1)
+          DEALLOCATE(records, stat=err)
+          RETURN
+       END IF
+
+       DEALLOCATE(records, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observations / writeObservationFile", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+
+    END DO
+
+  END SUBROUTINE writeObservationFile
+
+
+
+
+
+END MODULE Observations_cl
Index: trunk/mops/oorb/classes/Observatories_class.f90
===================================================================
--- trunk/mops/oorb/classes/Observatories_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Observatories_class.f90	(revision 34646)
@@ -0,0 +1,1439 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Type and routines for observatories.
+!! 
+!! @author  MG, JV
+!! @version 2012-01-09
+!!
+MODULE Observatories_cl
+
+  USE Base_cl
+  USE File_cl
+  USE Observatory_cl
+  USE Time_cl
+  USE CartesianCoordinates_cl
+
+  USE utilities
+  USE planetary_data
+  USE linal
+
+  IMPLICIT NONE
+  PRIVATE :: new_Obsies
+  PRIVATE :: new_Obsies_file
+  PRIVATE :: nullify_Obsies
+  PRIVATE :: copy_Obsies
+  PRIVATE :: exist_Obsies
+  PRIVATE :: getPosition_Obsies
+  PRIVATE :: getName_Obsies
+  PRIVATE :: getObservatoryCCoord_code
+  PRIVATE :: getObservatoryCCoord_obsy
+
+  TYPE Observatories
+     PRIVATE
+     TYPE (Observatory), DIMENSION(:), POINTER :: observatory_arr => NULL()
+     CHARACTER(len=FNAME_LEN)                  :: code_fname          =  ""
+     INTEGER                                   :: no_of_observatories =  0
+     LOGICAL                                   :: is_initialized      = .FALSE.
+  END TYPE Observatories
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_Obsies
+     MODULE PROCEDURE new_Obsies_file
+  END INTERFACE NEW
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_Obsies
+  END INTERFACE NULLIFY
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_Obsies
+  END INTERFACE copy
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_Obsies
+  END INTERFACE exist
+
+  INTERFACE getPosition
+     MODULE PROCEDURE getPosition_Obsies
+  END INTERFACE getPosition
+
+  INTERFACE getName
+     MODULE PROCEDURE getName_Obsies
+  END INTERFACE getName
+
+  INTERFACE getObservatory
+     MODULE PROCEDURE getObservatory_Obsies
+  END INTERFACE getObservatory
+
+  INTERFACE getObservatoryCCoord
+     MODULE PROCEDURE getObservatoryCCoord_code
+     MODULE PROCEDURE getObservatoryCCoord_obsy
+  END INTERFACE getObservatoryCCoord
+
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Default initialization routine. Reads the observatory data from
+  !! the file to which the parameter CODE_FNAME points.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Obsies(this)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(inout) :: this
+
+    CALL NEW(this, TRIM(OORB_DATA_DIR) // "/" &
+         // TRIM(CODE_FNAME))
+
+  END SUBROUTINE new_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads the observatory data from the given file.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Obsies_file(this, filename)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(inout) :: this
+    CHARACTER(len=*), INTENT(in)        :: filename
+    TYPE (File)                         :: code_file
+    CHARACTER(len=96)                   :: name, form
+    CHARACTER(len=OBSY_CODE_LEN)        :: code
+    REAL(bp), DIMENSION(3)              :: coordinates, position
+    INTEGER                             :: i, err, length
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    length = LEN_TRIM(filename)
+    IF (length /= 0 .AND. length <= FNAME_LEN) THEN
+       this%code_fname = TRIM(filename)
+    ELSE IF (length > FNAME_LEN) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / new", &
+            "Filename too long; adjust parameters.", 1)
+       RETURN
+    ELSE
+       this%code_fname = TRIM(CODE_FNAME)
+    END IF
+
+    CALL NEW(code_file, TRIM(this%code_fname))
+    IF (error) THEN
+       CALL errorMessage("Observatories / new", &
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+
+    CALL setActionRead(code_file)
+    CALL setStatusOld(code_file)
+    CALL OPEN(code_file)
+    IF (error) THEN
+       CALL errorMessage("Observatories / new", &
+            "TRACE BACK 4", 1)
+       RETURN
+    END IF
+
+    this%no_of_observatories = getNrOfLines(code_file)
+
+    ALLOCATE(this%observatory_arr(this%no_of_observatories), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / new", &
+            "Could not allocate memory for observatories.", 1)
+       RETURN
+    END IF
+
+    form = "(A3,1X,F9.5,F8.6,F9.6,A96)"
+    DO i=1, this%no_of_observatories
+
+       READ(getUnit(code_file), TRIM(form), iostat=err) code, coordinates, name
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / new", &
+               "Error while reading from observatory datafile.", 1)
+          RETURN
+       END IF
+
+       ! Make the transformation to Cartesian geocentric equatorial
+       ! coordinates in AUs (body-fixed coordinates):
+       coordinates(1) = coordinates(1)*rad_deg
+       position(1)    = r_earth*coordinates(2)*COS(coordinates(1))
+       position(2)    = r_earth*coordinates(2)*SIN(coordinates(1))
+       position(3)    = r_earth*coordinates(3)
+
+       CALL NEW(this%observatory_arr(i), code, name, position)
+       IF (error) THEN
+          CALL errorMessage("Observatories / new", &
+               "TRACE BACK 6", 1)
+          RETURN
+       END IF
+
+    END DO
+
+    CALL NULLIFY(code_file)
+    IF (error) THEN
+       CALL errorMessage("Observatories / new", &
+            "TRACE BACK 7", 1)
+       RETURN
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_Obsies_file
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_Obsies(this)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(inout) :: this
+    INTEGER :: i, err
+
+    IF (ASSOCIATED(this%observatory_arr)) THEN
+       DO i=1,SIZE(this%observatory_arr,dim=1)
+          CALL NULLIFY(this%observatory_arr(i))
+       END DO
+       DEALLOCATE(this%observatory_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / nullify", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+    this%no_of_observatories =  0
+    this%code_fname          =  ""
+    this%is_initialized      =  .FALSE.
+
+  END SUBROUTINE nullify_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION copy_Obsies(this)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    TYPE (Observatories)             :: copy_Obsies
+    INTEGER :: err, i, nobsies
+
+    nobsies = 0
+    IF (ASSOCIATED(this%observatory_arr)) THEN
+       nobsies = SIZE(this%observatory_arr,dim=1)
+       ALLOCATE(copy_Obsies%observatory_arr(nobsies), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / copy", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+       DO i=1,nobsies
+          copy_Obsies%observatory_arr(i) = &
+               copy(this%observatory_arr(i))
+       END DO
+    END IF
+    copy_Obsies%no_of_observatories = nobsies
+    copy_Obsies%observatory_arr     = this%observatory_arr
+    copy_Obsies%code_fname          = this%code_fname
+    copy_Obsies%is_initialized      = this%is_initialized
+
+  END FUNCTION copy_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of this object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_Obsies(this)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+
+    exist_Obsies = this%is_initialized
+
+  END FUNCTION exist_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the equation of the equinoxes (difference between
+  !! apparent sidereal time and mean sidereal time) in radians.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION equationOfEquinoxes(t)
+
+    IMPLICIT NONE
+    TYPE(Time), INTENT(inout) :: t
+    REAL(bp)                  :: mjd_tt, oblm, dpsi, deps
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / equationOfEquinoxes", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd_tt = getMJD(t, "TT")
+    oblm = meanObliquity(mjd_tt)
+    CALL getNutationAngles(t, dpsi, deps)
+    IF (error) THEN
+       CALL errorMessage("Observatories / equationOfEquinoxes", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    equationOfEquinoxes = rad_asec*dpsi*COS(oblm)
+
+  END FUNCTION equationOfEquinoxes
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns name of observatory based on the given observatory code.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=128) FUNCTION getName_Obsies(this, code)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    CHARACTER(len=*), INTENT(in)     :: code
+    CHARACTER(len=OBSY_CODE_LEN)     :: trial_code
+    INTEGER                          :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getName", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%no_of_observatories
+       trial_code = getCode(this%observatory_arr(i))
+       IF (TRIM(code) == TRIM(trial_code)) THEN
+          getName_Obsies = getName(this%observatory_arr(i))
+          RETURN
+       END IF
+    END DO
+
+    ! The matching code could not be found, which indicates it is not
+    ! included in the observatory code file:
+    error = .TRUE.
+    CALL errorMessage("Observatories / getName", &
+         "Code " // TRIM(code) // " does not refer to any observatory listed in " &
+         // this%code_fname, 1)
+
+  END FUNCTION getName_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns observatory object based on the given observatory code.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservatory_Obsies(this, code)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    CHARACTER(len=*), INTENT(in)     :: code
+    TYPE (Observatory)               :: getObservatory_Obsies
+    CHARACTER(len=OBSY_CODE_LEN)     :: trial_code
+    REAL(bp), DIMENSION(6)           :: position
+    INTEGER                          :: i, indx
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatory", &
+            "Object has not been initialized yet.", 1)
+       RETURN
+    END IF
+
+    indx = INDEX(code,"-")
+    IF (indx == 0) THEN
+       DO i=1, this%no_of_observatories
+          trial_code = getCode(this%observatory_arr(i))
+          IF (error) THEN
+             CALL errorMessage("Observatories / getObservatory", &
+                  "TRACE BACK (5)", 1)
+             RETURN
+          END IF
+          ! If the matching code is found, then 
+          ! collect the data and return:
+          IF (TRIM(code) == TRIM(trial_code)) THEN
+             getObservatory_Obsies = copy(this%observatory_arr(i))
+             IF (error) THEN
+                CALL errorMessage("Observatories / getObservatory", &
+                     "TRACE BACK (10)", 1)
+                CALL NULLIFY(getObservatory_Obsies)
+                RETURN
+             END IF
+             RETURN
+          END IF
+       END DO
+    ELSE
+       CALL toInt(code(indx+1:), i, error)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatory", &
+               "TRACE BACK (15)", 1)
+          CALL NULLIFY(getObservatory_Obsies)
+          RETURN
+       END IF
+       position = 0.0_bp
+       CALL NEW(getObservatory_Obsies, code, planetary_locations(i), position)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatory", &
+               "TRACE BACK (20)", 1)
+          CALL NULLIFY(getObservatory_Obsies)
+          RETURN
+       END IF
+       RETURN
+    END IF
+
+    ! The matching code could not be found, which indicates it is not
+    ! included in the observatory code file:
+    error = .TRUE.
+    CALL errorMessage("Observatories / getObservatory", &
+         "Code " // TRIM(code) // &
+         " does not refer to any observatory listed in " &
+         // this%code_fname, 1)
+
+  END FUNCTION getObservatory_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns heliocentric equatorial Cartesian coordinates for the
+  !! given observatory code and epoch.
+  !!
+  !! Returns error
+  !!
+  FUNCTION getObservatoryCCoord_code(this, code, t)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in)  :: this
+    CHARACTER(len=*), INTENT(in)      :: code
+    TYPE (Time), INTENT(in)           :: t
+    TYPE (CartesianCoordinates)       :: getObservatoryCCoord_code
+    TYPE (Time)                       :: t_
+    TYPE (CartesianCoordinates)       :: geocenter_ccoord, geocentric_obs_ccoord
+    REAL(bp), DIMENSION(:,:), POINTER :: coordinates
+    REAL(bp)                          :: mjd_tt
+    INTEGER                           :: err, indx, i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "t has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    t_ = copy(t)
+    indx = INDEX(code,"-")
+    IF (indx == 0) THEN
+       ! We are dealing with an Earth based observer or a satellite
+       ! with its coordinates given relative to the Earth.
+
+       ! Equatorial Cartesian coordinates for the Earth (geocenter):
+       mjd_tt = getMJD(t_, "TT")
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       coordinates => JPL_ephemeris(mjd_tt, 3, 11, error)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Could not get planetary ephemeris (5).", 1)
+          RETURN
+       END IF
+       CALL NEW(geocenter_ccoord, coordinates(1,:), "equatorial", copy(t_))
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       DEALLOCATE(coordinates, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+       ! Equatorial geocentric Cartesian state for the observatory
+       geocentric_obs_ccoord = getGeocentricObservatoryCCoord(this, code, t_)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       ! Equatorial heliocentric Cartesian state for the observatory
+       getObservatoryCCoord_code = copy(geocenter_ccoord + geocentric_obs_ccoord)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       CALL rotateToEquatorial(getObservatoryCCoord_code)
+       CALL NULLIFY(t_)
+       CALL NULLIFY(geocenter_ccoord)
+       CALL NULLIFY(geocentric_obs_ccoord)
+
+    ELSE
+       ! We are dealing with a planetocentric observer.
+
+       ! Equatorial Cartesian planetocentric coordinates:
+       mjd_tt = getMJD(t_, "TT")
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       CALL toInt(TRIM(code(indx+1:)), i, error)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Could not convert string to integer.", 1)
+          RETURN
+       END IF
+       IF (i < 1 .OR. i>11) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Observatory code invalid: " // TRIM(code(indx+1:)), 1)
+          RETURN
+       END IF
+       coordinates => JPL_ephemeris(mjd_tt, i, 11, error)
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Could not get planetary ephemeris (10).", 1)
+          RETURN
+       END IF
+       CALL NEW(getObservatoryCCoord_code, coordinates(1,:), "equatorial", copy(t_))
+       IF (error) THEN
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "TRACE BACK (30)", 1)
+          RETURN
+       END IF
+       DEALLOCATE(coordinates, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Observatories / getObservatoryCCoord", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+       CALL rotateToEquatorial(getObservatoryCCoord_code)
+       CALL NULLIFY(t_)
+
+    END IF
+
+  END FUNCTION getObservatoryCCoord_code
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns heliocentric equatorial Cartesian coordinates for the
+  !! given observatory and epoch.
+  !!
+  !! Returns error
+  !!
+  FUNCTION getObservatoryCCoord_obsy(this, obsy, t)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    TYPE (Observatory), INTENT(in)   :: obsy
+    TYPE (Time), INTENT(in)          :: t
+    TYPE (CartesianCoordinates)      :: getObservatoryCCoord_obsy
+    CHARACTER(len=OBSY_CODE_LEN)     :: code
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obsy)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "obsy has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "t has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    code = getCode(obsy)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    getObservatoryCCoord_obsy = getObservatoryCCoord(this, code, t)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getObservatoryCCoord", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getObservatoryCCoord_obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns geocentric equatorial Cartesian coordinates for the given
+  !! observatory code and epoch.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getGeocentricObservatoryCCoord(this, code, t)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    CHARACTER(len=*), INTENT(in)     :: code
+    TYPE (Time), INTENT(inout)       :: t
+
+    TYPE (CartesianCoordinates)      :: getGeocentricObservatoryCCoord
+    TYPE (Time)                      :: t_obs
+    ! Diurnal rotation matrix (transformation from body-fixed to
+    ! true-of-date frames):
+    REAL(bp), DIMENSION(3,3)         :: diurnal_matrix
+    ! Rotation matrix from true-of-date frame to the reference
+    ! system in which observations are given (i.e., for
+    ! nutation and precession):
+    REAL(bp), DIMENSION(3,3)         :: pn_matrix
+    REAL(bp), DIMENSION(3)           :: omega, bf_position, &
+         true_position, true_velocity, position, velocity
+    REAL(bp)                         :: epoch_obs, gast
+    CHARACTER(len=20)                :: frame_obs, refsys_obs, &
+         frame_true, refsys_true
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "t has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Reference system in which the observations are given
+    frame_obs = "equatorial"
+    refsys_obs = "mean"
+    epoch_obs = 51544.5_bp ! J2000.0
+    CALL NEW(t_obs, epoch_obs, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    ! True-of-date reference system
+    frame_true = "equatorial"
+    refsys_true = "true-of-date"
+
+    ! Earth angular velocity (rad/d)
+    omega(1:2) = 0.0_bp
+    omega(3) = two_pi*1.00273790934_bp
+
+    ! Greenwich Apparent Sidereal Time = Greenwich Mean Sidereal Time +
+    ! Equation of the Equinoxes
+    gast = getGMST(t) + equationOfEquinoxes(t)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    ! Diurnal rotation matrix (transformation from body-fixed to
+    ! true-of-date frames), neglecting polar motion
+    diurnal_matrix = rotationMatrix(-gast,3)
+
+    ! Coordinates of the observatory in the body-fixed frame
+    bf_position = getPosition(this, code)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+
+    ! Coordinates of the observatory in the true-of-date frame
+    true_position = MATMUL(diurnal_matrix, bf_position)
+
+    ! Observatory velocity in the true-of-date frame: V = OMEGA X R
+    true_velocity = cross_product(omega, true_position)
+
+    ! Rotation matrix from the true-of-date reference system
+    ! to the reference system of the observations. Notice that
+    ! the EPOCH of the true-of-date frame is the time at which
+    ! the observation is obtained: therefore this statement
+    ! must be within the loop on observations
+    pn_matrix = precessionAndNutationMatrix(frame_true, refsys_true, &
+         t, frame_obs, refsys_obs, t_obs)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+    ! Coordinates of the observatory in the frame of observations
+    position = MATMUL(pn_matrix, true_position)
+    velocity = MATMUL(pn_matrix, true_velocity)
+
+    CALL NEW(getGeocentricObservatoryCCoord, position, velocity, &
+         frame_true, t)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getGeocentricObservatoryCCoord", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+
+    CALL NULLIFY(t_obs)
+
+  END FUNCTION getGeocentricObservatoryCCoord
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian geocentric equatorial coordinates in AUs
+  !! (body-fixed coordinates).
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPosition_Obsies(this, code)
+
+    IMPLICIT NONE
+    TYPE (Observatories), INTENT(in) :: this
+    CHARACTER(len=*), INTENT(in)     :: code
+    REAL(bp), DIMENSION(3)           :: getPosition_Obsies
+    CHARACTER(len=OBSY_CODE_LEN)     :: trial_code
+    INTEGER                          :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getPosition", &
+            "Object has not been initialized yet.", 1)
+       RETURN
+    END IF
+
+    DO i=1, this%no_of_observatories
+       trial_code = getCode(this%observatory_arr(i))
+       ! If the matching code is found, then collect the data and return:
+       IF (TRIM(code) == TRIM(trial_code)) THEN
+          getPosition_Obsies = getPosition(this%observatory_arr(i))
+          RETURN
+       END IF
+    END DO
+
+    ! The matching code could not be found, which indicates it is not included in the
+    ! observatory code file:
+    error = .TRUE.
+    CALL errorMessage("Observatories / getPosition", &
+         "Code " // TRIM(code) // " does not refer to any observatory listed in " &
+         // this%code_fname, 1)
+
+  END FUNCTION getPosition_Obsies
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computation of the nutation matrix from nutation angles 
+  !!
+  !! Uses all 106 terms of the series for Nutation in Longitude and Obliquity
+  !! as listed in the Expl. Suppl. to AA, pp. 112-113.
+  !!
+  !! Note 1. No corrections (Herring 1987) as listed in p. 116 (presumable due to the
+  !! difference of the real Earth from the Wahr model). Effect?
+  !! Note 2. No planetary terms (Vondrak 1983), p. 118-119 with 85 terms. Should be used 
+  !! if mas accuracy is required.
+  !!
+  !! Based on f77 routine by Mario Carpino (nutn80.f).
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getNutationAngles(t0, dpsi, deps)
+
+    IMPLICIT NONE
+    TYPE(Time), INTENT(inout) :: t0
+    REAL(bp),INTENT(out)      :: dpsi, deps
+    REAL(bp) :: mjd_tt, dl, dp, df, dd, dn, t1
+    REAL(lp) :: l, n, cp, sp, cx, sx, cd, sd, cn, sn, cl, &
+         sl, cp2, sp2, cd2, sd2, cn2, sn2, cl2, sl2, ca, &
+         sa, cb, sb, cc, sc, cv, sv, ce, se, cf, sf, cg, &
+         sg, ch, sh, cj, sj, ck, sk, cm, sm, cq, sq, cr, &
+         sr, cs, ss, ct, st, cu, su, cw, sw, t,  &
+         t2, t3, p, x, d
+
+    IF (.NOT. exist(t0)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getNutationAngles", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd_tt = getMJD(t0, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / getNutationAngles", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    t1 = (mjd_tt-51544.5_bp)/36525.0_bp
+    t = REAL(t1,kind=lp)
+    t2 = t*t
+    t3 = t2*t
+
+    ! Fundamental arguments (IAU 1980, Expl.Suppl. to AA p. 114):
+    dl = ( 485866.733_bp +1717915922.633_bp*t1 +31.310*t2 +0.064*t3)*rad_asec
+    dp = (1287099.804_bp + 129596581.224_bp*t1 - 0.577*t2 -0.012*t3)*rad_asec
+    df = ( 335778.877_bp +1739527263.137_bp*t1 -13.257*t2 +0.011*t3)*rad_asec
+    dd = (1072261.307_bp +1602961601.328_bp*t1 - 6.891*t2 +0.019*t3)*rad_asec
+    dn = ( 450160.280_bp -   6962890.539_bp*t1 + 7.455*t2 +0.008*t3)*rad_asec
+    l = REAL(MOD(dl,two_pi),kind=lp)
+    p = REAL(MOD(dp,two_pi),kind=lp)
+    x = REAL(MOD(df,two_pi)*2.0_bp,kind=lp)
+    d = REAL(MOD(dd,two_pi),kind=lp)
+    n = REAL(MOD(dn,two_pi),kind=lp)
+    cl = COS(l)
+    sl = SIN(l)
+    cp = COS(p)
+    sp = SIN(p)
+    cx = COS(x)
+    sx = SIN(x)
+    cd = COS(d)
+    sd = SIN(d)
+    cn = COS(n)
+    sn = SIN(n)
+    cp2 = 2.0_lp*cp*cp - 1.0_lp
+    sp2 = 2.0_lp*sp*cp
+    cd2 = 2.0_lp*cd*cd - 1.0_lp
+    sd2 = 2.0_lp*sd*cd
+    cn2 = 2.0_lp*cn*cn - 1.0_lp
+    sn2 = 2.0_lp*sn*cn
+    cl2 = 2.0_lp*cl*cl - 1.0_lp
+    sl2 = 2.0_lp*sl*cl
+    ca = cx*cd2 +sx*sd2
+    sa = sx*cd2 -cx*sd2
+    cb = ca*cn -sa*sn
+    sb = sa*cn +ca*sn
+    cc = cb*cn -sb*sn
+    sc = sb*cn +cb*sn
+    cv = cx*cd2 -sx*sd2
+    sv = sx*cd2 +cx*sd2
+    ce = cv*cn -sv*sn
+    se = sv*cn +cv*sn
+    cf = ce*cn -se*sn
+    sf = se*cn +ce*sn
+    cg = cl*cd2 +sl*sd2
+    sg = sl*cd2 -cl*sd2
+    ch = cx*cn2 -sx*sn2
+    sh = sx*cn2 +cx*sn2
+    cj = ch*cl -sh*sl
+    sj = sh*cl +ch*sl
+    ck = cj*cl -sj*sl
+    sk = sj*cl +cj*sl
+    cm = cx*cl2 +sx*sl2
+    sm = sx*cl2 -cx*sl2
+    cq = cl*cd +sl*sd
+    sq = sl*cd -cl*sd
+    cr = 2.0_lp*cq*cq - 1.0_lp
+    sr = 2.0_lp*sq*cq
+    cs = cx*cn -sx*sn
+    ss = sx*cn +cx*sn
+    ct = cs*cl -ss*sl
+    st = ss*cl +cs*sl
+    cu = cf*cl +sf*sl
+    su = sf*cl -cf*sl
+    cw = cp*cg -sp*sg
+    sw = sp*cg +cp*sg
+
+    ! Series for dpsi
+    ! Terms 1-54:
+    dpsi = -(171996.0_lp+174.2_lp*t)*sn      +(2062.0_lp+0.2_lp*t)*sn2 &
+         +46.0_lp*(sm*cn+cm*sn)              -11.0_lp*sm &
+         -3.0_lp*(sm*cn2+cm*sn2)             -3.0_lp*(sq*cp-cq*sp) &
+         -2.0_lp*(sb*cp2-cb*sp2)             +(sn*cm-cn*sm) &
+         -(13187.0_lp+1.6_lp*t)*sc           +(1426.0_lp-3.4_lp*t)*sp &
+         -(517.0_lp-1.2_lp*t)*(sc*cp+cc*sp)  +(217.0_lp-0.5_lp*t)*(sc*cp-cc*sp) &
+         +(129.0_lp+0.1_lp*t)*sb             +48.0_lp*sr &
+         -22.0_lp*sa                         +(17.0_lp-0.1_lp*t)*sp2 &
+         -15.0_lp*(sp*cn+cp*sn)              -(16.0_lp-0.1_lp*t)*(sc*cp2+cc*sp2) &
+         -12.0_lp*(sn*cp-cn*sp)              -6.0_lp*(sn*cr-cn*sr) &
+         -5.0_lp*(sb*cp-cb*sp)               +4.0_lp*(sr*cn+cr*sn) &
+         +4.0_lp*(sb*cp+cb*sp)               -4.0_lp*sq &
+         +(sr*cp+cr*sp)                      +(sn*ca-cn*sa) &
+         -(sp*ca-cp*sa)                      +(sp*cn2+cp*sn2) &
+         +(sn*cq-cn*sq)                      -(sp*ca+cp*sa) &
+         -(2274.0_lp+0.2*t)*sh               +(712.0_lp+0.1_lp*t)*sl &
+         -(386.0_lp+0.4*t)*ss                -301.0_lp*sj &
+         -158.0_lp*sg                        +123.0_lp*(sh*cl-ch*sl) &
+         +63.0_lp*sd2                        +(63.0_lp+0.1_lp*t)*(sl*cn+cl*sn) &
+         -(58.0_lp+0.1_lp*t)*(sn*cl-cn*sl)   -59.0_lp*su &
+         -51.0_lp*st                         -38.0_lp*sf &
+         +29.0_lp*sl2                        +29.0_lp*(sc*cl+cc*sl) &
+         -31.0_lp*sk                         +26.0_lp*sx &
+         +21.0_lp*(ss*cl-cs*sl)              +16.0_lp*(sn*cg-cn*sg) &
+         -13.0_lp*(sn*cg+cn*sg)              -10.0_lp*(se*cl-ce*sl) &
+         -7.0_lp*(sg*cp+cg*sp)               +7.0_lp*(sh*cp+ch*sp) &
+         -7.0_lp*(sh*cp-ch*sp)               -8.0_lp*(sf*cl+cf*sl)
+    ! Terms 55-106
+    dpsi = dpsi +6.0_lp*(sl*cd2+cl*sd2)      +6.0_lp*(sc*cl2+cc*sl2) &
+         -6.0_lp*(sn*cd2+cn*sd2)             -7.0_lp*se &
+         +6.0_lp*(sb*cl+cb*sl)               -5.0_lp*(sn*cd2-cn*sd2) &
+         +5.0_lp*(sl*cp-cl*sp)               -5.0_lp*(ss*cl2+cs*sl2) &
+         -4.0_lp*(sp*cd2-cp*sd2)             +4.0_lp*(sl*cx-cl*sx) &
+         -4.0_lp*sd                          -3.0_lp*(sl*cp+cl*sp) &
+         +3.0_lp*(sl*cx+cl*sx)               -3.0_lp*(sj*cp-cj*sp) &
+         -3.0_lp*(su*cp-cu*sp)               -2.0_lp*(sn*cl2-cn*sl2) &
+         -3.0_lp*(sk*cl+ck*sl)               -3.0_lp*(sf*cp-cf*sp) &
+         +2.0_lp*(sj*cp+cj*sp)               -2.0_lp*(sb*cl-cb*sl) &
+         +2.0_lp*(sn*cl2+cn*sl2)             -2.0_lp*(sl*cn2+cl*sn2) &
+         +2.0_lp*(sl*cl2+cl*sl2)             +2.0_lp*(sh*cd+ch*sd) &
+         +(sn2*cl-cn2*sl)                    -(sg*cd2-cg*sd2) &
+         +(sf*cl2-cf*sl2)                    -2.0_lp*(su*cd2+cu*sd2) &
+         -(sr*cd2-cr*sd2)                    +(sw*ch+cw*sh) &
+         -(sl*ce+cl*se)                      -(sf*cr-cf*sr) &
+         +(su*ca+cu*sa)                      +(sg*cp-cg*sp) &
+         +(sb*cl2+cb*sl2)                    -(sf*cl2+cf*sl2) &
+         -(st*ca-ct*sa)                      +(sc*cx+cc*sx) &
+         +(sj*cr+cj*sr)                      -(sg*cx+cg*sx) &
+         +(sp*cs+cp*ss)                      +(sn*cw-cn*sw) &
+         -(sn*cx-cn*sx)                      -(sh*cd-ch*sd) &
+         -(sp*cd2+cp*sd2)                    -(sl*cv-cl*sv) &
+         -(ss*cp-cs*sp)                      -(sw*cn+cw*sn) &
+         -(sl*ca-cl*sa)                      +(sl2*cd2+cl2*sd2) &
+         -(sf*cd2+cf*sd2)                    +(sp*cd+cp*sd)
+
+    ! Series for deps:
+    deps = (92025.0_lp+8.9*t)*cn             -(895.0_lp-0.5*t)*cn2 &
+         -24.0_lp*(cm*cn-sm*sn)              +(cm*cn2-sm*sn2) &
+         +(cb*cp2+sb*sp2)                    +(5736.0_lp-3.1_lp*t)*cc &
+         +(54.0_lp-0.1_lp*t)*cp              +(224.0_lp-0.6*t)*(cc*cp-sc*sp) &
+         -(95.0_lp-0.3*t)*(cc*cp+sc*sp)      -70.0_lp*cb &
+         +cr                                 +9.0_lp*(cp*cn-sp*sn) &
+         +7.0_lp*(cc*cp2-sc*sp2)             +6.0_lp*(cn*cp+sn*sp) &
+         +3.0_lp*(cn*cr+sn*sr)               +3.0_lp*(cb*cp+sb*sp) &
+         -2.0_lp*(cr*cn-sr*sn)               -2.0_lp*(cb*cp-sb*sp) &
+         +(977.0_lp-0.5*t)*ch                -7.0_lp*cl &
+         +200.0_lp*cs                        +(129.0_lp-0.1_lp*t)*cj &
+         -cg                                 -53.0_lp*(ch*cl+sh*sl) &
+         -2.0_lp*cd2                         -33.0_lp*(cl*cn-sl*sn) &
+         +32.0_lp*(cn*cl+sn*sl)              +26.0_lp*cu &
+         +27.0_lp*ct                         +16.0_lp*cf &
+         -cl2                                -12.0_lp*(cc*cl-sc*sl)
+    deps = deps &
+         +13.0_lp*ck                         -cx &
+         -10.0_lp*(cs*cl+ss*sl)              -8.0_lp*(cn*cg+sn*sg) &
+         +7.0_lp*(cn*cg-sn*sg)               +5.0_lp*(ce*cl+se*sl) &
+         -3.0_lp*(ch*cp-sh*sp)               +3.0_lp*(ch*cp+sh*sp) &
+         +3.0_lp*(cf*cl-sf*sl)               -3.0_lp*(cc*cl2-sc*sl2) &
+         +3.0_lp*(cn*cd2-sn*sd2)             +3.0_lp*ce &
+         -3.0_lp*(cb*cl-sb*sl)               +3.0_lp*(cn*cd2+sn*sd2) &
+         +3.0_lp*(cs*cl2-ss*sl2)             +(cj*cp+sj*sp) &
+         +(cu*cp+su*sp)                      +(cn*cl2+sn*sl2) &
+         +(ck*cl-sk*sl)                      +(cf*cp+sf*sp) &
+         -(cj*cp-sj*sp)                      +(cb*cl+sb*sl) &
+         -(cn*cl2-sn*sl2)                    +(cl*cn2-sl*sn2) &
+         -(ch*cd-sh*sd)                      -(cn2*cl+sn2*sl) &
+         -(cf*cl2+sf*sl2)                    +(cu*cd2-su*sd2) &
+         -(cw*ch-sw*sh)                      +(cl*ce-sl*se) &
+         +(cf*cr+sf*sr)                      -(cb*cl2-sb*sl2) 
+
+    dpsi = dpsi*0.0001_bp
+    deps = deps*0.0001_bp
+
+  END SUBROUTINE getNutationAngles
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes nutation matrix according to Wahr (IAU-1980) theory.
+  !! The nutation matrix (RNUT) transforms mean coordinates into true
+  !! coordinates:
+  !!
+  !!     Xtrue = RNUT Xmean
+  !!
+  !! Use transpose to get from Xtrue to Xmean:
+  !!
+  !!     Xmean = transpose(RNUT) Xtrue
+  !!
+  !! Based on f77 routine by Mario Carpino (rnut80.f).
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getNutationMatrix(t)
+
+    IMPLICIT NONE
+
+    TYPE (Time), INTENT(inout) :: t
+    REAL(bp), DIMENSION(3,3) :: getNutationMatrix
+    REAL(bp), DIMENSION(3,3) :: r1, r2, r3, r23
+    REAL(bp) :: epsm, epst, dpsi, deps, mjd_tt
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getNutationMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd_tt = getMJD(t, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / getNutationMatrix", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    epsm = meanObliquity(mjd_tt)
+    CALL getNutationAngles(t, dpsi, deps)
+    IF (error) THEN
+       CALL errorMessage("Observatories / getNutationMatrix", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    dpsi = dpsi * rad_asec
+    epst = epsm + deps * rad_asec
+
+    r3 = rotationMatrix(  epsm, 1)
+    r2 = rotationMatrix( -dpsi, 3)
+    r1 = rotationMatrix( -epst, 1)
+
+    r23 = MATMUL(r2,r3)
+    getNutationMatrix = MATMUL(r1,r23)
+
+  END FUNCTION getNutationMatrix
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns precession matrix which transforms equatorial coordinates
+  !! from J2000.0 into mean equatorial coordinates at chosen epoch t:
+  !!
+  !!     Xepoch = RPREC Xj2000.0
+  !!
+  !! Use transpose to get from Xepoch to Xj2000.0:
+  !!
+  !!     Xj2000.0 = transpose(RPREC) Xepoch
+  !!
+  !! Based on f77 routine by Mario Carpino (prec.f)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPrecessionMatrix(t)
+
+    IMPLICIT NONE
+    TYPE(Time), INTENT(inout) :: t
+    REAL(bp), DIMENSION(3,3)  :: getPrecessionMatrix
+    REAL(bp), DIMENSION(3,3) :: r1, r2, r3, r12
+    REAL(bp) :: mjd_tt, cent, zeta, theta, z
+    REAL(bp), PARAMETER :: &
+                                ! Calcolo costanti usate (vedi Astronomical Almanac 1987, B18)
+                                ! Linear terms:
+         zed = 0.6406161_bp * rad_deg, &
+         zd  = 0.6406161_bp * rad_deg, &
+         thd = 0.5567530_bp * rad_deg, &
+                                ! Quadratical terms:
+         zedd= 0.0000839_bp * rad_deg, &
+         zdd = 0.0003041_bp * rad_deg, &
+         thdd = -0.0001185_bp * rad_deg, &
+                                ! Cubical terms:
+         zeddd = 0.0000050_bp * rad_deg, &
+         zddd = 0.0000051_bp * rad_deg, &
+         thddd = - 0.0000116_bp * rad_deg
+
+    IF (.NOT. exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / getPrecessionMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd_tt = getMJD(t, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / getPrecessionMatrix", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    ! Fundamental arguments:
+    cent  = ( mjd_tt - 51544.5_bp ) / 36525.0_bp ! centuries since J2000.0
+    zeta  = ( ( zeddd * cent + zedd ) * cent + zed ) * cent
+    z     = ( (  zddd * cent +  zdd ) * cent +  zd ) * cent
+    theta = ( ( thddd * cent + thdd ) * cent + thd ) * cent
+
+    r3 = rotationMatrix(- zeta, 3)
+    r2 = rotationMatrix( theta, 2)
+    r1 = rotationMatrix(-    z, 3)
+
+    ! Rotation matrix:
+    r12 = MATMUL(r1,r2)
+    getPrecessionMatrix = MATMUL(r12,r3)
+
+  END FUNCTION getPrecessionMatrix
+
+
+
+
+
+
+  !! *Description*:
+  !! 
+  !! Construction of rotation matrix for transformations between
+  !! different reference systems.
+  !!
+  !! INPUT:    frame1    -  starting frame ("ecliptical" or "equatorial")
+  !!           rsys1     -  starting reference system ("mean" or "true-of-date")
+  !!           t1        -  starting reference time (mjd, tt)
+  !!           frame2    -  final frame ("ecliptical" or "equatorial")
+  !!           rsys2     -  final reference system ("mean" or "true-of-date")
+  !!           t2        -  final reference time (mjd, tt)
+  !!
+  !! OUTPUT:   ROT(3,3)  -  rotation matrix giving the transformation from
+  !!                        starting to final reference systems:
+  !!                        x2 = ROT x1
+  !!
+  !! Returns error.
+  !!
+  !! Based on f77 routine by Mario Carpino (rotpn.f).
+  !!
+  FUNCTION precessionAndNutationMatrix(frame1, rsys1, t1, frame2, rsys2, t2)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout) :: t1, t2
+    CHARACTER(len=*), INTENT(in) :: frame1, rsys1, frame2, rsys2
+    REAL(bp), DIMENSION(3,3) :: precessionAndNutationMatrix
+    TYPE (Time) :: t_
+    CHARACTER(len=20) :: frame, rsys
+    REAL(bp), DIMENSION(3,3) :: rot, r
+    REAL(bp), PARAMETER :: eps = 1.0e-6_bp
+    REAL(bp) :: tt_, tt1, tt2, obl
+
+    IF (frame1 /= "ecliptical" .AND. frame1 /= "equatorial") THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown starting frame.", 1)
+       RETURN
+    END IF
+
+    IF (rsys1 /= "mean" .AND. rsys1 /= "true-of-date") THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown starting reference system.", 1)
+       RETURN
+    END IF
+
+    IF (frame2 /= "ecliptical" .AND. frame2 /= "equatorial") THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown final frame.", 1)
+       RETURN
+    END IF
+
+    IF (rsys2 /= "mean" .AND. rsys2 /= "true-of-date") THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown final reference system.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(t1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown starting epoch.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(t2)) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatories / precessionAndNutationMatrix", &
+            "Unkown final epoch.", 1)
+       RETURN
+    END IF
+
+    frame = frame1
+    rsys = rsys1
+    t_ = copy(t1)
+
+    tt1 = getMJD(t1, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / " // &
+            "precessionAndNutationMatrix", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    tt2 = getMJD(t2, "TT")
+    IF (error) THEN
+       CALL errorMessage("Observatories / " // &
+            "precessionAndNutationMatrix", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    tt_ = tt1
+
+    ! Initialization of the rotation matrix (equal to the unit matrix)
+    rot = identity_matrix(3)
+
+    IF (info_verb >= 5) THEN
+       CALL matrix_print(rot,stdout,errstr)
+       WRITE(stdout,*)
+    END IF
+
+    ! Building of the rotation matrix
+    DO
+
+       ! Different epochs
+       IF (ABS(tt_ - tt2) > eps) THEN
+
+          IF (frame == "ecliptical") THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,*) "Transformation of FRAME (ecliptical --> equatorial)"
+             END IF
+             obl = meanObliquity(tt_)
+             r = rotationMatrix(-obl,1)
+             rot = MATMUL(r,rot)
+             frame = "equatorial"
+             IF (error) THEN
+                CALL errorMessage("Observatories / " // &
+                     "precessionAndNutationMatrix", &
+                     "TRACE BACK (15)", 1)
+                RETURN
+             END IF
+          ELSE IF (frame == "equatorial") THEN
+             IF (TRIM(rsys) == "true-of-date") THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,*) "Transformation of RSYS (True-of-date --> mean)"
+                END IF
+                r = getNutationMatrix(t_)
+                IF (error) THEN
+                   CALL errorMessage("Observatories / " // &
+                        "precessionAndNutationMatrix", &
+                        "TRACE BACK (20)", 1)
+                   RETURN
+                END IF
+                rot = MATMUL(TRANSPOSE(r),rot)
+                rsys = "mean"
+             ELSE IF (rsys == "mean") THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,*) "Transformation of T (precession)"
+                END IF
+                r = getPrecessionMatrix(t_)
+                rot = MATMUL(TRANSPOSE(r),rot)
+                r = getPrecessionMatrix(t2)
+                rot = MATMUL(r,rot)
+                tt_ = tt2
+                t_ = copy(t2)
+                IF (error) THEN
+                   CALL errorMessage("Observatories / " // &
+                        "precessionAndNutationMatrix", &
+                        "TRACE BACK (25)", 1)
+                   RETURN
+                END IF
+             END IF
+          END IF
+          !
+          ! Already at the same epoch
+          !
+       ELSE IF (TRIM(rsys) /= TRIM(rsys2)) THEN
+
+          IF (TRIM(rsys) == "true-of-date") THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,*) "Transformation of RSYS (True-of-date --> mean)"
+             END IF
+             r = getNutationMatrix(t_)
+             IF (error) THEN
+                CALL errorMessage("Observatories / " // &
+                     "precessionAndNutationMatrix", &
+                     "TRACE BACK (30)", 1)
+                RETURN
+             END IF
+             rot = MATMUL(TRANSPOSE(r),rot)
+             rsys = "mean"
+          ELSE IF (rsys == "mean") THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,*) "Transformation of RSYS (Mean --> True-of-date)"
+             END IF
+             IF (TRIM(rsys2) == "true-of-date") THEN
+                r = getNutationMatrix(t_)
+                IF (error) THEN
+                   CALL errorMessage("Observatories / " // &
+                        "precessionAndNutationMatrix", &
+                        "TRACE BACK (35)", 1)
+                   RETURN
+                END IF
+                rot = MATMUL(r,rot)
+                rsys = rsys2
+             ELSE
+                error = .TRUE.
+                CALL errorMessage("Observatories / " // &
+                     "precessionAndNutationMatrix", &
+                     "Internal error (5).", 1)
+                RETURN
+             END IF
+          END IF
+
+       ELSE IF (frame /= frame2) THEN
+
+          IF (frame == "ecliptical") THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,*) "Transformation of FRAME (ecliptical --> equatorial)"
+             END IF
+             obl = meanObliquity(tt_)
+             r = rotationMatrix(-obl,1)
+             rot = MATMUL(r,rot)
+             frame = "equatorial"
+          ELSE IF (frame == "equatorial") THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,*) "Transformation of FRAME (equatorial --> ecliptical)"
+             END IF
+             IF (frame2 == "ecliptical") THEN
+                obl = meanObliquity(tt_)
+                r = rotationMatrix(obl,1)
+                rot = MATMUL(r,rot)
+                frame = "ecliptical"
+             ELSE
+                error = .TRUE.
+                CALL errorMessage("Observatories / " // &
+                     "precessionAndNutationMatrix", &
+                     "Internal error (10).", 1)
+                RETURN
+             END IF
+          END IF
+
+       ELSE
+
+          EXIT
+
+       END IF
+
+       IF (info_verb >= 5) THEN
+          CALL matrix_print(rot,stdout,errstr)
+          WRITE(stdout,*)
+       END IF
+
+    END DO
+
+    precessionAndNutationMatrix = rot
+
+  END FUNCTION precessionAndNutationMatrix
+
+
+
+
+END MODULE Observatories_cl
+
+
+
+
+
+
+
+
+
+
+
Index: trunk/mops/oorb/classes/Observatory_class.f90
===================================================================
--- trunk/mops/oorb/classes/Observatory_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Observatory_class.f90	(revision 34646)
@@ -0,0 +1,315 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Type and routines for an observatory.
+!!
+!! @author  MG
+!! @version 2008-08-12
+!!
+MODULE Observatory_cl
+
+  USE Base_cl
+
+  IMPLICIT NONE
+
+  PRIVATE :: new_Obsy
+  PRIVATE :: nullify_Obsy
+  PRIVATE :: copy_Obsy
+  PRIVATE :: exist_Obsy
+  PRIVATE :: equal_Obsy
+  PRIVATE :: getCode_Obsy
+  PRIVATE :: getName_Obsy
+  PRIVATE :: getPosition_Obsy
+
+  TYPE Observatory
+     PRIVATE
+     CHARACTER(len=96)            :: name           =  ""
+     CHARACTER(len=OBSY_CODE_LEN) :: code           =  ""
+     REAL(bp), DIMENSION(3)       :: position       =  0.0_bp
+     LOGICAL                      :: is_initialized = .FALSE.
+  END TYPE Observatory
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_Obsy
+  END INTERFACE
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_Obsy
+  END INTERFACE
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_Obsy
+  END INTERFACE
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_Obsy
+  END INTERFACE
+
+  INTERFACE equal
+     MODULE PROCEDURE equal_Obsy
+  END INTERFACE
+
+  INTERFACE getCode
+     MODULE PROCEDURE getCode_Obsy
+  END INTERFACE
+
+  INTERFACE getName
+     MODULE PROCEDURE getName_Obsy
+  END INTERFACE
+
+  INTERFACE getPosition
+     MODULE PROCEDURE getPosition_Obsy
+  END INTERFACE
+
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new object based on given information. The position
+  !! contains the body-fixed Cartesian geocentric equatorial
+  !! coordinates of the observatory given in AUs.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Obsy(this, code, name, position)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(out)    :: this
+    CHARACTER(len=*), INTENT(in)       :: code
+    CHARACTER(len=*), INTENT(in)       :: name
+    REAL(bp), DIMENSION(3), INTENT(in) :: position
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (LEN_TRIM(code) > OBSY_CODE_LEN) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / new", &
+            "Observatory code ("// TRIM(code) // &
+            ")too long.", 1)
+       RETURN
+    END IF
+
+    this%code           =  code
+    this%name           =  name
+    this%position       =  position
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(inout) :: this
+
+    this%code           =  ""
+    this%name           =  ""
+    this%position       =  0.0_bp
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+    TYPE (Observatory)             :: copy_Obsy
+
+    copy_Obsy%code           = this%code
+    copy_Obsy%name           = this%name
+    copy_Obsy%position       = this%position
+    copy_Obsy%is_initialized = this%is_initialized
+
+  END FUNCTION copy_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of this object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+
+    exist_Obsy = this%is_initialized
+
+  END FUNCTION exist_Obsy
+
+
+
+
+
+  LOGICAL FUNCTION equal_Obsy(this, that)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+    TYPE (Observatory), INTENT(in) :: that
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / equal", &
+            "1st object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / equal", &
+            "2nd object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Observatory code:
+    IF (.NOT.(this%code == that%code)) THEN
+       equal_Obsy = .FALSE.
+       RETURN
+    END IF
+
+    ! Position wrt. the geocenter:
+    IF (ANY(ABS(this%position - that%position) > EPSILON(this%position(1)))) THEN
+       equal_Obsy = .FALSE.
+       RETURN
+    END IF
+
+    ! Assuming that all of the above comparisons are true,
+    ! it can be concluded that the two objects are the same:
+    equal_Obsy = .TRUE.
+
+  END FUNCTION equal_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns observatory code as a character string.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=OBSY_CODE_LEN) FUNCTION getCode_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / getCode", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getCode_Obsy = this%code
+
+  END FUNCTION getCode_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns name of observatory as a character string.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=128) FUNCTION getName_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / getName", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getName_Obsy = this%name
+
+  END FUNCTION getName_Obsy
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns geocentric coordinates of the observatory.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPosition_Obsy(this)
+
+    IMPLICIT NONE
+    TYPE (Observatory), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)         :: getPosition_Obsy
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Observatory / getPosition", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getPosition_Obsy = this%position
+
+  END FUNCTION getPosition_Obsy
+
+
+
+
+
+END MODULE Observatory_cl
+
Index: trunk/mops/oorb/classes/Orbit_class.f90
===================================================================
--- trunk/mops/oorb/classes/Orbit_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Orbit_class.f90	(revision 34646)
@@ -0,0 +1,9821 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012   !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!
+!! Type and routines for orbits. Contains the most
+!! fundamental routines used in orbital inversion. 
+!!
+!! @see StochasticOrbit_class 
+!!
+!! @author  MG, TL, KM, JV 
+!! @version 2012-02-15
+!!
+MODULE Orbit_cl
+
+  USE Base_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  USE CartesianCoordinates_cl
+
+  USE utilities
+  USE planetary_data
+  USE integrators
+  USE linal
+  USE sort
+
+  IMPLICIT NONE
+  PRIVATE :: new_Orb
+  PRIVATE :: new_Orb_cartesian
+  PRIVATE :: new_Orb_spherical
+  PRIVATE :: new_Orb_elements
+  PRIVATE :: new_Orb_2point
+  PRIVATE :: nullify_Orb
+  PRIVATE :: copy_Orb
+  PRIVATE :: exist_Orb
+  PRIVATE :: GaussfgJacobian_Orb
+  PRIVATE :: getCartesianElements
+  PRIVATE :: getDelaunayElements
+  PRIVATE :: getEphemeris_Orb_single
+  PRIVATE :: getEphemeris_Orb_multiple
+  PRIVATE :: getEphemerides_Orb_single
+  PRIVATE :: getEphemerides_Orb_multiple
+  PRIVATE :: getFrame_Orb
+  PRIVATE :: getKeplerianElements
+  PRIVATE :: getParameters_Orb
+  PRIVATE :: getPhaseAngles_Orb
+  PRIVATE :: getPoincareElements
+  PRIVATE :: getPosition_Orb
+  PRIVATE :: getPhaseAngle_Orb
+  PRIVATE :: getSCoord_Orb
+  PRIVATE :: getStumpffFunctions
+  PRIVATE :: getTime_Orb
+  PRIVATE :: getVelocity_Orb
+  PRIVATE :: opposite_Orb
+  PRIVATE :: propagate_Orb_single
+  PRIVATE :: propagate_Orb_multiple
+  PRIVATE :: reallocate_Orb
+  PRIVATE :: reallocate_Orb_1
+  PRIVATE :: reallocate_Orb_2
+  PRIVATE :: rotateToEcliptic_Orb
+  PRIVATE :: rotateToEquatorial_Orb
+  PRIVATE :: estimateCosDf
+  PRIVATE :: setParameters_Orb
+  PRIVATE :: solveKeplerEquation_stumpff
+  PRIVATE :: solveKeplerEquation_newton
+  PRIVATE :: toCartesian_Orb
+  PRIVATE :: toCometary_Orb
+  PRIVATE :: toKeplerian_Orb
+
+  TYPE Orbit
+
+     !     PRIVATE
+     TYPE (Time)                         :: t
+     CHARACTER(len=FRAME_LEN)            :: frame                = "equatorial"
+     CHARACTER(len=ELEMENT_TYPE_LEN)     :: element_type         = "cartesian"
+     REAL(bp), DIMENSION(6)              :: elements
+     LOGICAL                             :: is_initialized       = .FALSE.
+     ! Central body, default is Sun (for body id's, see module planetary_data)
+     INTEGER                             :: central_body         = 11
+     ! Parameters for propagation:
+     CHARACTER(len=DYN_MODEL_LEN)        :: dyn_model_prm        = "2-body"
+     CHARACTER(len=INTEGRATOR_LEN)       :: integrator_prm       = "bulirsch-stoer"
+     REAL(bp), DIMENSION(:,:), POINTER   :: additional_perturbers => NULL() ! (car equ + mjdtt + mass)
+     REAL(bp), DIMENSION(6)              :: finite_diff_prm      = -1.0_bp
+     REAL(bp)                            :: integration_step_prm = 5.0_bp 
+     LOGICAL, DIMENSION(10)              :: perturbers_prm       = .FALSE.
+     ! Mass of the asteroid in solar masses (M_sol). A negative value
+     ! indicates that this orbit is integrated as a test particle, ie,
+     ! it has no effect on the orbits of other objects. Default is -1.
+     REAL(bp)                            :: mass_prm             = -1.0_bp
+
+  END TYPE Orbit
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_Orb
+     MODULE PROCEDURE new_Orb_cartesian
+     MODULE PROCEDURE new_Orb_spherical
+     MODULE PROCEDURE new_Orb_elements
+     MODULE PROCEDURE new_Orb_2point
+  END INTERFACE NEW
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_Orb
+  END INTERFACE NULLIFY
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_Orb
+  END INTERFACE copy
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_Orb
+  END INTERFACE exist
+
+  INTERFACE getApoapsisDistance
+     MODULE PROCEDURE getApoapsisDistance_Orb
+  END INTERFACE getApoapsisDistance
+
+  INTERFACE getCCoord
+     MODULE PROCEDURE getCCoord_Orb
+  END INTERFACE getCCoord
+
+  INTERFACE getFrame
+     MODULE PROCEDURE getFrame_Orb
+  END INTERFACE getFrame
+
+  INTERFACE getJacobiConstants
+     MODULE PROCEDURE getJacobiConstants_Orb
+  END INTERFACE getJacobiConstants
+
+  INTERFACE getParameters
+     MODULE PROCEDURE getParameters_Orb
+  END INTERFACE getParameters
+
+  INTERFACE getPeriapsisDistance
+     MODULE PROCEDURE getPeriapsisDistance_Orb
+  END INTERFACE getPeriapsisDistance
+
+  INTERFACE getPhaseAngle
+     MODULE PROCEDURE getPhaseAngle_Orb
+  END INTERFACE getPhaseAngle
+
+  INTERFACE getPhaseAngles
+     MODULE PROCEDURE getPhaseAngles_Orb
+  END INTERFACE getPhaseAngles
+
+  INTERFACE getPosition
+     MODULE PROCEDURE getPosition_Orb
+  END INTERFACE getPosition
+
+  INTERFACE getSCoord
+     MODULE PROCEDURE getSCoord_Orb
+  END INTERFACE getSCoord
+
+  INTERFACE getTime
+     MODULE PROCEDURE getTime_Orb
+  END INTERFACE getTime
+
+  INTERFACE getTisserandsParameters
+     MODULE PROCEDURE getTisserandsParameters_Orb
+  END INTERFACE getTisserandsParameters
+
+  INTERFACE getVelocity
+     MODULE PROCEDURE getVelocity_Orb
+  END INTERFACE getVelocity
+
+  INTERFACE propagate
+     MODULE PROCEDURE propagate_Orb_single
+     MODULE PROCEDURE propagate_Orb_multiple
+  END INTERFACE propagate
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_Orb
+     MODULE PROCEDURE reallocate_Orb_1
+     MODULE PROCEDURE reallocate_Orb_2
+  END INTERFACE reallocate
+
+  INTERFACE rotateToEquatorial
+     MODULE PROCEDURE rotateToEquatorial_Orb
+  END INTERFACE rotateToEquatorial
+
+  INTERFACE rotateToEcliptic
+     MODULE PROCEDURE rotateToEcliptic_Orb
+  END INTERFACE rotateToEcliptic
+
+  INTERFACE setParameters
+     MODULE PROCEDURE setParameters_Orb
+  END INTERFACE setParameters
+
+  INTERFACE solveKeplerEquation
+     MODULE PROCEDURE solveKeplerEquation_stumpff
+     MODULE PROCEDURE solveKeplerEquation_newton
+  END INTERFACE solveKeplerEquation
+
+  INTERFACE opposite
+     MODULE PROCEDURE opposite_Orb
+  END INTERFACE opposite
+
+  INTERFACE GaussfgJacobian
+     MODULE PROCEDURE GaussfgJacobian_Orb
+  END INTERFACE GaussfgJacobian
+
+  INTERFACE getEphemeris
+     MODULE PROCEDURE getEphemeris_Orb_single
+     MODULE PROCEDURE getEphemeris_Orb_multiple
+  END INTERFACE getEphemeris
+
+  INTERFACE getEphemerides
+     MODULE PROCEDURE getEphemerides_Orb_single
+     MODULE PROCEDURE getEphemerides_Orb_multiple
+  END INTERFACE getEphemerides
+
+  INTERFACE toCartesian
+     MODULE PROCEDURE toCartesian_Orb
+  END INTERFACE toCartesian
+
+  INTERFACE toCometary
+     MODULE PROCEDURE toCometary_Orb
+  END INTERFACE toCometary
+
+  INTERFACE toKeplerian
+     MODULE PROCEDURE toKeplerian_Orb
+  END INTERFACE toKeplerian
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a Orbit-object. Position and velocity are
+  !! zero-vectors. Coordinate frame is equatorial and propagation
+  !! scheme is 2-body. Central body is the Sun.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%elements        = 0.0_bp
+    this%element_type    = "cartesian"
+    this%frame           = "equatorial"
+    CALL NULLIFY(this%t)
+    this%central_body    = 11
+    this%dyn_model_prm   = "2-body"
+    this%finite_diff_prm = -1.0_bp
+    this%is_initialized  = .TRUE.
+
+  END SUBROUTINE new_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a Orbit-object using a given
+  !! CartesianCoordinates-object. Propagation scheme
+  !! is 2-body and central body is the Sun.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Orb_cartesian(this, ccoord, central_body)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)             :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: ccoord
+    INTEGER, INTENT(in), OPTIONAL           :: central_body
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%elements = getCoordinates(ccoord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new",&
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+    this%element_type = "cartesian"
+    this%frame = getFrame(ccoord)
+    NULLIFY(this%additional_perturbers)
+    this%t = getTime(ccoord)
+    IF (PRESENT(central_body)) THEN
+       this%central_body = central_body
+    ELSE
+       this%central_body = 11
+    END IF
+    this%dyn_model_prm = "2-body"
+    this%finite_diff_prm = -1.0_bp
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_Orb_cartesian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a Orbit-object using given elements. Propagation
+  !! scheme is 2-body. Optional argument can be used to define the
+  !! central body other than the Sun.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Orb_elements(this, elements, element_type, frame, t, central_body, mass)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)        :: this
+    REAL(bp), DIMENSION(6), INTENT(in) :: elements
+    CHARACTER(len=*), INTENT(in)       :: element_type, frame
+    TYPE (Time), INTENT(in)            :: t
+    INTEGER, INTENT(in), OPTIONAL      :: central_body
+    REAL(bp), INTENT(in), OPTIONAL     :: mass
+
+    TYPE (SphericalCoordinates)        :: scoord
+    TYPE (CartesianCoordinates)        :: ccoord
+    CHARACTER(len=32)                  :: tmp
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(t)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Given epoch has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%t = copy(t)
+    this%dyn_model_prm = "2-body"
+    this%finite_diff_prm = -1.0_bp
+    tmp = element_type
+    CALL locase(tmp, error)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new", &
+            "The element type string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    this%element_type = TRIM(tmp)
+
+    IF (PRESENT(central_body)) THEN
+       this%central_body = central_body
+    ELSE
+       this%central_body = 11
+    END IF
+
+    IF (PRESENT(mass)) THEN
+       this%mass_prm = mass
+    ELSE
+       this%mass_prm = -1.0_bp
+    END IF
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cartesian")
+
+       this%elements = elements
+       tmp = frame
+       CALL locase(tmp, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "The frame string contains forbidden characters (5).", 1)
+          RETURN
+       END IF
+       this%frame = TRIM(tmp)
+       this%is_initialized = .TRUE.
+
+    CASE ("spherical")
+
+       tmp = frame
+       CALL locase(tmp, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "The frame string contains forbidden characters (10).", 1)
+          RETURN
+       END IF
+       this%frame = TRIM(tmp)
+       CALL NEW(scoord, elements, this%frame, this%t)
+       CALL NEW(ccoord, scoord)
+       this%elements = getCoordinates(ccoord)
+       CALL NULLIFY(ccoord)
+       CALL NULLIFY(scoord)
+       IF (error) THEN
+          CALL errorMessage("Orbit / new",&
+               "TRACE BACK 1", 1)
+          RETURN
+       END IF
+       this%element_type = "cartesian"
+       this%is_initialized = .TRUE.
+
+    CASE ("keplerian")
+
+       ! Check soundness of Keplerian elements:
+       IF (elements(1) < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Semimajor Axis is negative.", 1)
+          RETURN
+       ELSE
+          this%elements(1) = elements(1)
+       END IF
+
+       IF (elements(2) == 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is exactly 1 (not possible, too few digits used).", 1)
+          RETURN
+       ELSE IF (elements(2) < 0.0_bp .OR. elements(2) > 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is outside the range [0,1[.", 1)
+          RETURN
+       ELSE
+          this%elements(2) = elements(2)
+       END IF
+
+       IF (elements(3) < 0.0_bp .OR. elements(3) >= pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Inclination is outside the range [0,pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(3) = elements(3)
+       END IF
+
+       IF (elements(4) < 0.0_bp .OR. elements(4) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Longitude of Ascending Node is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(4) = elements(4)
+       END IF
+
+       IF (elements(5) < 0.0_bp .OR. elements(5) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Argument of Perihelion is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(5) = elements(5)
+       END IF
+
+       IF (elements(6) < 0.0_bp .OR. elements(6) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Mean Anomaly is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(6) = elements(6)
+       END IF
+
+       this%element_type = "keplerian"
+       this%frame = frame
+       this%is_initialized = .TRUE.
+
+    CASE ("cometary")
+
+       ! Check soundness of cometary elements:
+       IF (elements(1) < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Perihelion distance is negative.", 1)
+          RETURN
+       ELSE
+          this%elements(1) = elements(1)
+       END IF
+
+       IF (elements(2) < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is negative.", 1)
+          RETURN
+       ELSE IF (elements(2) == 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is exactly 1 (not possible, too few digits used).", 1)
+          RETURN
+       ELSE
+          this%elements(2) = elements(2)
+       END IF
+
+       IF (elements(3) < 0.0_bp .OR. elements(3) >= pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Inclination is outside the range [0,pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(3) = elements(3)
+       END IF
+
+       IF (elements(4) < 0.0_bp .OR. elements(4) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Longitude of Ascending Node is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(4) = elements(4)
+       END IF
+
+       IF (elements(5) < 0.0_bp .OR. elements(5) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Argument of Perihelion is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(5) = elements(5)
+       END IF
+
+       ! Time of perihelion can be anything:
+       this%elements(6) = elements(6)
+
+       this%element_type = "cometary"
+       this%frame = frame
+       this%is_initialized = .TRUE.
+
+    CASE ("cometary_ta")
+
+       !! Same as 'cometary', but time of perihelion changed to the
+       !! true anomaly.
+
+       ! Check soundness of cometary elements:
+       IF (elements(1) < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Perihelion distance is negative.", 1)
+          RETURN
+       ELSE
+          this%elements(1) = elements(1)
+       END IF
+
+       IF (elements(2) < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is negative.", 1)
+          RETURN
+       ELSE IF (elements(2) == 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Eccentricity is exactly 1 (not possible, too few digits used).", 1)
+          RETURN
+       ELSE
+          this%elements(2) = elements(2)
+       END IF
+
+       IF (elements(3) < 0.0_bp .OR. elements(3) >= pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Inclination is outside the range [0,pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(3) = elements(3)
+       END IF
+
+       IF (elements(4) < 0.0_bp .OR. elements(4) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Longitude of Ascending Node is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(4) = elements(4)
+       END IF
+
+       IF (elements(5) < 0.0_bp .OR. elements(5) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Argument of Perihelion is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(5) = elements(5)
+       END IF
+
+       IF (elements(6) < 0.0_bp .OR. elements(6) >= two_pi) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "True Anomaly is outside the range [0,two_pi[.", 1)
+          RETURN
+       ELSE
+          this%elements(6) = elements(6)
+       END IF
+
+       this%element_type = "cometary_ta"
+       this%frame = frame
+       this%is_initialized = .TRUE.
+
+    CASE default
+
+       error = .TRUE.
+       CALL errorMessage("Orbit / new",&
+            "Type of elements (" // TRIM(this%element_type) // &
+            ") is incorrect.", 1)
+       RETURN       
+
+    END SELECT
+
+    NULLIFY(this%additional_perturbers)
+
+
+  END SUBROUTINE new_Orb_elements
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Derives Cartesian orbital elements (this) from two positions
+  !! (ccoord0 and ccoord1) using either (i) the p-iteration method
+  !! (2-body) by Herrick and Liu, (ii) the continued fraction method
+  !! by Hansen (2-body), or (iii) the amoeba method by Granvik and
+  !! Muinonen (n-body). The frame of the output orbit is defined by
+  !! the equal frames of the input positions. The Sun is the central
+  !! body.
+  !! 
+  !! Returns error.
+  !!
+  RECURSIVE SUBROUTINE new_Orb_2point(this, ccoord0, ccoord1, &
+       method, smamax, ftol, iter, perturbers, integrator, &
+       integration_step)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                       :: this
+    TYPE (CartesianCoordinates), INTENT(in)           :: ccoord0, ccoord1
+    CHARACTER(len=*), INTENT(in)                      :: method
+    REAL(bp), INTENT(in)                              :: smamax
+    REAL(bp), INTENT(in), OPTIONAL                    :: ftol
+    INTEGER(ibp), INTENT(out), OPTIONAL               :: iter
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL       :: perturbers
+    CHARACTER(len=*), INTENT(in), OPTIONAL            :: integrator
+    REAL(bp), INTENT(in), OPTIONAL                    :: integration_step
+
+    REAL(bp), PARAMETER :: dp_init = 1.0_bp !1.0_bp
+    REAL(bp), PARAMETER :: p_init = 1.0e-7_bp
+    REAL(bp), PARAMETER :: tolp = 1.0e-8_bp !1.0e-13_bp
+    REAL(bp), PARAMETER :: told = 1.0e-16_bp !1.0e-16
+    REAL(bp), PARAMETER :: tol = 1.0e-10_bp !1.0e-13_bp
+    REAL(bp), PARAMETER :: toli = 1.0e-8_bp
+    REAL(bp), PARAMETER :: tol_amoeba = 1.0e-13_bp
+    ! Require 100m accuracy (comparable to better than 0.5" astrometric
+    ! accuracy when the topocentric distance is more than 40,000 km) in
+    ! the n-body amoeba routine:
+    REAL(bp), PARAMETER :: ftol_prm = 100.0_bp/m_au
+    INTEGER(ibp), PARAMETER :: itmax_prm = 1000!500
+    TYPE (Orbit), DIMENSION(4) :: orb_arr
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t0, t1
+    TYPE (CartesianCoordinates) :: ccoord_
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=64) :: method_
+    REAL(bp), DIMENSION(4,3) :: p_matrix
+    REAL(bp), DIMENSION(4) :: y_vector
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp), DIMENSION(3) :: psum, pos0, vel0, pos1, orbit_normal, &
+         ran
+    REAL(bp) :: r0, r1, r01, cdf, sdf, diff1, diff2, p, p1, p2, dp, &
+         cos_df, f, g, kappa, tau, h, cf, dcf, len_orbit_normal, ftol_
+    INTEGER :: y, i, ntest, nsec, ntmax, nsmax, ihi, ilo, ndim, &
+         err_verb_tmp, iter_
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(ccoord0)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "First position is unavailable.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(ccoord1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Second position is unavailable.", 1)
+       RETURN
+    END IF
+
+    frame = getFrame(ccoord0)
+    IF (frame /= getFrame(ccoord1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Frames of input coordinates are different.", 1)
+       RETURN
+    END IF
+
+    t0 = getTime(ccoord0)
+    t1 = getTime(ccoord1)
+    ccoord_ = copy(ccoord0)
+    pos0 = getPosition(ccoord_)
+    ! Initialize this object (at least) temporarily:
+    CALL NEW(this, ccoord_)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new", &
+            "Could not initialize this object temporarily.", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(ccoord_)
+    ccoord_ = copy(ccoord1)
+    pos1 = getPosition(ccoord_)
+    r0  = SQRT(DOT_PRODUCT(pos0,pos0))
+    r1  = SQRT(DOT_PRODUCT(pos1,pos1))
+    cdf = DOT_PRODUCT(pos0,pos1) / (r0*r1)
+    IF (ABS(cdf) > 1.0_bp) THEN
+       cdf = SIGN(1.0_bp, cdf)
+    END IF
+
+    IF (PRESENT(perturbers)) THEN
+       this%perturbers_prm = perturbers
+    ELSE
+       this%perturbers_prm = .TRUE.
+    END IF
+    IF (PRESENT(integrator)) THEN
+       this%integrator_prm = integrator
+    ELSE
+       this%integrator_prm = "bulirsch-stoer"
+    END IF
+    IF (PRESENT(integration_step)) THEN
+       this%integration_step_prm = integration_step
+    ELSE
+       this%integration_step_prm = 1.0_bp
+    END IF
+
+    method_ = method
+    CALL locase(method_, error)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new", &
+            "The method string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    SELECT CASE (method_)
+
+    CASE ("p-iteration")
+
+       !!
+       !! p-iteration
+       !!
+       !! The orbital segment is not assumed to include the attracting 
+       !! focus by default (y=1). However, if the computation is unsuccesful, 
+       !! the attracting focus will be included in the orbital segment and
+       !! the computations will be done again.
+       !!
+       !! Reference: J. M. A. Danby, "Fundamentals of celestial mechanics", 1992
+       !!
+       y = 1
+
+       DO i=1,2
+
+          sdf = y * SQRT(1.0_bp - cdf**2.0_bp)
+
+          ! First bracketing:
+          diff1 = 0.0_bp
+          ntest = 1
+          p2 = p_init
+          dp = dp_init
+          ! Determine maximum number of iteration steps needed to cover
+          ! the phase space region defined by maximum allowed semimajor axis
+          ! (maximum value for orbital parameter):
+          ntmax = INT(smamax/dp)
+          cos_df = estimateCosDf(this, ccoord_, p2, y)
+          IF (error) THEN
+             CALL errorMessage("Orbit / new", &
+                  "TRACE BACK 5", 1)
+             CALL NULLIFY(this)
+             RETURN
+          END IF
+          diff2 = cdf - cos_df
+          DO WHILE (diff1*diff2 >= 0.0_bp)
+             ntest = ntest + 1
+             IF (ntest > ntmax) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / new", &
+                     "Too many steps in bracketing (1).", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             p1    = p2
+             p2    = p1 + dp
+             cos_df = estimateCosDf(this, ccoord_, p2, y)
+             IF (error) THEN
+                CALL errorMessage("Orbit / new", &
+                     "TRACE BACK 10", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             diff1 = diff2
+             diff2 = cdf - cos_df
+          END DO
+
+          ! Second bracketing:
+          diff2 = diff1
+          ntest = 1
+          p2 = p1
+          dp = dp_init/10.0_bp
+          ! Determine maximum number of iteration steps needed to cover
+          ! the phase space region defined by maximum allowed semimajor axis
+          ! (maximum value for orbital parameter):
+          ntmax = INT(smamax/dp)
+          DO WHILE (diff1*diff2 >= 0.0_bp)
+             ntest = ntest + 1
+             IF (ntest > ntmax) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / new", &
+                     "Too many steps in bracketing (2).", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             p1    = p2
+             p2    = p1 + dp
+             cos_df = estimateCosDf(this, ccoord_, p2, y)
+             IF (error) THEN
+                CALL errorMessage("Orbit / new", &
+                     "TRACE BACK 15", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             diff1 = diff2
+             diff2 = cdf - cos_df
+          END DO
+
+          ! Secant method:
+          nsec = 0
+          ! Determine maximum number of iteration steps needed to cover
+          ! the phase space region defined by maximum allowed semimajor axis
+          ! (maximum value for orbital parameter):
+          !nsmax = INT(smamax/dp_init)
+          nsmax = INT(smamax/dp)
+          cos_df = estimateCosDf(this, ccoord_, p2, y)
+          IF (error) THEN
+             CALL errorMessage("Orbit / new", &
+                  "TRACE BACK 20", 1)
+             CALL NULLIFY(this)
+             RETURN
+          END IF
+          diff2 = cdf - cos_df
+          IF (ABS(diff2-diff1) < told) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / new", &
+                  "Step size approaches (+/-)-infinity (1).", 1)
+             CALL NULLIFY(this)
+             RETURN
+          END IF
+          dp = -diff2*(p2-p1)/(diff2-diff1)
+          DO WHILE (ABS(dp) >= tolp) 
+             nsec = nsec+1
+             IF (nsec > nsmax .OR. p2+dp <= 0.0_bp) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / new", &
+                     "Too many steps in iteration.", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             p1 = p2
+             p2 = p2 + dp
+             cos_df = estimateCosDf(this, ccoord_, p2, y)
+             IF (error) THEN
+                CALL errorMessage("Orbit / new", &
+                     "TRACE BACK 25", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             diff1 = diff2
+             diff2 = cdf - cos_df
+             IF (ABS(diff2-diff1) < told) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / new", &
+                     "Step size approaches (+/-)-infinity (2).", 1)
+                CALL NULLIFY(this)
+                RETURN
+             END IF
+             dp = -diff2*(p2-p1)/(diff2-diff1)
+          END DO
+          p = p2
+          f = (r1/p)*(cdf - 1.0_bp) + 1.0_bp
+          g = ((r0*r1) / SQRT(planetary_mu(this%central_body)*p)) * sdf
+
+          IF (g*y >= 0.0_bp) THEN
+             ! Found correct orbital solution.
+             EXIT
+          ELSE
+             ! Found incorrect orbital solution; include attracting focus
+             ! in the orbital segment and redo the computation:
+             y = -1 * y
+          END IF
+
+       END DO
+
+       IF (g*y < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Could not find correct orbit.", 1)
+          CALL NULLIFY(this)
+          RETURN
+       ELSE IF (ABS(g) < TINY(g)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Attempted division by zero (g-function).", 1)
+          CALL NULLIFY(this)
+          RETURN
+       ELSE
+          vel0 = (pos1 - f*pos0)/g
+          this%elements(1:3) = pos0
+          this%elements(4:6) = vel0
+       END IF
+
+    CASE ("continued fraction")
+
+       !!
+       !! continued fraction
+       !!
+       !! Derives Cartesian orbital elements (this) from two Cartesian
+       !! positions (ccoord0 and ccoord1) using Hansen's continued
+       !! fraction for the sector-triangle ratio (2-body).
+       !!
+       !! Reference: A. D. Dubyago, "The determination of orbits", 1961
+       !!
+
+       r01 = DOT_PRODUCT(pos0,pos1)
+       tau = SQRT(planetary_mu(this%central_body))*(getMJD(t1,"TT") - getMJD(t0,"TT"))
+       IF (ABS(tau) < tol) THEN
+          ! t0 and t1 practically the same.
+          CALL errorMessage("Orbit / new", &
+               "Epochs t0 and t1 practically the same.", 1)
+          RETURN
+       END IF
+       kappa = SQRT(2.0_bp*(r0*r1+r01))
+       orbit_normal = cross_product(pos0,pos1)
+       len_orbit_normal = SQRT(DOT_PRODUCT(orbit_normal,orbit_normal))
+       IF (len_orbit_normal < toli) THEN
+          ! r0 and r1 almost parallel.
+          CALL errorMessage("Orbit / new", &
+               "Vectors r0 and r1 almost parallel.", 1)
+          RETURN
+       END IF
+       h = tau**2/(kappa**2*(kappa/3.0_bp+(r0+r1)/2.0_bp))
+       CALL continuedFraction(h, tol, cf, dcf)
+       IF (dcf > tol) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Failure in continued fraction", 1)
+          RETURN
+       END IF
+       p = (len_orbit_normal*cf/tau)**2.0_bp
+       f = (r1/p)*(cdf - 1.0_bp) + 1.0_bp
+       sdf = SQRT(DOT_PRODUCT(orbit_normal,orbit_normal))/(r0*r1)
+       g = ((r0*r1) / SQRT(planetary_mu(this%central_body)*p)) * sdf
+       IF (ABS(g) < TINY(g)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / new", &
+               "Attempted division by zero (g-function).", 1)
+          CALL NULLIFY(this)
+          RETURN
+       END IF
+       vel0 = (pos1 - f*pos0)/g
+       this%elements(1:3) = pos0
+       this%elements(4:6) = vel0
+
+    CASE ("2-body amoeba")
+
+       !! Minimization of the function func in N dimensions by the
+       !! downhill simplex method of Nelder and Mead. The (N + 1) × N
+       !! matrix p is input. Its N + 1 rows are N-dimensional vectors that
+       !! are the vertices of the starting simplex. Also input is the
+       !! vector y of length N + 1, whose components must be preinitialized
+       !! to the values of func evaluated at the N + 1 vertices (rows) of
+       !! p and ftol the fractional convergence tolerance to be achieved in
+       !! the function value (n.b.!). On output, p and y will have been
+       !! reset to N+1 new points all within ftol of a minimum function
+       !! value, and iter gives the number of function evaluations taken.
+       !!
+       !! Parameters: The maximum allowed number of function evaluations,
+       !! and a small number.
+       !!
+
+       this%dyn_model_prm = "2-body"
+       IF (PRESENT(ftol)) THEN
+          ftol_ = ftol
+       ELSE
+          ftol_ = ftol_prm
+       END IF
+       elements = getCoordinates(ccoord0)
+       CALL NEW(orb_arr(1), elements, "cartesian", frame, t0)
+       CALL setParameters(orb_arr(1), &
+            dyn_model=this%dyn_model_prm, &
+            perturbers=this%perturbers_prm, &
+            integrator=this%integrator_prm, &
+            integration_step=this%integration_step_prm)
+       y_vector(1) = distance_2b(orb_arr(1))
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       IF (y_vector(1) < ftol_) THEN
+          this = copy(orb)
+          this%dyn_model_prm = "2-body"
+          this%perturbers_prm = perturbers
+          this%integrator_prm = integrator
+          this%integration_step_prm = integration_step
+          CALL NULLIFY(orb)
+          IF (PRESENT(iter)) THEN
+             iter = 0
+          END IF
+          RETURN
+       END IF
+       p_matrix(1,1:3) = elements(4:6)
+       CALL NULLIFY(orb)
+       DO i=2,4
+          p_matrix(i,1:3) = elements(4:6) + 0.1_bp*elements(4:6)
+          elements(4:6) =  p_matrix(i,1:3)
+          CALL NEW(orb_arr(i), elements, "cartesian", frame, t0)
+       END DO
+       DO i=2,4
+          CALL setParameters(orb_arr(i), &
+               dyn_model=this%dyn_model_prm, &
+               perturbers=this%perturbers_prm, &
+               integrator=this%integrator_prm, &
+               integration_step=this%integration_step_prm)
+          y_vector(i) = distance_2b(orb_arr(i))
+          IF (error) THEN
+             CALL errorMessage("Orbit / new", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+       END DO
+       CALL amoeba_private_2b
+       IF (PRESENT(iter)) THEN
+          iter = iter_
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       ilo = iminloc(y_vector(:))
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,4(F20.15,1X))") "Velocity at " // &
+               "epoch 0 and resulting distance from target " // &
+               "position:", p_matrix(ilo,:), y_vector(ilo)
+          WRITE(stdout,"(2X,A,1X,I0)") "Required number of " // &
+               "iterations:", iter_
+          WRITE(stdout,"(1X)")
+       END IF
+       this%elements(1:3) = elements(1:3)
+       this%elements(4:6) = p_matrix(ilo,1:3)
+       this%dyn_model_prm = "2-body"
+
+    CASE ("n-body amoeba")
+
+       !! Minimization of the function func in N dimensions by the
+       !! downhill simplex method of Nelder and Mead. The (N + 1) × N
+       !! matrix p is input. Its N + 1 rows are N-dimensional vectors that
+       !! are the vertices of the starting simplex. Also input is the
+       !! vector y of length N + 1, whose components must be preinitialized
+       !! to the values of func evaluated at the N + 1 vertices (rows) of
+       !! p and ftol the fractional convergence tolerance to be achieved in
+       !! the function value (n.b.!). On output, p and y will have been
+       !! reset to N+1 new points all within ftol of a minimum function
+       !! value, and iter gives the number of function evaluations taken.
+       !!
+       !! Parameters: The maximum allowed number of function evaluations,
+       !! and a small number.
+       !!
+
+       this%dyn_model_prm = "n-body"
+       err_verb_tmp = err_verb
+       err_verb = 0
+       CALL NEW(orb, ccoord0, ccoord1, "continued fraction", smamax)
+       IF (error) THEN
+          error = .FALSE.
+          CALL NULLIFY(orb)
+          CALL NEW(orb, ccoord0, ccoord1, "p-iteration", smamax)          
+       END IF
+       err_verb = err_verb_tmp
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "Could not solve the 2-point boundary value " // & 
+               "problem in the 2-body approximation.", 1)
+          RETURN
+       END IF
+       IF (PRESENT(ftol)) THEN
+          ftol_ = ftol
+       ELSE
+          ftol_ = ftol_prm
+       END IF
+       orb_arr(1) = copy(orb)
+       CALL setParameters(orb_arr(1), &
+            dyn_model="n-body", &
+            perturbers=this%perturbers_prm, &
+            integrator=this%integrator_prm, &
+            integration_step=this%integration_step_prm)
+       y_vector(1) = distance(orb_arr(1))
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       IF (y_vector(1) < ftol_) THEN
+          this = copy(orb)
+          this%dyn_model_prm = "n-body"
+          this%perturbers_prm = perturbers
+          this%integrator_prm = integrator
+          this%integration_step_prm = integration_step
+          CALL NULLIFY(orb)
+          IF (PRESENT(iter)) THEN
+             iter = 0
+          END IF
+          RETURN
+       END IF
+       elements = getElements(orb, "cartesian", frame)
+       p_matrix(1,1:3) = elements(4:6)
+       CALL NULLIFY(orb)
+       DO i=2,4
+          CALL randomNumber(ran)
+          p_matrix(i,1:3) = elements(4:6) + 0.01_bp*(2.0_bp*ran-1.0_bp)*elements(4:6)
+          elements(4:6) =  p_matrix(i,1:3)
+          CALL NEW(orb_arr(i), elements, "cartesian", frame, t0)
+       END DO
+       DO i=2,4
+          CALL setParameters(orb_arr(i), &
+               dyn_model="n-body", &
+               perturbers=this%perturbers_prm, &
+               integrator=this%integrator_prm, &
+               integration_step=this%integration_step_prm)
+          y_vector(i) = distance(orb_arr(i))
+          IF (error) THEN
+             CALL errorMessage("Orbit / new", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+       END DO
+       CALL amoeba_private
+       IF (PRESENT(iter)) THEN
+          iter = iter_
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Orbit / new", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       ilo = iminloc(y_vector(:))
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,4(F20.15,1X))") "Velocity at " // &
+               "epoch 0 and resulting distance from target " // &
+               "position:", p_matrix(ilo,:), y_vector(ilo)
+          WRITE(stdout,"(2X,A,1X,I0)") "Required number of " // &
+               "iterations:", iter_
+          WRITE(stdout,"(1X)")
+       END IF
+       this%elements(1:3) = elements(1:3)
+       this%elements(4:6) = p_matrix(ilo,1:3)
+       this%dyn_model_prm = "n-body"
+
+    CASE default 
+
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Method chosen for solving the 2-point boundary value " // &
+            "problem not available:" // TRIM(method) // ".", 1)
+       RETURN
+
+    END SELECT
+
+    CALL NULLIFY(ccoord_)
+    NULLIFY(this%additional_perturbers)
+
+
+  CONTAINS 
+
+
+    SUBROUTINE amoeba_private_2b 
+
+      IMPLICIT NONE
+      TYPE (Orbit) :: orb
+      REAL(bp) :: ysave, ytry, ytmp
+      INTEGER(ibp) :: i, ilo, inhi 
+
+      ndim = SIZE(p_matrix,dim=2)
+      IF (ndim /= SIZE(p_matrix,dim=1) - 1 .OR. ndim /= SIZE(y_vector) - 1) THEN
+         error = .TRUE.
+         CALL errorMessage("Orbit / new", &
+              "Matrix and vector dimensions incompatible.", 1)
+         RETURN
+      END IF
+      iter_ = 0 
+      psum(:) = SUM(p_matrix(:,:),dim=1) 
+      DO !Iteration loop.  
+         ! Determine which point is the highest (worst),
+         ! next-highest, and lowest (best)
+         ilo = iminloc(y_vector(:))
+         ihi = imaxloc(y_vector(:))
+         ytmp = y_vector(ihi) 
+         y_vector(ihi) = y_vector(ilo)
+         inhi = imaxloc(y_vector(:))
+         y_vector(ihi) = ytmp
+         IF (info_verb >= 3) THEN
+            DO i=1,SIZE(y_vector,dim=1)
+               IF (i == ilo) THEN
+                  WRITE(stdout,"('ILO:',1X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               ELSE IF (i == ihi) THEN
+                  WRITE(stdout,"('IHI:',1X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               ELSE
+                  WRITE(stdout,"(5X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               END IF
+            END DO
+            WRITE(stdout,"(1X)")
+         END IF
+         ! Compute the fractional range from highest to lowest and
+         ! return if satisfactory.
+         IF (y_vector(ilo) < ftol_) THEN 
+            ! If returning, put best point and value in slot 1. 
+            CALL swap(y_vector(1),y_vector(ilo))
+            CALL swap(p_matrix(1,:),p_matrix(ilo,:)) 
+            RETURN 
+         END IF
+         IF (iter_ >= ITMAX_PRM) THEN
+            ! TMAX exceeded in amoeba
+            error = .TRUE.
+            CALL errorMessage("Orbit / new", &
+                 "Maximum number of iterations exceeded.", 1)
+            RETURN
+         END IF
+         ! Begin a new iteration. First extrapolate by a factor -1
+         ! through the face of the simplex across from the high
+         ! point, i.e., reflect the simplex from the high point.
+         ytry = amotry_2b(-1.0_bp) 
+         IF (error) THEN
+            CALL errorMessage("Orbit / new", &
+                 "TRACE BACK (30)", 1)
+            RETURN
+         END IF
+         iter_ = iter_ + 1 
+         IF (ytry <= y_vector(ilo)) THEN
+            ! Gives a result better than the best point, so try an
+            ! additional extrapolation by a factor of 2.  
+            ytry = amotry_2b(2.0_bp)
+            IF (error) THEN
+               CALL errorMessage("Orbit / new", &
+                    "TRACE BACK (35)", 1)
+               RETURN
+            END IF
+            iter_ = iter_ + 1 
+         ELSE IF (ytry >= y_vector(inhi)) THEN 
+            ! The reflected point is worse than the second highest,
+            ! so look for an intermediate lower point, i.e., do a
+            ! one-dimensional contraction.
+            ysave = y_vector(ihi) 
+            ytry = amotry_2b(0.5_bp)
+            IF (error) THEN
+               CALL errorMessage("Orbit / new", &
+                    "TRACE BACK (40)", 1)
+               RETURN
+            END IF
+            iter_ = iter_ + 1
+            IF (ytry >= ysave) THEN
+               ! Can't seem to get rid of that high point. Better
+               ! contract around the lowest (best) point.
+               p_matrix(:,:) = 0.5_bp*(p_matrix(:,:)+SPREAD(p_matrix(ilo,:),1,SIZE(p_matrix,1)))
+               DO i=1,ndim+1
+                  IF (i /= ilo) THEN
+                     elements(4:6) = p_matrix(i,:)
+                     CALL NEW(orb, elements, "cartesian", frame, t0)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     CALL setParameters(orb, &
+                          dyn_model=this%dyn_model_prm, &
+                          perturbers=this%perturbers_prm, &
+                          integrator=this%integrator_prm, &
+                          integration_step=this%integration_step_prm)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     y_vector(i) = distance_2b(orb)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (50)", 1)
+                        RETURN
+                     END IF
+                     CALL NULLIFY(orb)
+                  END IF
+               END DO
+               iter_ = iter_ + ndim ! Keep track of function evaluations.
+               psum(:) = SUM(p_matrix(:,:),dim=1)
+            END IF
+         END IF
+      END DO ! Go back for the test of doneness and the next iteration.
+
+    END SUBROUTINE amoeba_private_2b
+
+
+
+    SUBROUTINE amoeba_private 
+
+      IMPLICIT NONE
+      TYPE (Orbit) :: orb
+      REAL(bp) :: ysave, ytry, ytmp
+      INTEGER(ibp) :: i, ilo, inhi 
+
+      ndim = SIZE(p_matrix,dim=2)
+      IF (ndim /= SIZE(p_matrix,dim=1) - 1 .OR. ndim /= SIZE(y_vector) - 1) THEN
+         error = .TRUE.
+         CALL errorMessage("Orbit / new", &
+              "Matrix and vector dimensions incompatible.", 1)
+         RETURN
+      END IF
+      iter_ = 0 
+      psum(:) = SUM(p_matrix(:,:),dim=1) 
+      DO !Iteration loop.  
+         ! Determine which point is the highest (worst),
+         ! next-highest, and lowest (best)
+         ilo = iminloc(y_vector(:))
+         ihi = imaxloc(y_vector(:))
+         ytmp = y_vector(ihi) 
+         y_vector(ihi) = y_vector(ilo)
+         inhi = imaxloc(y_vector(:))
+         y_vector(ihi) = ytmp
+         IF (info_verb >= 3) THEN
+            DO i=1,SIZE(y_vector,dim=1)
+               IF (i == ilo) THEN
+                  WRITE(stdout,"('ILO:',1X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               ELSE IF (i == ihi) THEN
+                  WRITE(stdout,"('IHI:',1X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               ELSE
+                  WRITE(stdout,"(5X,4(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+               END IF
+            END DO
+            WRITE(stdout,"(1X)")
+         END IF
+         ! Compute the fractional range from highest to lowest and
+         ! return if satisfactory.
+         IF (y_vector(ilo) < ftol_) THEN 
+            ! If returning, put best point and value in slot 1. 
+            CALL swap(y_vector(1),y_vector(ilo))
+            CALL swap(p_matrix(1,:),p_matrix(ilo,:)) 
+            RETURN 
+         END IF
+         IF (iter_ >= ITMAX_PRM) THEN
+            ! TMAX exceeded in amoeba
+            error = .TRUE.
+            CALL errorMessage("Orbit / new", &
+                 "Maximum number of iterations exceeded.", 1)
+            RETURN
+         END IF
+         ! Begin a new iteration. First extrapolate by a factor -1
+         ! through the face of the simplex across from the high
+         ! point, i.e., reflect the simplex from the high point.
+         ytry = amotry(-1.0_bp) 
+         IF (error) THEN
+            CALL errorMessage("Orbit / new", &
+                 "TRACE BACK (30)", 1)
+            RETURN
+         END IF
+         iter_ = iter_ + 1 
+         IF (ytry <= y_vector(ilo)) THEN
+            ! Gives a result better than the best point, so try an
+            ! additional extrapolation by a factor of 2.  
+            ytry = amotry(2.0_bp)
+            IF (error) THEN
+               CALL errorMessage("Orbit / new", &
+                    "TRACE BACK (35)", 1)
+               RETURN
+            END IF
+            iter_ = iter_ + 1 
+         ELSE IF (ytry >= y_vector(inhi)) THEN 
+            ! The reflected point is worse than the second highest,
+            ! so look for an intermediate lower point, i.e., do a
+            ! one-dimensional contraction.
+            ysave = y_vector(ihi) 
+            ytry = amotry(0.5_bp)
+            IF (error) THEN
+               CALL errorMessage("Orbit / new", &
+                    "TRACE BACK (40)", 1)
+               RETURN
+            END IF
+            iter_ = iter_ + 1
+            IF (ytry >= ysave) THEN
+               ! Can't seem to get rid of that high point. Better
+               ! contract around the lowest (best) point.
+               p_matrix(:,:) = 0.5_bp*(p_matrix(:,:)+SPREAD(p_matrix(ilo,:),1,SIZE(p_matrix,1)))
+               DO i=1,ndim+1
+                  IF (i /= ilo) THEN
+                     elements(4:6) = p_matrix(i,:)
+                     CALL NEW(orb, elements, "cartesian", frame, t0)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     CALL setParameters(orb, &
+                          dyn_model=this%dyn_model_prm, &
+                          perturbers=this%perturbers_prm, &
+                          integrator=this%integrator_prm, &
+                          integration_step=this%integration_step_prm)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     y_vector(i) = distance(orb)
+                     IF (error) THEN
+                        CALL errorMessage("Orbit / new", &
+                             "TRACE BACK (50)", 1)
+                        RETURN
+                     END IF
+                     CALL NULLIFY(orb)
+                  END IF
+               END DO
+               iter_ = iter_ + ndim ! Keep track of function evaluations.
+               psum(:) = SUM(p_matrix(:,:),dim=1)
+            END IF
+         END IF
+      END DO ! Go back for the test of doneness and the next iteration.
+
+    END SUBROUTINE amoeba_private
+
+
+
+    !! *Description*:
+    !!
+    !! Extrapolates by a factor fac through the face of the
+    !! simplex across from the high point, tries it, and replaces
+    !! the high point if the new point is better.
+    !!
+    REAL(bp) FUNCTION amotry_2b(fac)
+
+      IMPLICIT NONE
+      REAL(bp), INTENT(IN) :: fac
+
+      TYPE (Orbit) :: orb
+      REAL(bp), DIMENSION(SIZE(p_matrix,2)) :: ptry 
+      REAL(bp) :: fac1, fac2, ytry
+
+      fac1 = (1.0_bp-fac)/ndim
+      fac2 = fac1 - fac 
+      ptry(:) = psum(:)*fac1-p_matrix(ihi,:)*fac2 
+      ! Evaluate the function at the trial point.
+      elements(4:6) = ptry
+      CALL NEW(orb, elements, "cartesian", frame, t0)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (55)", 1)
+         RETURN
+      END IF
+      CALL setParameters(orb, &
+           dyn_model=this%dyn_model_prm, &
+           perturbers=this%perturbers_prm, &
+           integrator=this%integrator_prm, &
+           integration_step=this%integration_step_prm)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (45)", 1)
+         RETURN
+      END IF
+      ytry = distance_2b(orb)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (60)", 1)
+         RETURN
+      END IF
+      CALL NULLIFY(orb)
+      IF (ytry < y_vector(ihi)) THEN 
+         ! If it's better than the highest, then replace
+         ! the highest.
+         y_vector(ihi) = ytry
+         psum(:) = psum(:) - p_matrix(ihi,:) + ptry(:)
+         p_matrix(ihi,:) = ptry(:)
+      END IF
+      amotry_2b = ytry 
+
+    END FUNCTION amotry_2b
+
+
+
+    !! *Description*:
+    !!
+    !! Extrapolates by a factor fac through the face of the
+    !! simplex across from the high point, tries it, and replaces
+    !! the high point if the new point is better.
+    !!
+    REAL(bp) FUNCTION amotry(fac)
+
+      IMPLICIT NONE
+      REAL(bp), INTENT(IN) :: fac
+
+      TYPE (Orbit) :: orb
+      REAL(bp), DIMENSION(SIZE(p_matrix,2)) :: ptry 
+      REAL(bp) :: fac1, fac2, ytry
+
+      fac1 = (1.0_bp-fac)/ndim
+      fac2 = fac1 - fac 
+      ptry(:) = psum(:)*fac1-p_matrix(ihi,:)*fac2 
+      ! Evaluate the function at the trial point.
+      elements(4:6) = ptry
+      CALL NEW(orb, elements, "cartesian", frame, t0)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (55)", 1)
+         RETURN
+      END IF
+      CALL setParameters(orb, &
+           dyn_model=this%dyn_model_prm, &
+           perturbers=this%perturbers_prm, &
+           integrator=this%integrator_prm, &
+           integration_step=this%integration_step_prm)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (45)", 1)
+         RETURN
+      END IF
+      ytry = distance(orb)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (60)", 1)
+         RETURN
+      END IF
+      CALL NULLIFY(orb)
+      IF (ytry < y_vector(ihi)) THEN 
+         ! If it's better than the highest, then replace
+         ! the highest.
+         y_vector(ihi) = ytry
+         psum(:) = psum(:) - p_matrix(ihi,:) + ptry(:)
+         p_matrix(ihi,:) = ptry(:)
+      END IF
+      amotry = ytry 
+
+    END FUNCTION amotry
+
+
+
+    REAL(bp) FUNCTION distance_2b(orb)
+
+      IMPLICIT NONE
+      TYPE (Orbit), INTENT(inout) :: orb 
+
+      REAL(bp), DIMENSION(3) :: pos_orb
+
+      CALL propagate(orb, t1)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (65)", 1)
+         RETURN
+      END IF
+      pos_orb = getPosition(orb)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (75)", 1)
+         RETURN
+      END IF
+      distance_2b = SQRT(SUM((pos1-pos_orb)**2))
+
+    END FUNCTION distance_2b
+
+
+
+
+    REAL(bp) FUNCTION distance(orb)
+
+      IMPLICIT NONE
+      TYPE (Orbit), INTENT(inout) :: orb 
+
+      REAL(bp), DIMENSION(3) :: pos_orb1
+
+      CALL propagate(orb, t1)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (65)", 1)
+         RETURN
+      END IF
+      pos_orb1 = getPosition(orb)
+      IF (error) THEN
+         CALL errorMessage("Orbit / new", &
+              "TRACE BACK (75)", 1)
+         RETURN
+      END IF
+      distance = SQRT(SUM((pos1-pos_orb1)**2))
+
+    END FUNCTION distance
+
+  END SUBROUTINE new_Orb_2point
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a Orbit-object using a given
+  !! SphericalCoordinates-object. Coordinate frame s equal to the
+  !! frame of the input frame and propagation scheme is 2-body.
+  !! Central body is the Sun.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_Orb_spherical(this, scoord)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout) :: this
+    TYPE (SphericalCoordinates), INTENT(in) :: scoord
+    TYPE (CartesianCoordinates) :: ccoord
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Transform to Cartesian coordinates:
+    CALL NEW(ccoord, scoord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new",&
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+    this%elements = getCoordinates(ccoord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / new",&
+            "TRACE BACK 2", 1)
+       RETURN
+    END IF
+    this%element_type = "cartesian"
+    this%frame = getFrame(ccoord)
+    this%t = getTime(ccoord)
+    CALL NULLIFY(ccoord)
+    NULLIFY(this%additional_perturbers)
+    this%dyn_model_prm = "2-body"
+    this%finite_diff_prm = -1.0_bp
+    this%is_initialized = .TRUE.
+    this%central_body = 11
+
+  END SUBROUTINE new_Orb_spherical
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout) :: this
+    INTEGER :: err
+
+    this%elements = 0.0_bp
+    this%element_type = ""
+    CALL NULLIFY(this%t)
+    this%finite_diff_prm = -1.0_bp
+    this%frame = ""
+    this%mass_prm = -1.0_bp
+    this%dyn_model_prm    = ""
+    this%perturbers_prm = .FALSE.
+    IF (ASSOCIATED(this%additional_perturbers)) THEN
+       DEALLOCATE(this%additional_perturbers, stat=err)
+    ELSE
+       NULLIFY(this%additional_perturbers)
+    END IF
+    this%is_initialized = .FALSE.
+    this%central_body   = 11
+
+  END SUBROUTINE nullify_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION copy_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    TYPE (Orbit)             :: copy_Orb
+    INTEGER :: err
+
+    copy_Orb%elements       = this%elements
+    copy_Orb%element_type   = this%element_type
+    copy_Orb%frame          = this%frame
+    copy_Orb%mass_prm           = this%mass_prm
+    copy_Orb%t              = copy(this%t)
+    copy_Orb%central_body   = this%central_body
+    copy_Orb%dyn_model_prm  = this%dyn_model_prm
+    copy_Orb%perturbers_prm(:) = this%perturbers_prm(:)
+    IF (ASSOCIATED(this%additional_perturbers)) THEN
+       ALLOCATE(copy_Orb%additional_perturbers(SIZE(this%additional_perturbers,dim=1), &
+            SIZE(this%additional_perturbers,dim=2)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / copy", &
+               "Could not allocate memory.",1)
+          RETURN
+       END IF
+       copy_Orb%additional_perturbers = this%additional_perturbers
+    ELSE
+       NULLIFY(copy_Orb%additional_perturbers)
+    END IF
+    copy_Orb%finite_diff_prm = this%finite_diff_prm
+    copy_Orb%integrator_prm = this%integrator_prm
+    copy_Orb%integration_step_prm = this%integration_step_prm
+    copy_Orb%is_initialized = this%is_initialized
+
+  END FUNCTION copy_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether it exists or not.
+  !!
+  LOGICAL FUNCTION exist_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+
+    exist_Orb = this%is_initialized
+
+  END FUNCTION exist_Orb
+
+
+
+
+
+  REAL(bp) FUNCTION aeidist(ptry,param,errstr)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(:), INTENT(in) :: ptry
+    REAL(bp), DIMENSION(:), INTENT(in) :: param
+    CHARACTER(len=*), INTENT(inout) :: errstr
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp), DIMENSION(3) :: vel
+
+    vel = ptry 
+    elements = (/ param(1:3), vel /)
+    CALL NEW(t, param(7), "TT")
+    IF (error) THEN
+       errstr = "error12"
+       RETURN
+    END IF
+    CALL NEW(orb, elements, "cartesian", "ecliptic", t)
+    IF (error) THEN
+       errstr = "error13"
+       RETURN
+    END IF
+    elements = getCometaryElements(orb, qei_only=.TRUE.)
+    IF (error) THEN
+       errstr = "error14"
+       RETURN
+    END IF
+    CALL NULLIFY(orb)
+    CALL NULLIFY(t)
+    elements(1) = elements(1)/(1.0_bp-elements(2))
+    aeidist = SQRT(SUM((ABS(elements(1:3)-param(4:6))/param(4:6))**2))
+
+  END FUNCTION aeidist
+
+
+
+
+
+  REAL(bp) FUNCTION xyzdist(ptry,param,errstr)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(:), INTENT(in) :: ptry
+    REAL(bp), DIMENSION(:), INTENT(in) :: param
+    CHARACTER(len=*), INTENT(inout) :: errstr
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp), DIMENSION(3) :: nam
+
+    nam = ptry 
+    elements = (/ param(1:3), nam /)
+    CALL NEW(t, param(7), "TT")
+    IF (error) THEN
+       errstr = "error12"
+       RETURN
+    END IF
+    CALL NEW(orb, elements, "keplerian", "ecliptic", t)
+    IF (error) THEN
+       errstr = "error13"
+       RETURN
+    END IF
+    elements = getCartesianElements(orb, "ecliptic")
+    IF (error) THEN
+       errstr = "error14"
+       RETURN
+    END IF
+    CALL NULLIFY(orb)
+    CALL NULLIFY(t)
+    xyzdist = SQRT(SUM((elements(1:3)-param(4:6))**2))
+
+  END FUNCTION xyzdist
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Checks the orbit, bound/unbound.
+  !!
+  !! Returns error.
+  !!
+  LOGICAL FUNCTION boundOrbit(this, smamax, sma)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)     :: this
+    REAL(bp), INTENT(in)            :: smamax
+
+    REAL(bp), OPTIONAL, INTENT(out) :: sma
+    REAL(bp), DIMENSION(6)          :: elements
+    REAL(bp)                        :: a, r, alpha, tmp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / boundOrbit", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getCartesianElements(this,"equatorial")
+    IF (error) THEN
+       CALL errorMessage("Orbit / boundOrbit", &
+            "TRACE BACK 1",1)
+       RETURN
+    END IF
+
+    r = SQRT(DOT_PRODUCT(elements(1:3),elements(1:3)))
+    ! alpha = rv^2/mu
+    alpha = r*DOT_PRODUCT(elements(4:6),elements(4:6))/planetary_mu(this%central_body)
+    ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+    ! -> a = r / (2 - rv^2/mu)
+    tmp = 2.0_bp - alpha
+    IF (ABS(tmp) < 100.0_bp*EPSILON(tmp)) THEN
+       boundOrbit = .FALSE.
+       RETURN
+    END IF
+    a = r / tmp
+
+    IF (PRESENT(sma)) THEN
+       sma = a
+    END IF
+
+    ! Make sure the semimajor axis is within the boundary values.
+    ! Lower bound:
+    IF (a < planetary_radii(this%central_body)) THEN
+       boundOrbit = .FALSE.
+       RETURN
+    END IF
+    ! Upper bound:
+    IF (a > smamax) THEN
+       boundOrbit = .FALSE.
+       RETURN
+    END IF
+
+    boundOrbit = .TRUE.
+
+  END FUNCTION boundOrbit
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The continued fraction for computing the orbit parameter
+  !! Comments: Based on f77 routine by Karri Muinonen,
+  !!           partly based on software written by Olof Hernius.  
+  !! 
+  !! Reference: "The determination of orbits" (1961), A. D. Dubyago.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE continuedFraction(h, tol, sector_to_triangel_ratio, &
+       dsector_to_triangel_ratio)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: h, tol
+    REAL(bp), INTENT(out) :: sector_to_triangel_ratio, &
+         dsector_to_triangel_ratio
+    INTEGER, PARAMETER :: niter = 10000
+    REAL (bp) :: tmp1, tmp2, d1, d2
+    INTEGER :: i
+
+    d1 = 10.0_bp/11.0_bp
+    d2 = 11.0_bp/9.0_bp
+    tmp1 = d2*h/(1.0_bp+d2*h)
+    tmp2 = tmp1
+    DO i=1,niter
+       tmp1 = d2*h/(1.0_bp + tmp1)
+       dsector_to_triangel_ratio = ABS(tmp1-tmp2)
+       IF (dsector_to_triangel_ratio < tol) THEN
+          sector_to_triangel_ratio = 1.0_bp + d1*tmp1
+          RETURN
+       END IF
+       tmp2 = tmp1
+    END DO
+
+  END SUBROUTINE continuedFraction
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes an estimate for the cosine of the true anomaly
+  !! difference.
+  !! 
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION estimateCosDf(this, ccoord, p, y)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: ccoord
+    REAL(bp), INTENT(in)                    :: p
+    INTEGER, INTENT(in)                     :: y
+    TYPE (Orbit)                            :: orb
+    TYPE (Time)                             :: t1
+    REAL(bp), DIMENSION(3)                  :: pos0, pos1, pos, vel0
+    REAL(bp)                                :: r0, r1, cdf, sdf, f, g
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / estimateCosDf", &
+            "This object has not yet been initialized.", 1)
+       RETURN       
+    END IF
+
+    IF (this%element_type /= "cartesian") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / estimateCosDf", &
+            "Orbital elements must be Cartesian.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(ccoord)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / estimateCosDf", &
+            "Second position has not been initialized.", 1)
+       RETURN       
+    END IF
+
+    pos0 = this%elements(1:3)
+    pos1 = getPosition(ccoord)
+
+    r0  = SQRT(DOT_PRODUCT(pos0,pos0))
+    r1  = SQRT(DOT_PRODUCT(pos1,pos1))
+    cdf = DOT_PRODUCT(pos0,pos1) / (r0*r1)
+    sdf = y * SQRT(ABS(1.0_bp - cdf**2))
+
+    f = (r1/p)*(cdf - 1.0_bp) + 1.0_bp
+    g = ((r0*r1) / SQRT(planetary_mu(this%central_body)*p)) * sdf
+    IF (ABS(g) < TINY(g)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / estimateCosDf", &
+            "Attempted division by zero (g-function).", 1)
+       RETURN
+    END IF
+    vel0 = (pos1 - f*pos0)/g
+    orb = copy(this)
+    orb%elements(4:6) = vel0
+    t1 = getTime(ccoord)
+    CALL propagate(orb, t1)
+    IF (error) THEN
+       CALL errorMessage("Orbit / estimateCosDf", &
+            "TRACE BACK 4", 1)
+       RETURN
+    END IF
+    pos = orb%elements(1:3)
+    estimateCosDf = DOT_PRODUCT(pos0,pos) / (r0*SQRT(DOT_PRODUCT(pos,pos)))
+
+    CALL NULLIFY(orb)
+
+  END FUNCTION estimateCosDf
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Calculates the Jacobian matrix of final coordinates wrt initial
+  !! coordinates when Gauss' f- and g-functions are used.
+  !!
+  SUBROUTINE GaussfgJacobian_Orb(this, r0, u, alpha, stumpff_cs, s, &
+       f, g, df, dg, pos, r1, jacobian)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)              :: this
+    REAL(bp), INTENT(in)                  :: r0, u, alpha, s, f, g, df, dg, r1
+    REAL(bp), DIMENSION(0:3), INTENT(in)  :: stumpff_cs
+    REAL(bp), DIMENSION(3), INTENT(in)    :: pos
+    REAL(bp), DIMENSION(6,6), INTENT(out) :: jacobian
+    REAL(bp), PARAMETER                   :: tol = 1.0e-20_bp
+    REAL(bp), DIMENSION(6,3)              :: tmp_S, pstumpff_cs
+    REAL(bp), DIMENSION(6)                :: pr0, pdr0, palpha, pr1, tmp_A, &
+         tmp_B, tmp_C, ps, tmp_e, pf, pg, pdf, pdg
+    REAL(bp)                              :: dr0, tmp_d, mu_
+    INTEGER                               :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / GaussfgJacobian", &
+            "This object has not yet been initialized.", 1)
+       RETURN       
+    END IF
+
+    IF (ABS(r0) < tol .OR. ABS(alpha) < tol .OR. &
+         ABS(s) < tol .OR. ABS(r1) < tol) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / GaussfgJacobian", &
+            "Preliminary criterions are not fulfilled.", 1)
+       RETURN
+    END IF
+
+    ! Define mu parameter
+    mu_ = planetary_mu(this%central_body)
+
+    ! Partial derivatives of r0, dr0, and alpha.
+    pr0(1:3)    = this%elements(1:3)/r0
+    pr0(4:6)    = 0
+    dr0         = u/r0
+    pdr0(1:3)   =  -this%elements(1:3)*dr0/r0**2 + this%elements(4:6)/r0
+    pdr0(4:6)   = this%elements(1:3)/r0
+    palpha(1:3) = -2.0_bp*mu_/r0**3.0_bp*this%elements(1:3) 
+    palpha(4:6) = -2.0_bp*this%elements(4:6)
+
+    ! Partial derivatives of s.
+    tmp_A = pr0*stumpff_cs(1) + (pr0*dr0+r0*pdr0)*stumpff_cs(2)
+    tmp_B = (r0-mu_/alpha)*(stumpff_cs(1) - s*stumpff_cs(0)) + &
+         (2.0_bp*stumpff_cs(2)-s*stumpff_cs(1))*u + 2.0_bp*mu_*stumpff_cs(3)
+    tmp_C = (r0*stumpff_cs(1) + 2.0_bp*u*stumpff_cs(2) + &
+         3.0_bp*mu_*stumpff_cs(3) - tmp_B)/s
+    IF (ANY(ABS(tmp_C) < tol)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / GaussfgJacobian", &
+            "Criterions are not fulfilled.", 1)
+       RETURN
+    END IF
+    ps = (0.5_bp*palpha/alpha*tmp_B - tmp_A)/tmp_C
+
+    ! Partial derivatives of Stumpff-functions 1-3 (0 not needed).
+    tmp_d      = 1/(alpha*s**2.0_bp)
+    tmp_e      = palpha*s**2.0_bp + 2.0_bp*s*alpha*ps
+    tmp_S(:,1) = 0.5_bp*tmp_d*(s*stumpff_cs(0)-stumpff_cs(1))*tmp_e
+    tmp_S(:,2) = tmp_d*(0.5_bp*s*stumpff_cs(1)-stumpff_cs(2))*tmp_e
+    tmp_S(:,3) = tmp_d*(0.5_bp*tmp_d*s**2_bp*(stumpff_cs(1)-s*stumpff_cs(0)) &
+         -stumpff_cs(3))*tmp_e
+
+    pstumpff_cs(:,1) = ps*stumpff_cs(1)/s+tmp_S(:,1)
+    pstumpff_cs(:,2) = 2.0_bp*ps*stumpff_cs(2)/s+tmp_S(:,2)
+    pstumpff_cs(:,3) = 3.0_bp*ps*stumpff_cs(3)/s+tmp_S(:,3)
+
+    ! Partial derivatives of Gauss" f- and g-functions
+    ! and the Jacobian.
+    pf  = mu_/r0*(pr0/r0*stumpff_cs(2)-pstumpff_cs(:,2))
+    pg  = -mu_*pstumpff_cs(:,3)
+
+    DO i=1,3
+       jacobian(i,:)   = pf*this%elements(i) + pg*this%elements(3+i)
+       jacobian(i,i)   = jacobian(i,i) + f
+       jacobian(i,i+3) = jacobian(i,i+3) + g
+    END DO
+    DO i=1,6
+       pr1(i) = DOT_PRODUCT(pos,jacobian(1:3,i))/r1
+    END DO
+    pdf = mu_/(r0*r1)*((pr0/r0+pr1/r1)*stumpff_cs(1) - pstumpff_cs(:,1))
+    pdg = mu_/r1*(pr1/r1*stumpff_cs(2) - pstumpff_cs(:,2))
+    DO i=4,6
+       jacobian(i,:)   = pdf*this%elements(i-3) + pdg*this%elements(i)
+       jacobian(i,i-3) = jacobian(i,i-3) + df
+       jacobian(i,i)   = jacobian(i,i) + dg
+    END DO
+
+  END SUBROUTINE GaussfgJacobian_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the apoapsis distance Q for the input orbit. The
+  !! semimajor axis 'a' is computed if it is not given as a
+  !! parameter. Optionally, returns partial derivatives between Q and
+  !! Keplerian elements.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getApoapsisDistance_Orb(this, Q, a, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                      :: this
+    REAL(bp), INTENT(out)                         :: Q
+    REAL(bp), INTENT(in), OPTIONAL                :: a
+    REAL(bp), DIMENSION(6), INTENT(out), OPTIONAL :: partials ! Partials
+
+    TYPE (Orbit) :: this_
+    REAL(bp), DIMENSION(3) :: pos, vel
+    REAL(bp) :: a_, e, r, e_sin_ea, e_cos_ea, alpha, gamma
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getApoapsisDistance", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cometary")
+
+       IF (this%elements(2) < 1.0_bp) THEN
+          ! Elliptic orbit
+          Q = this%elements(1) * &
+               (1.0_bp + this%elements(2)) / &
+               (1.0_bp - this%elements(2))
+       ELSE
+          ! Parabolic or hyperbolic orbit
+          Q = HUGE(Q)
+       END IF
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1:2) = (/ 1.0_bp + this%elements(2), this%elements(1) / &
+               (1.0_bp - this%elements(2)) /)
+       END IF
+
+    CASE ("keplerian")
+
+       Q = this%elements(1)*(1.0_bp+this%elements(2))
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1:2) = (/ 1.0_bp + this%elements(2), this%elements(1) /)
+       END IF
+
+    CASE ("cartesian")
+
+       this_ = copy(this)
+       CALL rotateToEcliptic(this_)
+       pos = this_%elements(1:3)
+       vel = this_%elements(4:6)
+       r = SQRT(DOT_PRODUCT(pos,pos))
+       ! alpha = rv^2/mu
+       alpha = r*DOT_PRODUCT(vel,vel)/planetary_mu(this_%central_body)
+       IF (PRESENT(a)) THEN
+          a_ = a
+       ELSE
+          ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+          ! -> a = r / (2 - rv^2/mu)
+          IF (ABS(2.0_bp - alpha) < 10.0_bp*EPSILON(alpha)) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getApoapsisDistance", &
+                  "a is approaching infinity.", 1)
+             RETURN
+          END IF
+          a_ = r / (2.0_bp - alpha)
+          IF (a_ < 0.0_bp) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getApoapsisDistance", &
+                  "Semimajor axis is negative.", 1)
+             RETURN
+          END IF
+       END IF
+       ! gamma = sqrt(mu*a)
+       gamma = SQRT(planetary_mu(this_%central_body)*a_)
+       IF (ABS(gamma) < TINY(gamma)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "Gamma is computationally too small.", 1)
+          RETURN
+       END IF
+       ! r(1+e*cos(f))=a|1-e^2|, r*cos(f)=a*cos(E)-ae, and for elliptical 
+       ! orbits a=r/(2-rv^2/mu) (see above) and |1-e^2|=1-e^2
+       ! -> e*cos(E)=rv^2/mu-1=alpha-1
+       e_cos_ea = alpha - 1.0_bp
+       !
+       e_sin_ea = DOT_PRODUCT(pos,vel)/gamma
+       e = SQRT(e_cos_ea**2.0_bp + e_sin_ea**2.0_bp)
+       IF (e > 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "Orbit is hyperbolic.", 1)
+          RETURN
+       ELSE IF (e < 10.0_bp*EPSILON(e)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "Orbit is almost circular (1).", 1)
+          WRITE(stderr,*) e
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+       Q = a_*(1.0_bp + e)
+
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1:2) = (/ 1.0_bp + e, a_ /)
+       END IF
+
+    END SELECT
+
+  END SUBROUTINE getApoapsisDistance_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns Cartesian orbital elements.
+  !!
+  !!   - array(1) = x
+  !!   - array(2) = y
+  !!   - array(3) = z
+  !!   - array(4) = dx/dt
+  !!   - array(5) = dy/dt
+  !!   - array(6) = dz/dt
+  !!
+  !!
+  !! *Usage*:
+  !!
+  !! elements = getCartesianElements(myorbit)
+  !! 
+  !! Returns error.
+  !!
+  FUNCTION getCartesianElements(this, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)     :: this
+    CHARACTER(len=*), INTENT(in) :: frame
+    REAL(bp), DIMENSION(6)       :: getCartesianElements
+
+    TYPE (Orbit) :: this_
+    TYPE (Time) :: t
+    CHARACTER(len=FRAME_LEN) :: frame_
+    REAL(bp), DIMENSION(3,3) :: R
+    REAL(bp), DIMENSION(6) :: celements
+    REAL(bp) :: sea, cea, ea, dot_ea, b
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCartesianElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    frame_ = frame
+    CALL locase(frame_, error)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getCartesianElements", &
+            "The frame string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    IF (frame_ /= "ecliptic" .AND. &
+         frame_ /= "equatorial") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCartesianElements", &
+            "Frame " // TRIM(frame_) // " not recognized.", 1)
+    END IF
+
+    IF (this%element_type == "cartesian") THEN
+       getCartesianElements(1:6) = this%elements(1:6)
+       IF (frame_ == "equatorial" .AND. &
+            this%frame /= "equatorial") THEN
+          CALL rotateToEquatorial(getCartesianElements(1:6))
+       ELSE IF (frame_ == "ecliptic" .AND. &
+            this%frame /= "ecliptic") THEN
+          CALL rotateToEcliptic(getCartesianElements(1:6))
+       END IF
+       RETURN
+    END IF
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cometary")
+
+       ! Make transformation cometary -> cartesian at periapsis:
+       celements(1:3) = (/ this%elements(1), 0.0_bp, 0.0_bp /)
+       ! v^2 = mu * (2/r - 1/a) = mu * (1+e)/q
+       celements(4:6) = (/ 0.0_bp, &
+            SQRT(planetary_mu(this%central_body) * &
+            (1.0_bp+this%elements(2))/this%elements(1)), 0.0_bp /)
+
+       ! Orbital-plane Cartesian elements to ecliptical Cartesian
+       ! elements:
+       R = getTransformationMatrix(this)
+       celements(1:3) = MATMUL(R,celements(1:3))
+       celements(4:6) = MATMUL(R,celements(4:6))
+
+       ! Propagate elements (must use 2b!) to the initial epoch
+       CALL NEW(t, this%elements(6), "TT")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       CALL NEW(this_, celements, "cartesian", "ecliptic", t)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL setParameters(this_, dyn_model="2-body")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       CALL propagate(this_, this%t)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       getCartesianElements = getElements(this_, "cartesian", frame_)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (30)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+       CALL NULLIFY(t)
+
+    CASE ("cometary_ta")
+
+       this_ = copy(this)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (35)", 1)
+          RETURN
+       END IF
+       CALL toCometary(this_)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (40)", 1)
+          RETURN
+       END IF
+       getCartesianElements = getElements(this_, "cartesian", frame_)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+
+    CASE ("keplerian")
+
+       ! Compute needed quantities:
+       CALL solveKeplerEquation(this, this%t, ea)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCartesianElements", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       cea = COS(ea)
+       sea = SIN(ea)
+       b = this%elements(1) * SQRT(1.0_bp - this%elements(2)**2.0_bp)
+       dot_ea = SQRT(planetary_mu(this%central_body)/this%elements(1)**3.0_bp)/(1.0_bp - this%elements(2)*cea)
+
+       ! Keplerian elements to polar Cartesian elements:
+       ! -positions:
+       celements(1) = this%elements(1)*(cea - this%elements(2))
+       celements(2) = b*sea
+       celements(3) = 0.0_bp
+       ! -velocities:
+       celements(4) = -this%elements(1)*dot_ea*sea
+       celements(5) = b*dot_ea*cea
+       celements(6) = 0.0_bp
+
+       ! Polar Cartesian elements to ecliptical Cartesian elements:
+       R = getTransformationMatrix(this)
+       celements(1:3) = MATMUL(R,celements(1:3))
+       celements(4:6) = MATMUL(R,celements(4:6))
+
+       IF (frame_ == "equatorial") THEN
+          CALL rotateToEquatorial(celements)
+       END IF
+       getCartesianElements(1:6) = celements(1:6)
+
+    CASE default
+
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCartesianElements", &
+            "Conversion from " // TRIM(this%element_type) // &
+            " elements to cartesian elements has not yet been implemented.", 1)
+       RETURN
+
+    END SELECT
+
+  END FUNCTION getCartesianElements
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns cartesian heliocentric coordinates.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getCCoord_Orb(this, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)    :: this
+    TYPE (CartesianCoordinates) :: getCCoord_Orb
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+    CHARACTER(len=FRAME_LEN) :: frame_
+    REAL(bp), DIMENSION(6) :: celements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+       CALL locase(frame_, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getCCoord", &
+               "The frame string contains forbidden characters.", 1)
+          RETURN
+       END IF
+    ELSE IF (this%element_type == "cartesian") THEN
+       frame_ = this%frame
+    ELSE IF (.NOT.PRESENT(frame)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCCoord", &
+            "Frame missing when using Keplerian or cometary input elements.", 1)
+       RETURN       
+    END IF
+
+    celements(1:6) = getCartesianElements(this, frame=frame_)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getCCoord", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    CALL NEW(getCCoord_Orb, celements, frame_, copy(this%t))
+    IF (error) THEN
+       CALL errorMessage("Orbit / getCCoord", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getCCoord_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Calculates the cometary orbital elements from the heliocentric
+  !! (ecliptical or equatorial) Cartesian orbital elements, Keplerian
+  !! elements, or modified cometary elements (true anomaly instead of
+  !! time of perihelion) for the current epoch.
+  !!
+  !! Note that the time of perihelion of elliptic orbits is the
+  !! closest one in time.
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getCometaryElements(this, qei_only)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    LOGICAL, INTENT(in), OPTIONAL :: qei_only
+
+    REAL(bp), DIMENSION(6)   :: getCometaryElements
+    TYPE (Orbit) :: this_
+    !! The following four tolerance parameters have been tuned using
+    !! PS S3M populations SI, SL, and SH (Earth impactors, long-period
+    !! comets, hyperbolic objects). Nearly-parabolic orbits with
+    !! eccentricities having offsets larger than 10^(-13) from unity
+    !! should be correctly converted to cometary elements. The
+    !! relative error of the conversion com->car->com is, e.g, < 10^-7
+    !! for SI whereas for e~1-10^-13 SL orbits the error on q is up to
+    !! 0.2%. Note that the latter is only true for e~1-10^-13 orbits,
+    !! not for e~1+10^-13 orbits which are a lot more accurate!
+    !! REAL(bp), PARAMETER :: tol1 = 1.0e-6_bp
+    !! REAL(bp), PARAMETER :: tol2 = 1.0e-8_bp
+    !! REAL(bp), PARAMETER :: tol3 = 1.0e-11_bp
+    !! REAL(bp), PARAMETER :: tol4 = 1.0e-3_bp
+    !! The tolerances have subsequently been updated using the S1b
+    !! population and when generating initial orbits for the tidal
+    !! disruption studies.
+    REAL(bp), PARAMETER :: tol1 = 1.0e-6_bp
+    REAL(bp), PARAMETER :: tol2 = 1.0e-6_bp
+    REAL(bp), PARAMETER :: tol3 = 1.0e-10_bp
+    REAL(bp), PARAMETER :: tol4 = 1.0e-3_bp
+    INTEGER, PARAMETER :: max_iter = 100
+    REAL(bp), DIMENSION(0:3) :: stumpff_c, stumpff_cs
+    REAL(bp), DIMENSION(3) :: pos, vel, k, cos_angles, evec, fb, gb
+    REAL(bp) :: r0, ru, alpha, a, e, i, an, ap, varpi, tmp1, tmp2, &
+         div, q, tp, r, rp, rpp, xv, s, ds, x, dt, cosu, u0, mjd_tt, &
+         p, ea, sin_ea, cos_ea, ma, mm
+    INTEGER :: iiter
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getCometaryElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Return initial elements if error occurs:
+    getCometaryElements(1:6) = this%elements(1:6)
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cometary")
+
+       ! Return immediately if elements are cometary
+       RETURN
+
+    CASE ("cometary_ta")
+
+       this_ = copy(this)
+       IF (this%elements(2) < 1.0_bp) THEN
+          ! cos(ea) = (cos(f)+e)/(1+e*cos(f))
+          cos_ea = (COS(this%elements(6)) + this%elements(2)) / &
+               (1.0_bp + this%elements(2)*COS(this%elements(6)))
+          ! sin(ea) = sqrt(1-e^2)*sin(f)/(1+e*cos(f))
+          sin_ea = SQRT(1.0_bp - this%elements(2)**2.0_bp)*SIN(this%elements(6)) / &
+               (1.0_bp + this%elements(2)*COS(this%elements(6)))
+          ea = ATAN2(sin_ea,cos_ea)
+          ma = ea - this%elements(2)*SIN(ea)
+          ! Time of periapsis:
+          mm = SQRT((this_%elements(1) / &
+               (1.0_bp-this_%elements(2)))**3.0_bp / &
+               planetary_mu(this_%central_body))
+          mjd_tt = getMJD(this_%t,"TT")
+          dt = ma * mm
+          p = two_pi * mm
+          ! Select the closest time of perihelion:
+          IF (ma <= pi) THEN
+             getCometaryElements(6) = mjd_tt - dt
+          ELSE
+             getCometaryElements(6) = mjd_tt + (p - dt)
+          END IF
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("Orbit / getCometaryElements", &
+               "Conversion from ta to tp not yet available for e>=1 orbits.", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+
+    CASE ("keplerian")
+
+       this_ = copy(this)
+       ! Distance of periapsis:
+       getCometaryElements(1) = &
+            this_%elements(1) * (1.0_bp - this_%elements(2))
+       ! period p:
+       mjd_tt = getMJD(this_%t,"TT")
+       mm = SQRT(this_%elements(1)**3.0_bp / planetary_mu(this_%central_body))
+       dt = this_%elements(6) * mm
+       p = two_pi * mm
+       ! Remove full periods from dt:
+       IF (dt > p) THEN
+          dt = MODULO(dt,p)
+       END IF
+       ! Select the closest time of perihelion:
+       IF (this_%elements(6) <= pi) THEN
+          getCometaryElements(6) = mjd_tt - dt
+       ELSE
+          getCometaryElements(6) = mjd_tt + (p - dt)
+       END IF
+       CALL NULLIFY(this_)
+
+    CASE ("cartesian")
+
+       this_ = copy(this)
+       CALL rotateToEcliptic(this_)
+
+       ! Semimajor axis, eccentricity and mean anomaly:
+       pos = this_%elements(1:3)
+       r0  = SQRT(DOT_PRODUCT(pos,pos))
+       vel = this_%elements(4:6)
+       ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+       ! -> a = r / (2 - rv^2/mu)
+       ! Semimajor axis (a<0 for e>1 orbits):
+       a = r0 / (2.0_bp - r0*DOT_PRODUCT(vel,vel) / &
+            planetary_mu(this_%central_body))
+       ! Angular momentum:
+       k = cross_product(pos,vel)
+       ! Eccentricity vector:
+       evec = cross_product(vel,k)/planetary_mu(this_%central_body) - pos/r0
+       ! Eccentricity:
+       e = SQRT(DOT_PRODUCT(evec,evec))
+       ! Periapsis distance (note that if e>1 then a<0):
+       q = a * (1.0_bp - e)
+
+       ! Inclination and ascending node:
+       ru = SQRT(DOT_PRODUCT(k,k))
+       IF (ru < EPSILON(ru)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getCometaryElements", &   
+               "Position and velocity almost parallel.", 1)
+          RETURN
+       END IF
+       k = k/ru
+       cos_angles(1) = k(3)
+       IF (ABS(cos_angles(1)) > 1.0_bp) THEN
+          cos_angles(1) = SIGN(1.0_bp, cos_angles(1))
+       END IF
+       i = ACOS(cos_angles(1))
+       IF (PRESENT(qei_only)) THEN
+          IF (qei_only) THEN
+             ! Return (q,e,i) only
+             CALL NULLIFY(this_)
+             getCometaryElements = (/ q, e, i, -1.0_bp, -1.0_bp, -1.0_bp /)
+             RETURN
+          END IF
+       END IF
+       ! Notice computational abs!!
+       ru = SQRT(ABS(1.0_bp - k(3)**2.0_bp))
+       IF (ru < EPSILON(ru)) THEN
+          CALL errorMessage("Orbit / getCometaryElements", &
+               "Warning: Inclination (almost) zero, setting Longitude of Node to 0 deg.", 1)
+          an = 0.0_bp          
+       ELSE
+          cos_angles(2) = -k(2)/ru
+          IF (ABS(cos_angles(2)) > 1.0_bp) THEN
+             cos_angles(2) = SIGN(1.0_bp, cos_angles(2))
+          END IF
+          an = ACOS(cos_angles(2))
+          IF (k(1) < 0.0_bp) THEN
+             an = two_pi - an
+          END IF
+          IF (an == two_pi) THEN
+             an = 0.0_bp
+          END IF
+       END IF
+
+       ! Argument of periapsis:
+       div = 1.0_bp + k(3)
+       fb(1) = 1.0_bp - k(1)**2.0_bp/div
+       fb(2) = -k(1)*k(2)/div
+       fb(3) = -k(1)
+       gb = cross_product(k, fb)
+       tmp1 = DOT_PRODUCT(evec, gb)
+       tmp2 = DOT_PRODUCT(evec, fb)
+       varpi = ATAN2(tmp1, tmp2)
+       ap = varpi - an
+       ap = MODULO(ap,two_pi)
+       IF (ap == two_pi) THEN
+          ap = 0.0_bp
+       END IF
+
+       ! Time of periapsis
+       alpha = 2.0_bp*planetary_mu(this_%central_body)/r0 - &
+            DOT_PRODUCT(vel,vel)
+       xv = DOT_PRODUCT(pos,vel)
+       IF (alpha <= 0.0_bp) THEN
+          ! Hyperbolic orbit
+          cosu = (1.0_bp+r0/a)/e
+          IF (cosu <= -1.0_bp) THEN
+             u0 = pi
+          ELSE IF (cosu >= 1.0_bp) THEN
+             u0 = 0.0_bp
+          ELSE
+             u0 = ACOS(cosu)
+          END IF
+          s = -SIGN(1.0_bp,xv)*u0/SQRT(-alpha)
+       ELSE
+          ! Elliptic orbit
+          IF (ABS(xv) > tol1) THEN
+             s = (q-r0)/xv
+          ELSE
+             s = 0.0_bp
+          END IF
+       END IF
+       DO iiter=1,max_iter
+          x = s**2.0_bp * alpha
+          CALL getStumpffFunctions(x, stumpff_c)
+          stumpff_cs(0) = stumpff_c(0)
+          stumpff_cs(1) = stumpff_c(1) * s
+          stumpff_cs(2) = stumpff_c(2) * s**2.0_bp
+          stumpff_cs(3) = stumpff_c(3) * s**3.0_bp
+          r = r0 * stumpff_cs(0) + xv * stumpff_cs(1) + &
+               planetary_mu(this_%central_body) * stumpff_cs(2)
+          rp = (-r0*alpha + planetary_mu(this_%central_body)) * &
+               stumpff_cs(1) + xv * stumpff_cs(0)
+          rpp = (-r0*alpha + planetary_mu(this_%central_body)) * &
+               stumpff_cs(0) - xv * alpha * stumpff_cs(1)
+          ds = -rp/rpp
+          s = s + ds
+          IF (ABS(ds) < tol2 .AND. ABS(rp) < tol3 .AND. &
+               (ABS(r-q) < tol4 .OR. ABS(r-q/(1.0_bp-e)*(1.0_bp+e)) < tol4)) THEN
+             EXIT
+          END IF
+       END DO
+       IF (ABS(ds) > tol2 .OR. ABS(rp) > tol3 .OR. &
+            (ABS(r-q) > tol4 .AND. ABS(r-q/(1.0_bp-e)*(1.0_bp+e)) > tol4)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getCometaryElements", &
+               "Computation of time of perihelion did not converge.", 1)
+          IF (err_verb >= 1) THEN
+             WRITE(stderr,*) "abs(ds) > tol2: ", ABS(ds) > tol2, &
+                  "(", ABS(ds), " > ", tol2, ") or"
+             WRITE(stderr,*) "abs(rp) > tol3: ", ABS(rp) > tol3, &
+                  "(", ABS(rp), " > ", tol3, ") or"
+             WRITE(stderr,*) "abs(r-q) > tol4 and abs(r-Q) > tol4: ", &
+                  ABS(r-q) > tol4 .AND. ABS(r-q/(1.0_bp-e)*(1.0_bp+e)) > tol4, &
+                  "(", ABS(r-q), " > ", tol4, " and ", &
+                  ABS(r-q/(1.0_bp-e)*(1.0_bp+e)), " > ", tol4, ")"
+          END IF
+          RETURN          
+       END IF
+       dt = r0 * stumpff_cs(1) + xv * stumpff_cs(2) + &
+            planetary_mu(this_%central_body)*stumpff_cs(3)
+       mjd_tt = getMJD(this_%t,"TT")
+       ! Choose the time of perihelion closest to the epoch in case of
+       ! an elliptic orbit:
+       IF (e < 1.0_bp) THEN
+          ! period p:
+          p = two_pi*SQRT(a**3.0_bp/planetary_mu(this_%central_body))
+          ! Remove full periods from dt:
+          IF (ABS(dt) > p) THEN
+             dt = MODULO(dt,p)
+          END IF
+          ! If dt refers to the time of aphelion, subtract (if dt>0,
+          ! otherwise add) half a period to get to perihelion (scale
+          ! tolerance with e to make sure ~circular orbits are
+          ! processed correctly):
+          IF (ABS(r-q/(1-e)*(1+e)) < tol4*e) THEN
+             dt = dt - SIGN(1.0_bp,dt) * 0.5_bp * p
+          END IF
+          ! Select the closest time of perihelion:
+          IF (ABS(dt) < ABS(dt - SIGN(1.0_bp,dt)*p)) THEN
+             tp = mjd_tt + dt
+          ELSE
+             tp = mjd_tt + dt - SIGN(1.0_bp,dt)*p
+          END IF
+       ELSE
+          ! For hyperbolic orbits always:
+          tp = mjd_tt + dt
+       END IF
+       CALL NULLIFY(this_)
+
+       getCometaryElements = (/ q, e, i, an, ap, tp /)
+
+    END SELECT
+
+  END FUNCTION getCometaryElements
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns Delaunay's elements calculated from Keplerian elements. The mass 
+  !! of the target body is assumed to be zero compared to the mass of the Sun.
+  !!
+  !!   - de(1) = l      = Mean Motion (Mean Anomaly)
+  !!   - de(2) = g      = Argument of Perihelion
+  !!   - de(3) = &theta = Longitude of the Ascending Node
+  !!   - de(4) = L      = sqrt(mu*(Semimajor Axis)) = related to the 
+  !!                                                  two-body orbital energy
+  !!   - de(5) = G      = L*sqrt(1-Eccentricity^2)  = magnitude of the orbital 
+  !!                                                  angular momentum
+  !!   - de(6) = &Theta = G*cos(Inclination)        = z-component of the orbital 
+  !!                                                  angular momentum
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getDelaunayElements(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)   :: getDelaunayElements
+    REAL(bp), DIMENSION(6)   :: kep
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getDelaunayElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    kep = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getDelaunayElements", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    getDelaunayElements(1) = kep(6)
+    getDelaunayElements(2) = kep(5)
+    getDelaunayElements(3) = kep(4)
+    getDelaunayElements(4) = SQRT(planetary_mu(this%central_body) * kep(1))
+    getDelaunayElements(5) = getDelaunayElements(4) * SQRT(1.0_bp - &
+         kep(2)**2.0_bp)
+    getDelaunayElements(6) = getDelaunayElements(5) * &
+         COS(kep(3))
+
+  END FUNCTION getDelaunayElements
+
+
+
+
+
+  FUNCTION getElements(this, element_type, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)        :: this
+    CHARACTER(len=*), INTENT(in)    :: element_type
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+    REAL(bp), DIMENSION(6)          :: getElements
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type_
+    REAL(bp), DIMENSION(6)          :: elem
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (LEN_TRIM(element_type) > ELEMENT_TYPE_LEN) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getElements", &
+            "Element type indicator too long.", 1)
+       RETURN       
+    END IF
+
+    element_type_ = element_type
+    CALL locase(element_type_, error)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getElements", &
+            "The element type string ('" // TRIM(element_type_) &
+            // "') contains forbidden characters.", 1)
+       RETURN
+    END IF
+    SELECT CASE (element_type_)
+    CASE ("cometary")
+       getElements = getCometaryElements(this)
+    CASE ("keplerian")
+       getElements = getKeplerianElements(this)
+    CASE ("cartesian")
+       IF (PRESENT(frame)) THEN
+          getElements = getCartesianElements(this, frame)
+       ELSE IF (this%element_type == "cartesian") THEN
+          getElements = getCartesianElements(this, this%frame)
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("Orbit / getElements", &
+               "Frame must be given explicitly if Keplerian " // &
+               "elements are to be converted to Cartesian elements.", 1)
+          RETURN
+       END IF
+    CASE ("delaunay")
+       getElements = getDelaunayElements(this)
+    CASE ("poincare")
+       getElements = getPoincareElements(this)
+    CASE ("equinoctial")
+       ! Ref. Milani 1999, Icarus 137, pp. 269--292
+       elem = getKeplerianElements(this)
+       getElements(1) = elem(1)
+       getElements(2) = elem(2)*SIN(elem(4) + elem(5))
+       getElements(3) = elem(2)*COS(elem(4) + elem(5))
+       getElements(4) = TAN(elem(3)/2.0_bp)*SIN(elem(4))
+       getElements(5) = TAN(elem(3)/2.0_bp)*COS(elem(4))
+       getElements(6) = MODULO(SUM(elem(4:6)), two_pi)
+    CASE default
+       error = .TRUE.
+       CALL errorMessage("Orbit / getElements", &
+            "Unkown option: " // TRIM(element_type_) // ".", 1)
+       RETURN       
+    END SELECT
+    IF (error) THEN
+       CALL errorMessage("Orbit / getElements", &
+            "TRACE BACK", 1)
+       RETURN       
+    END IF
+
+  END FUNCTION getElements
+
+
+
+
+
+  CHARACTER(len=ELEMENT_TYPE_LEN) FUNCTION getElementType(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getElementType", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getElementType = this%element_type
+
+  END FUNCTION getElementType
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial light-time-corrected
+  !! coordinates from the object's heliocentric Cartesian orbit and 
+  !! the observers" heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial light-time-corrected coordinates
+  !! wrt object's orbital elements are calculated. The output format
+  !! of partial derivatives is (row;column;observer). Optionally,
+  !! the light-time corrected orbit is returned.
+  !! 
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemerides_Orb_single(this, observers, ephemerides, &
+       lt_corr, partials_arr, this_lt_corr_arr)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                              :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: observers
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER    :: ephemerides
+    LOGICAL, INTENT(in), OPTIONAL                         :: lt_corr
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL         :: partials_arr
+    TYPE (Orbit), DIMENSION(:), POINTER, OPTIONAL         :: this_lt_corr_arr
+
+    TYPE (Orbit), DIMENSION(1)                           :: this_arr
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: ephemerides_arr
+    REAL(bp), DIMENSION(:,:,:,:), POINTER                :: partials_arr_
+    TYPE (Orbit), DIMENSION(:,:), POINTER                :: this_lt_corr_arr_
+    INTEGER                                              :: i, err, nobsy
+    LOGICAL                                              :: lt_corr_
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (single)", &
+            "Object has not yet been initialized.", 1)
+       RETURN       
+    END IF
+
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+    nobsy = SIZE(observers,dim=1)
+    this_arr(1) = copy(this)
+    IF (PRESENT(partials_arr)) THEN 
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          CALL getEphemerides(this_arr, observers, ephemerides_arr, &
+               lt_corr=lt_corr_, partials_arr=partials_arr_, &
+               this_lt_corr_arr=this_lt_corr_arr_)
+       ELSE
+          CALL getEphemerides(this_arr, observers, ephemerides_arr, &
+               lt_corr=lt_corr_, partials_arr=partials_arr_)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(partials_arr_, stat=err)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(partials_arr(6,6,nobsy), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "Could not allocate memory (5).", 1)
+          DEALLOCATE(partials_arr_, stat=err)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          RETURN       
+       END IF
+       partials_arr = partials_arr_(1,:,:,:)
+       DEALLOCATE(partials_arr_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "Could not deallocate memory (5).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          RETURN       
+       END IF
+    ELSE
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          CALL getEphemerides(this_arr, observers, ephemerides_arr, &
+               lt_corr=lt_corr_, &
+               this_lt_corr_arr=this_lt_corr_arr_)
+       ELSE
+          CALL getEphemerides(this_arr, observers, ephemerides_arr, &
+               lt_corr=lt_corr_)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "TRACE BACK (10)", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(this_lt_corr_arr)) THEN
+       ALLOCATE(this_lt_corr_arr(nobsy), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+          RETURN       
+       END IF
+       DO i=1,nobsy
+          this_lt_corr_arr(i) = copy(this_lt_corr_arr_(1,i))
+       END DO
+       DEALLOCATE(this_lt_corr_arr_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+          RETURN       
+       END IF
+    END IF
+    IF (ASSOCIATED(ephemerides)) THEN
+       DEALLOCATE(ephemerides, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (single)", &
+               "Could not allocate memory (12).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(ephemerides(nobsy), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (single)", &
+            "Could not allocate memory (15).", 1)
+       DEALLOCATE(ephemerides_arr, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       RETURN       
+    END IF
+    DO i=1,nobsy
+       ephemerides(i) = copy(ephemerides_arr(1,i))
+    END DO
+    DEALLOCATE(ephemerides_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (single)", &
+            "Could not allocate memory (15).", 1)
+       DEALLOCATE(ephemerides, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       RETURN       
+    END IF
+    CALL NULLIFY(this_arr(1))
+
+  END SUBROUTINE getEphemerides_Orb_single
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial light-time-corrected
+  !! coordinates from the object's heliocentric Cartesian orbit and 
+  !! the observers" heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial light-time-corrected coordinates
+  !! wrt object's orbital elements are calculated. The output format
+  !! of partial derivatives is (orbit;row;column;observer). Optionally,
+  !! the light-time corrected orbit is returned.
+  !! 
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemerides_Orb_multiple(this_arr, observers, ephemerides, &
+       lt_corr, partials_arr, this_lt_corr_arr)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:), INTENT(in)                :: this_arr
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: observers
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER  :: ephemerides
+    LOGICAL, INTENT(in), OPTIONAL                         :: lt_corr
+    REAL(bp), DIMENSION(:,:,:,:), POINTER, OPTIONAL       :: partials_arr
+    TYPE (Orbit), DIMENSION(:,:), POINTER, OPTIONAL       :: this_lt_corr_arr
+
+    TYPE (Orbit), DIMENSION(:), POINTER                 :: this_prop_arr_next
+    TYPE (Orbit), DIMENSION(:), ALLOCATABLE             :: this_prop_arr_current
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: ephemerides_
+    TYPE (Orbit), DIMENSION(:), POINTER                 :: this_lt_corr_arr_
+    TYPE (Time)                                         :: t
+    CHARACTER(len=FRAME_LEN), DIMENSION(:), ALLOCATABLE :: frames
+    REAL(bp), DIMENSION(:,:,:), POINTER                 :: partials_arr_, jacobian_prop_arr
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE             :: jacobian_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE                 :: mjd_tt_arr
+    REAL(bp)                                            :: mjd_tt_orb
+    INTEGER, DIMENSION(:), ALLOCATABLE                  :: indx_arr, indx_smaller, indx_larger
+    INTEGER                                             :: i, j, k, err, nthis, nobsy, indx
+    LOGICAL                                             :: lt_corr_
+
+    nthis = SIZE(this_arr)
+    nobsy = SIZE(observers)
+    ALLOCATE(this_prop_arr_current(nthis), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       RETURN
+    END IF
+    DO i=1,nthis
+       IF (.NOT.this_arr(i)%is_initialized) THEN
+          error = .TRUE.
+          DEALLOCATE(this_prop_arr_current, stat=err)
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "All objects have not yet been initialized.", 1)
+          RETURN       
+       END IF
+       this_prop_arr_current(i) = copy(this_arr(i))
+    END DO
+    ALLOCATE(ephemerides(nthis,nobsy), frames(nthis), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not allocate memory (10).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       DEALLOCATE(frames, stat=err)
+       RETURN
+    END IF
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+    IF (PRESENT(partials_arr)) THEN
+       ALLOCATE(partials_arr(nthis,6,6,SIZE(observers)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "Could not allocate memory (15).", 1)
+          DEALLOCATE(this_prop_arr_current, stat=err)
+          DEALLOCATE(ephemerides, stat=err)
+          DEALLOCATE(frames, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(jacobian_arr(nthis,6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "Could not allocate memory (20).", 1)
+          DEALLOCATE(this_prop_arr_current, stat=err)
+          DEALLOCATE(ephemerides, stat=err)
+          DEALLOCATE(frames, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(jacobian_arr, stat=err)
+          RETURN
+       END IF
+       DO i=1,nthis
+          jacobian_arr(i,:,:) = identity_matrix(6)
+       END DO
+    END IF
+    IF (PRESENT(this_lt_corr_arr)) THEN
+       ALLOCATE(this_lt_corr_arr(nthis,nobsy), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "Could not allocate memory (25).", 1)
+          DEALLOCATE(this_prop_arr_current, stat=err)
+          DEALLOCATE(ephemerides, stat=err)
+          DEALLOCATE(frames, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    ! This section splits ephemeris dates to two different groups:
+    ! 1) those earlier than the orbit epoch and 2) those later than
+    ! the orbit epoch:
+    mjd_tt_orb = getMJD(this_prop_arr_current(1)%t, "TT")
+    ALLOCATE(mjd_tt_arr(nobsy), indx_arr(nobsy), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not allocate memory (30).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       DEALLOCATE(frames, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       DEALLOCATE(jacobian_arr, stat=err)
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       DEALLOCATE(mjd_tt_arr, stat=err)
+       DEALLOCATE(indx_arr, stat=err)
+       RETURN
+    END IF
+    DO i=1,nobsy
+       t = getTime(observers(i))
+       mjd_tt_arr(i) = getMJD(t, "TT")
+       CALL NULLIFY(t)
+    END DO
+    CALL quicksort(mjd_tt_arr, indx_arr, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            TRIM(errstr), 1)
+       RETURN
+    END IF
+    indx = findLocation(mjd_tt_orb, mjd_tt_arr, indx_arr)
+    ! NB: Here we use tricks possible with Fortran. The arrays below 
+    ! have indices from 1:indx-1 and indx:nobsy, that is, the second
+    ! one does not generally start from 0 or 1
+    ALLOCATE(indx_smaller(1:indx-1), &
+         indx_larger(indx:SIZE(observers)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not allocate memory (35).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       DEALLOCATE(frames, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       DEALLOCATE(jacobian_arr, stat=err)
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       DEALLOCATE(mjd_tt_arr, stat=err)
+       DEALLOCATE(indx_arr, stat=err)
+       DEALLOCATE(indx_smaller, stat=err)
+       DEALLOCATE(indx_larger, stat=err)
+       RETURN
+    END IF
+    indx_smaller(1:indx-1) = indx_arr(1:indx-1)
+    indx_larger(indx:) = indx_arr(indx:)
+    DEALLOCATE(mjd_tt_arr, indx_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not deallocate memory (5).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       DEALLOCATE(frames, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       DEALLOCATE(jacobian_arr, stat=err)
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       DEALLOCATE(mjd_tt_arr, stat=err)
+       DEALLOCATE(indx_arr, stat=err)
+       DEALLOCATE(indx_smaller, stat=err)
+       DEALLOCATE(indx_larger, stat=err)
+       RETURN
+    END IF
+
+    DO i=1,nthis
+       IF (this_prop_arr_current(i)%element_type == "cartesian" &
+            .AND. this_prop_arr_current(i)%frame == "ecliptic") THEN
+          frames(i) = this_prop_arr_current(i)%frame
+          CALL rotateToEquatorial(this_prop_arr_current(i))
+       END IF
+    END DO
+    DO i=1, nobsy
+       IF (i <= SIZE(indx_smaller)) THEN
+          ! First propagate backwards from the orbit epoch 
+          j = indx_smaller(SIZE(indx_smaller)-i+1)
+       ELSE IF (i == SIZE(indx_smaller) + 1) THEN
+          ! Then propagate forwards from the orbit epoch
+          DO j=1,nthis
+             CALL NULLIFY(this_prop_arr_current(j))
+             this_prop_arr_current(j) = copy(this_arr(j))
+             IF (PRESENT(partials_arr)) THEN
+                jacobian_arr(j,:,:) = identity_matrix(6)
+             END IF
+          END DO
+          j = indx_larger(i)
+       ELSE
+          j = indx_larger(i)
+       END IF
+       IF (PRESENT(partials_arr)) THEN 
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             CALL getEphemeris(this_prop_arr_current, &
+                  observers(j), ephemerides_, &
+                  lt_corr=lt_corr_, &
+                  partials_arr=partials_arr_, &
+                  jacobian_prop_arr=jacobian_prop_arr, &
+                  this_lt_corr_arr=this_lt_corr_arr_, &
+                  this_prop_arr=this_prop_arr_next)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "TRACE BACK (5)", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(partials_arr_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+             DO k=1,nthis
+                this_lt_corr_arr(k,j) = copy(this_lt_corr_arr_(k))
+                CALL NULLIFY(this_lt_corr_arr_(k))
+             END DO
+             DEALLOCATE(this_lt_corr_arr_, stat=err)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "Could not deallocate memory (10).", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(partials_arr_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+          ELSE
+             CALL getEphemeris(this_prop_arr_current, &
+                  observers(j), ephemerides_, &
+                  lt_corr=lt_corr_, &
+                  partials_arr=partials_arr_, &
+                  jacobian_prop_arr=jacobian_prop_arr, &
+                  this_prop_arr=this_prop_arr_next)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "TRACE BACK (10)", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                IF (PRESENT(this_lt_corr_arr)) THEN
+                   DEALLOCATE(this_lt_corr_arr, stat=err)
+                END IF
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(partials_arr_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+          END IF
+          DO k=1,nthis
+             partials_arr(k,:,:,j) = MATMUL(partials_arr_(k,:,:), jacobian_arr(k,:,:))
+             jacobian_arr(k,:,:) = MATMUL(jacobian_prop_arr(k,:,:), jacobian_arr(k,:,:))
+          END DO
+          DEALLOCATE(partials_arr_, jacobian_prop_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                  "Could not deallocate memory (15).", 1)
+             DEALLOCATE(this_prop_arr_current, stat=err)
+             DEALLOCATE(ephemerides, stat=err)
+             DEALLOCATE(frames, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             DEALLOCATE(jacobian_arr, stat=err)
+             IF (PRESENT(this_lt_corr_arr)) THEN
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+             END IF
+             DEALLOCATE(indx_smaller, stat=err)
+             DEALLOCATE(indx_larger, stat=err)
+             DEALLOCATE(ephemerides_, stat=err)
+             DEALLOCATE(partials_arr_, stat=err)
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+             DEALLOCATE(this_lt_corr_arr_, stat=err)
+             DEALLOCATE(this_prop_arr_next, stat=err)
+             RETURN
+          END IF
+       ELSE
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             CALL getEphemeris(this_prop_arr_current, &
+                  observers(j), ephemerides_, &
+                  lt_corr=lt_corr_, &
+                  this_lt_corr_arr=this_lt_corr_arr_, &
+                  this_prop_arr=this_prop_arr_next)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "TRACE BACK (15)", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+             DO k=1,nthis
+                this_lt_corr_arr(k,j) = copy(this_lt_corr_arr_(k))
+                CALL NULLIFY(this_lt_corr_arr_(k))
+             END DO
+             DEALLOCATE(this_lt_corr_arr_, stat=err)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "Could not deallocate memory (20).", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+          ELSE
+             CALL getEphemeris(this_prop_arr_current, &
+                  observers(j), ephemerides_, &
+                  lt_corr=lt_corr_, &
+                  this_prop_arr=this_prop_arr_next)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemerides (multiple)", &
+                     "TRACE BACK (20)", 1)
+                DEALLOCATE(this_prop_arr_current, stat=err)
+                DEALLOCATE(ephemerides, stat=err)
+                DEALLOCATE(frames, stat=err)
+                DEALLOCATE(jacobian_arr, stat=err)
+                IF (PRESENT(this_lt_corr_arr)) THEN
+                   DEALLOCATE(this_lt_corr_arr, stat=err)
+                END IF
+                DEALLOCATE(indx_smaller, stat=err)
+                DEALLOCATE(indx_larger, stat=err)
+                DEALLOCATE(ephemerides_, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr_, stat=err)
+                DEALLOCATE(this_prop_arr_next, stat=err)
+                RETURN
+             END IF
+          END IF
+       END IF
+       DO k=1,nthis
+          ephemerides(k,j) = copy(ephemerides_(k))
+          CALL NULLIFY(ephemerides_(k))
+          CALL NULLIFY(this_prop_arr_current(k))
+          this_prop_arr_current(k) = copy(this_prop_arr_next(k))
+          CALL NULLIFY(this_prop_arr_next(k))
+       END DO
+       DEALLOCATE(ephemerides_, this_prop_arr_next, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "Could not deallocate memory (25).", 1)
+          DEALLOCATE(this_prop_arr_current, stat=err)
+          DEALLOCATE(ephemerides, stat=err)
+          DEALLOCATE(frames, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_arr, stat=err)
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          DEALLOCATE(indx_smaller, stat=err)
+          DEALLOCATE(indx_larger, stat=err)
+          DEALLOCATE(ephemerides_, stat=err)
+          DEALLOCATE(partials_arr_, stat=err)
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          DEALLOCATE(this_lt_corr_arr_, stat=err)
+          DEALLOCATE(this_prop_arr_next, stat=err)
+          RETURN
+       END IF
+    END DO
+    DO i=1,nthis
+       IF (PRESENT(partials_arr) .AND. &
+            this_prop_arr_current(i)%element_type == "cartesian" &
+            .AND. frames(i) == "ecliptic") THEN
+          DO j=1,SIZE(partials_arr,dim=4)
+             DO k=1,6
+                CALL rotateToEcliptic(partials_arr(i,k,:,j))
+             END DO
+          END DO
+       END IF
+    END DO
+
+    DO j=1,SIZE(this_prop_arr_current)
+       CALL NULLIFY(this_prop_arr_current(j))
+    END DO
+    DEALLOCATE(frames, this_prop_arr_current, indx_smaller, &
+         indx_larger, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemerides (multiple)", &
+            "Could not deallocate memory (30).", 1)
+       DEALLOCATE(this_prop_arr_current, stat=err)
+       DEALLOCATE(ephemerides, stat=err)
+       DEALLOCATE(frames, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       DEALLOCATE(jacobian_arr, stat=err)
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       DEALLOCATE(indx_smaller, stat=err)
+       DEALLOCATE(indx_larger, stat=err)
+       DEALLOCATE(ephemerides_, stat=err)
+       DEALLOCATE(partials_arr_, stat=err)
+       DEALLOCATE(jacobian_prop_arr, stat=err)
+       DEALLOCATE(this_lt_corr_arr_, stat=err)
+       DEALLOCATE(this_prop_arr_next, stat=err)
+       RETURN
+    END IF
+    IF (ALLOCATED(jacobian_arr)) THEN
+       DEALLOCATE(jacobian_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemerides (multiple)", &
+               "Could not deallocate memory (35).", 1)
+          DEALLOCATE(ephemerides, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE getEphemerides_Orb_multiple
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial light-time-corrected
+  !! coordinates from the object's heliocentric Cartesian orbit and 
+  !! the observer's heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial light-time-corrected coordinates
+  !! wrt object's orbital elements are calculated. Optionally,
+  !! the light-time corrected orbit is returned. 
+  !!
+  !! The given orbit is not propagated to the ephemeris epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemeris_Orb_single(this, observer, ephemeris, &
+       lt_corr, partials, this_prop, jacobian_prop, this_lt_corr, &
+       jacobian_lt_corr)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                     :: this
+    TYPE (CartesianCoordinates), INTENT(in)         :: observer
+    TYPE (SphericalCoordinates), INTENT(out)        :: ephemeris
+    LOGICAL, INTENT(in), OPTIONAL                   :: lt_corr
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: partials
+    TYPE (Orbit), INTENT(out), OPTIONAL             :: this_prop
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: jacobian_prop
+    TYPE (Orbit), INTENT(out), OPTIONAL             :: this_lt_corr
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: jacobian_lt_corr
+
+    TYPE (Orbit), DIMENSION(1)                         :: this_arr
+    TYPE (Orbit), DIMENSION(:), POINTER                :: this_prop_arr
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemeris_arr
+    TYPE (Orbit), DIMENSION(:), POINTER                :: this_lt_corr_arr
+    REAL(bp), DIMENSION(:,:,:), POINTER                :: partials_arr
+    REAL(bp), DIMENSION(:,:,:), POINTER                :: jacobian_prop_arr, &
+         jacobian_lt_corr_arr
+    INTEGER :: i, err
+    LOGICAL :: lt_corr_
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (single)", &
+            "This object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (single)", &
+            "'observer' has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+    this_arr(1) = copy(this)
+    IF (PRESENT(partials)) THEN 
+       IF (PRESENT(jacobian_prop)) THEN
+          IF (PRESENT(this_prop)) THEN
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             END IF
+          ELSE
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             END IF
+          END IF
+       ELSE
+          IF (PRESENT(this_prop)) THEN
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_prop_arr=this_prop_arr)
+                END IF
+             END IF
+          ELSE
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        partials_arr=partials_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        partials_arr=partials_arr)
+                END IF
+             END IF
+          END IF
+       END IF
+    ELSE
+       IF (PRESENT(jacobian_prop)) THEN
+          IF (PRESENT(this_prop)) THEN
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_prop_arr=this_prop_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             END IF
+          ELSE
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        jacobian_prop_arr=jacobian_prop_arr)
+                END IF
+             END IF
+          END IF
+       ELSE
+          IF (PRESENT(this_prop)) THEN
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_prop_arr=this_prop_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_prop_arr=this_prop_arr)
+                END IF
+             END IF
+          ELSE
+             IF (PRESENT(this_lt_corr)) THEN
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        this_lt_corr_arr=this_lt_corr_arr)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_, &
+                        this_lt_corr_arr=this_lt_corr_arr)
+                END IF
+             ELSE
+                IF (PRESENT(jacobian_lt_corr)) THEN
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+                        lt_corr=lt_corr_)
+                ELSE
+                   CALL getEphemeris(this_arr, observer, ephemeris_arr, &
+                        lt_corr=lt_corr_)
+                END IF
+             END IF
+          END IF
+       END IF
+    END IF
+    CALL NULLIFY(this_arr(1))
+    IF (error) THEN
+       CALL errorMessage("Orbit / getEphemeris (single)", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(this_lt_corr_arr, stat=err)
+       DEALLOCATE(this_prop_arr, stat=err)
+       DEALLOCATE(jacobian_prop_arr, stat=err)
+       DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+       DEALLOCATE(ephemeris_arr, stat=err)
+       RETURN
+    END IF
+    IF (PRESENT(partials)) THEN 
+       partials = partials_arr(1,:,:)
+       DEALLOCATE(partials_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (single)", &
+               "Could not deallocate memory (5)", 1)
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+          DEALLOCATE(this_prop_arr, stat=err)
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(this_lt_corr)) THEN
+       this_lt_corr = copy(this_lt_corr_arr(1))
+       DO i=1,SIZE(this_lt_corr_arr)
+          CALL NULLIFY(this_lt_corr_arr(i))
+       END DO
+       DEALLOCATE(this_lt_corr_arr, stat=err)
+    END IF
+    IF (PRESENT(this_prop)) THEN
+       this_prop = copy(this_prop_arr(1))
+       DO i=1,SIZE(this_prop_arr)
+          CALL NULLIFY(this_prop_arr(i))
+       END DO
+       DEALLOCATE(this_prop_arr, stat=err)
+    END IF
+    IF (PRESENT(jacobian_prop)) THEN
+       jacobian_prop = jacobian_prop_arr(1,:,:)
+       DEALLOCATE(jacobian_prop_arr, stat=err)
+    END IF
+    IF (PRESENT(jacobian_lt_corr)) THEN
+       jacobian_lt_corr = jacobian_lt_corr_arr(1,:,:)
+       DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+    END IF
+    ephemeris = copy(ephemeris_arr(1))
+    DEALLOCATE(ephemeris_arr, stat=err)
+
+  END SUBROUTINE getEphemeris_Orb_single
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial light-time-corrected
+  !! coordinates from the objects" heliocentric Cartesian orbits and 
+  !! the observer's heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial light-time-corrected coordinates
+  !! wrt object's orbital elements are calculated. Optionally,
+  !! the light-time corrected orbit is returned.
+  !!
+  !! The input orbits are propagated to the ephemeris epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemeris_Orb_multiple(this_arr, observer, &
+       ephemeris, lt_corr, partials_arr, this_prop_arr, &
+       jacobian_prop_arr, this_lt_corr_arr, jacobian_lt_corr_arr)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:), INTENT(in)             :: this_arr
+    TYPE (CartesianCoordinates), INTENT(in)            :: observer
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemeris
+    LOGICAL, INTENT(in), OPTIONAL                      :: lt_corr
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL      :: partials_arr
+    TYPE (Orbit), DIMENSION(:), POINTER, OPTIONAL      :: this_prop_arr
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL      :: jacobian_prop_arr
+    TYPE (Orbit), DIMENSION(:), POINTER, OPTIONAL      :: this_lt_corr_arr
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL      :: jacobian_lt_corr_arr
+
+    TYPE (Orbit), DIMENSION(:), ALLOCATABLE :: this_arr_
+    TYPE (Orbit)                            :: this_1, this_2
+    TYPE (CartesianCoordinates)             :: observer_
+    TYPE (Time)                             :: t_, t_observer
+    CHARACTER(len=FRAME_LEN)                :: frame
+    REAL(bp), DIMENSION(:,:,:), POINTER     :: jacobian_prop_arr_
+    REAL(bp), DIMENSION(6,6)                :: jacobian, jacobian_lt_corr
+    REAL(bp), DIMENSION(6,6)                :: scoord_partials
+    REAL(bp), DIMENSION(6)                  :: observer_coordinates, elements
+    INTEGER                                 :: i, nthis, err
+    LOGICAL                                 :: lt_corr_
+
+    nthis = SIZE(this_arr,dim=1)
+    ALLOCATE(this_arr_(nthis), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (multiple)", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(this_arr_, stat=err)
+       RETURN
+    END IF
+    DO i=1,nthis
+       IF (.NOT. this_arr(i)%is_initialized) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "All objects have not yet been initialized.", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          RETURN
+       END IF
+       CALL NULLIFY(this_arr_(i))
+       this_arr_(i) = copy(this_arr(i))
+    END DO
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (multiple)", &
+            "'observer' has not been initialized.", 1)
+       DEALLOCATE(this_arr_, stat=err)
+       RETURN
+    END IF
+    observer_ = copy(observer)
+
+    ALLOCATE(ephemeris(nthis), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (multiple)", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(this_arr_, stat=err)
+       DEALLOCATE(ephemeris, stat=err)
+       CALL NULLIFY(observer_)
+       RETURN
+    END IF
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+    IF (PRESENT(partials_arr)) THEN
+       ALLOCATE(partials_arr(nthis,6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          CALL NULLIFY(observer_)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(this_prop_arr)) THEN
+       IF (ASSOCIATED(this_prop_arr)) THEN
+          DEALLOCATE(this_prop_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                  "Could not deallocate memory (10).", 1)
+             DEALLOCATE(this_arr_, stat=err)
+             DEALLOCATE(ephemeris, stat=err)
+             IF (PRESENT(partials_arr)) THEN
+                DEALLOCATE(partials_arr, stat=err)
+             END IF
+             CALL NULLIFY(observer_)
+             RETURN
+          END IF
+       END IF
+       ALLOCATE(this_prop_arr(nthis), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          DEALLOCATE(this_prop_arr, stat=err)
+          CALL NULLIFY(observer_)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jacobian_prop_arr)) THEN
+       ALLOCATE(jacobian_prop_arr(nthis,6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_prop_arr)) THEN
+             DEALLOCATE(this_prop_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          CALL NULLIFY(observer_)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(this_lt_corr_arr)) THEN
+       ALLOCATE(this_lt_corr_arr(nthis), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not allocate memory (15).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_prop_arr)) THEN
+             DEALLOCATE(this_prop_arr, stat=err)
+          END IF
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+          IF (PRESENT(jacobian_prop_arr)) THEN
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+          END IF
+          CALL NULLIFY(observer_)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jacobian_lt_corr_arr)) THEN
+       ALLOCATE(jacobian_lt_corr_arr(nthis,6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not allocate memory (15).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_prop_arr)) THEN
+             DEALLOCATE(this_prop_arr, stat=err)
+          END IF
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          IF (PRESENT(jacobian_prop_arr)) THEN
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+          END IF
+          CALL NULLIFY(observer_)
+          RETURN
+       END IF
+       IF (.NOT.lt_corr_) THEN
+          DO i=1,nthis
+             jacobian_lt_corr_arr(i,:,:) = identity_matrix(6) 
+          END DO
+       END IF
+    END IF
+
+    ! Propagate to the observer epoch:
+    IF (info_verb >= 4) THEN
+       WRITE(stdout,"(1X,2(1X,A),I0,A)") &
+            "Orbit / getEphemeris_multiple:", &
+            "Propagate orbit array (size=", nthis, &
+            ") to the observer epoch."
+    END IF
+    t_observer = getTime(observer_)
+    IF (PRESENT(partials_arr) .OR. PRESENT(jacobian_prop_arr) &
+         .OR. PRESENT(jacobian_lt_corr_arr)) THEN
+       CALL propagate(this_arr_, t_observer, jacobian=jacobian_prop_arr_)
+    ELSE
+       CALL propagate(this_arr_, t_observer)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / getEphemeris (multiple)", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(this_arr_, stat=err)
+       DEALLOCATE(ephemeris, stat=err)
+       DEALLOCATE(jacobian_prop_arr_, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       IF (PRESENT(this_prop_arr)) THEN
+          DEALLOCATE(this_prop_arr, stat=err)
+       END IF
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       IF (PRESENT(jacobian_lt_corr_arr)) THEN
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+       END IF
+       IF (PRESENT(jacobian_prop_arr)) THEN
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+       END IF
+       CALL NULLIFY(observer_)
+       CALL NULLIFY(t_observer)
+       RETURN
+    END IF
+    IF (PRESENT(jacobian_prop_arr)) THEN
+       jacobian_prop_arr = jacobian_prop_arr_
+    END IF
+
+    ! Make the light-time correction (since the new epoch is orbit
+    ! dependent, all orbits must be propagated individually):
+    IF (info_verb >= 4 .AND. lt_corr_) THEN
+       WRITE(stdout,"(1X,2(1X,A))") &
+            "Orbit / getEphemeris_multiple:", &
+            "Make light-time correction."
+    END IF
+    DO i=1,nthis
+       IF (PRESENT(this_prop_arr)) THEN
+          this_prop_arr(i) = copy(this_arr_(i))
+       END IF
+       this_1 = copy(this_arr_(i))
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,5A)") &
+               "Orbit / getEphemeris_multiple:", &
+               "Orbital elements (" // &
+               TRIM(this_1%element_type) // ", " // &
+               TRIM(this_1%frame) // &
+               ") at observation date without light-time correction:"
+          elements = getElements(this_1, this_1%element_type, this_1%frame)
+          IF (this_1%element_type == "keplerian") THEN
+             WRITE(stdout,"(6(F14.10,1X))") elements(1:2), &
+                  elements(3:6)/rad_deg
+          ELSE IF (this_1%element_type == "cometary") THEN
+             WRITE(stdout,"(6(F14.10,1X))") elements(1:2), &
+                  elements(3:5)/rad_deg, elements(6)
+          ELSE
+             WRITE(stdout,"(6(F14.10,1X))") elements
+          END IF
+       END IF
+       IF (lt_corr_) THEN
+          ! Light-time correction:
+          t_ = getLightTimeCorrectedTime(this_1, observer_)
+          IF (error) THEN
+             CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                  "TRACE BACK 10", 1)
+             DEALLOCATE(this_arr_, stat=err)
+             DEALLOCATE(ephemeris, stat=err)
+             DEALLOCATE(jacobian_prop_arr_, stat=err)
+             IF (PRESENT(partials_arr)) THEN
+                DEALLOCATE(partials_arr, stat=err)
+             END IF
+             IF (PRESENT(this_prop_arr)) THEN
+                DEALLOCATE(this_prop_arr, stat=err)
+             END IF
+             IF (PRESENT(this_lt_corr_arr)) THEN
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_prop_arr)) THEN
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+             END IF
+             CALL NULLIFY(observer_)
+             CALL NULLIFY(t_observer)
+             CALL NULLIFY(this_1)
+             CALL NULLIFY(t_)
+             RETURN
+          END IF
+          IF (info_verb >= 5) THEN
+             WRITE(stdout,"(1X,2(1X,A),1X,I0,A,I0,1X,A)") &
+                  "Orbit / getEphemeris_multiple:", "Propagate orbit:", i, &
+                  "/", nthis, "due to light-time correction."
+          END IF
+          IF (PRESENT(partials_arr) .OR. PRESENT(jacobian_lt_corr_arr)) THEN
+             CALL propagate(this_1, t_, jacobian=jacobian_lt_corr)
+             frame = this_1%frame
+          ELSE
+             CALL propagate(this_1, t_)
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                  "TRACE BACK 15", 1)
+             DEALLOCATE(this_arr_, stat=err)
+             DEALLOCATE(ephemeris, stat=err)
+             DEALLOCATE(jacobian_prop_arr_, stat=err)
+             IF (PRESENT(partials_arr)) THEN
+                DEALLOCATE(partials_arr, stat=err)
+             END IF
+             IF (PRESENT(this_prop_arr)) THEN
+                DEALLOCATE(this_prop_arr, stat=err)
+             END IF
+             IF (PRESENT(this_lt_corr_arr)) THEN
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_prop_arr)) THEN
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+             END IF
+             CALL NULLIFY(observer_)
+             CALL NULLIFY(t_observer)
+             CALL NULLIFY(this_1)
+             CALL NULLIFY(t_)
+             RETURN
+          END IF
+          IF (PRESENT(jacobian_lt_corr_arr)) THEN
+             jacobian_lt_corr_arr(i,:,:) = jacobian_lt_corr
+          END IF
+       END IF
+       this_2 = copy(this_1)
+       IF (lt_corr_) THEN
+          CALL NULLIFY(this_1%t)
+          this_1%t = copy(t_observer)
+       END IF
+       ! Optionally, return orbit corresponding to
+       ! the ephemeris coordinates:
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          this_lt_corr_arr(i) = copy(this_1)
+          IF (error) THEN
+             CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                  "TRACE BACK 20", 1)
+             DEALLOCATE(this_arr_, stat=err)
+             DEALLOCATE(ephemeris, stat=err)
+             DEALLOCATE(jacobian_prop_arr_, stat=err)
+             IF (PRESENT(partials_arr)) THEN
+                DEALLOCATE(partials_arr, stat=err)
+             END IF
+             IF (PRESENT(this_prop_arr)) THEN
+                DEALLOCATE(this_prop_arr, stat=err)
+             END IF
+             IF (PRESENT(this_lt_corr_arr)) THEN
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             END IF
+             IF (PRESENT(jacobian_prop_arr)) THEN
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+             END IF
+             CALL NULLIFY(observer_)
+             CALL NULLIFY(t_observer)
+             CALL NULLIFY(this_1)
+             CALL NULLIFY(t_)
+             CALL NULLIFY(this_2)
+             RETURN
+          END IF
+       END IF
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,5A)") &
+               "Orbit / getEphemeris_multiple:", &
+               "Orbital elements (" // &
+               TRIM(this_1%element_type) // ", " // &
+               TRIM(this_1%frame) // &
+               ") at observation date with light-time correction:"
+          elements = getElements(this_1, this_1%element_type, this_1%frame)
+          IF (this_1%element_type == "keplerian") THEN
+             WRITE(stdout,"(6(F14.10,1X))") elements(1:2), &
+                  elements(3:6)/rad_deg
+          ELSE IF (this_1%element_type == "cometary") THEN
+             WRITE(stdout,"(6(F14.10,1X))") elements(1:2), &
+                  elements(3:5)/rad_deg, elements(6)
+          ELSE
+             WRITE(stdout,"(6(F14.10,1X))") elements
+          END IF
+       END IF
+
+       ! Transform to equatorial topocentric coordinates:
+       CALL toCartesian(this_1, frame="equatorial")
+       CALL rotateToEquatorial(observer_)
+       observer_coordinates(1:6) = getCoordinates(observer_)
+       this_1%elements(1:6) = this_1%elements(1:6) - &
+            observer_coordinates(1:6)
+       ephemeris(i) = getSCoord(this_1, frame="equatorial")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "TRACE BACK 25", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          DEALLOCATE(jacobian_prop_arr_, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_prop_arr)) THEN
+             DEALLOCATE(this_prop_arr, stat=err)
+          END IF
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          IF (PRESENT(jacobian_lt_corr_arr)) THEN
+             DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          END IF
+          IF (PRESENT(jacobian_prop_arr)) THEN
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+          END IF
+          CALL NULLIFY(observer_)
+          CALL NULLIFY(t_observer)
+          CALL NULLIFY(this_1)
+          CALL NULLIFY(t_)
+          CALL NULLIFY(this_2)
+          RETURN
+       END IF
+
+       ! Partial derivatives:
+       IF (PRESENT(partials_arr)) THEN
+
+          ! Chain rule.
+          jacobian = MATMUL(jacobian_lt_corr, jacobian_prop_arr_(i,:,:))
+
+          SELECT CASE (this_arr_(i)%element_type)
+
+          CASE ("cartesian")
+
+             ! Topocentric, spherical, equatorial coordinates wrt Cartesian elements.
+             !CALL partialsSCoordWrtCartesian_d(this_1, scoord_partials)
+             CALL partialsSCoordWrtCartesian_i(this_2, observer_, scoord_partials)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                     "TRACE BACK 30", 1)
+                DEALLOCATE(this_arr_, stat=err)
+                DEALLOCATE(ephemeris, stat=err)
+                DEALLOCATE(jacobian_prop_arr_, stat=err)
+                IF (PRESENT(partials_arr)) THEN
+                   DEALLOCATE(partials_arr, stat=err)
+                END IF
+                IF (PRESENT(this_prop_arr)) THEN
+                   DEALLOCATE(this_prop_arr, stat=err)
+                END IF
+                IF (PRESENT(this_lt_corr_arr)) THEN
+                   DEALLOCATE(this_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                   DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_prop_arr)) THEN
+                   DEALLOCATE(jacobian_prop_arr, stat=err)
+                END IF
+                CALL NULLIFY(observer_)
+                CALL NULLIFY(t_observer)
+                CALL NULLIFY(this_1)
+                CALL NULLIFY(t_)
+                CALL NULLIFY(this_2)
+                RETURN
+             END IF
+
+          CASE ("cometary")
+
+             ! Topocentric equatorial coordinates wrt cometary orbital elements.
+             CALL partialsSCoordWrtCometary(this_2, observer_, scoord_partials)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                     "TRACE BACK 35", 1)
+                DEALLOCATE(this_arr_, stat=err)
+                DEALLOCATE(ephemeris, stat=err)
+                DEALLOCATE(jacobian_prop_arr_, stat=err)
+                IF (PRESENT(partials_arr)) THEN
+                   DEALLOCATE(partials_arr, stat=err)
+                END IF
+                IF (PRESENT(this_prop_arr)) THEN
+                   DEALLOCATE(this_prop_arr, stat=err)
+                END IF
+                IF (PRESENT(this_lt_corr_arr)) THEN
+                   DEALLOCATE(this_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                   DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_prop_arr)) THEN
+                   DEALLOCATE(jacobian_prop_arr, stat=err)
+                END IF
+                CALL NULLIFY(observer_)
+                CALL NULLIFY(t_observer)
+                CALL NULLIFY(this_1)
+                CALL NULLIFY(t_)
+                CALL NULLIFY(this_2)
+                RETURN
+             END IF
+
+          CASE ("keplerian")
+
+             ! Topocentric equatorial coordinates wrt Keplerian orbital elements.
+             CALL partialsSCoordWrtKeplerian(this_2, observer_, scoord_partials)
+             IF (error) THEN
+                CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                     "TRACE BACK 35", 1)
+                DEALLOCATE(this_arr_, stat=err)
+                DEALLOCATE(ephemeris, stat=err)
+                DEALLOCATE(jacobian_prop_arr_, stat=err)
+                IF (PRESENT(partials_arr)) THEN
+                   DEALLOCATE(partials_arr, stat=err)
+                END IF
+                IF (PRESENT(this_prop_arr)) THEN
+                   DEALLOCATE(this_prop_arr, stat=err)
+                END IF
+                IF (PRESENT(this_lt_corr_arr)) THEN
+                   DEALLOCATE(this_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_lt_corr_arr)) THEN
+                   DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+                END IF
+                IF (PRESENT(jacobian_prop_arr)) THEN
+                   DEALLOCATE(jacobian_prop_arr, stat=err)
+                END IF
+                CALL NULLIFY(observer_)
+                CALL NULLIFY(t_observer)
+                CALL NULLIFY(this_1)
+                CALL NULLIFY(t_)
+                CALL NULLIFY(this_2)
+                RETURN
+             END IF
+
+          CASE default
+
+             error = .TRUE.
+             CALL errorMessage("Orbit / getEphemeris (multiple)", &
+                  "Could not choose between element types" // &
+                  "('cartesian', 'cometary', or 'keplerian'): " // &
+                  TRIM(this_arr_(i)%element_type), 1)
+             RETURN
+
+          END SELECT
+
+          ! Chain rule.
+          partials_arr(i,:,:) = MATMUL(scoord_partials, jacobian)
+
+       END IF
+
+       CALL NULLIFY(this_1)
+       CALL NULLIFY(this_2)
+       CALL NULLIFY(t_)
+
+    END DO
+
+    CALL NULLIFY(observer_)
+    CALL NULLIFY(t_observer)
+    IF (ASSOCIATED(jacobian_prop_arr_)) THEN
+       DEALLOCATE(jacobian_prop_arr_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getEphemeris (multiple)", &
+               "Could not deallocate memory (5).", 1)
+          DEALLOCATE(this_arr_, stat=err)
+          DEALLOCATE(ephemeris, stat=err)
+          IF (PRESENT(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          IF (PRESENT(this_prop_arr)) THEN
+             DEALLOCATE(this_prop_arr, stat=err)
+          END IF
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          IF (PRESENT(jacobian_lt_corr_arr)) THEN
+             DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          END IF
+          IF (PRESENT(jacobian_prop_arr)) THEN
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+          END IF
+          RETURN
+       END IF
+    END IF
+    DO i=1,SIZE(this_arr_)
+       CALL NULLIFY(this_arr_(i))
+    END DO
+    DEALLOCATE(this_arr_, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getEphemeris (multiple)", &
+            "Could not deallocate memory (15).", 1)
+       DEALLOCATE(ephemeris, stat=err)
+       IF (PRESENT(partials_arr)) THEN
+          DEALLOCATE(partials_arr, stat=err)
+       END IF
+       IF (PRESENT(this_prop_arr)) THEN
+          DEALLOCATE(this_prop_arr, stat=err)
+       END IF
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          DEALLOCATE(this_lt_corr_arr, stat=err)
+       END IF
+       IF (PRESENT(jacobian_lt_corr_arr)) THEN
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+       END IF
+       IF (PRESENT(jacobian_prop_arr)) THEN
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+       END IF
+       RETURN
+    END IF
+
+  END SUBROUTINE getEphemeris_Orb_multiple
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the coordinate frame.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=FRAME_LEN) FUNCTION getFrame_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getFrame", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getFrame_Orb = TRIM(this%frame)
+
+  END FUNCTION getFrame_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Calculates the Keplerian orbital elements (for elliptical orbits)
+  !! from the heliocentric (ecliptical or equatorial) Cartesian orbital
+  !! elements or elliptic cometary elements for the current epoch. 
+  !! Hyperbolic cometary elements lead to an error.
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getKeplerianElements(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)   :: getKeplerianElements
+
+    TYPE (Orbit):: this_
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(3) :: pos, vel, k, fb, gb, evec, cos_angles
+    REAL(bp) :: r, ru, ea, e_cos_ea, e_sin_ea, cos_ea, sin_ea, &
+         alpha, gamma, mjd_tt, a, e, i, an, ap, ma, div, tmp1, tmp2, &
+         varpi
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getKeplerianElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Return initial elements if error occurs:
+    getKeplerianElements(1:6) = this%elements(1:6)
+
+    SELECT CASE (this%element_type)
+
+    CASE ("keplerian")
+
+       RETURN
+
+    CASE ("cartesian")
+
+       this_ = copy(this)
+       CALL rotateToEcliptic(this_)
+
+       ! Semimajor axis, eccentricity and mean anomaly:
+       pos = this_%elements(1:3)
+       r   = SQRT(DOT_PRODUCT(pos,pos))
+       vel = this_%elements(4:6)
+       ! Angular momentum:
+       k = cross_product(pos,vel)
+       ! Eccentricity vector:
+       evec = cross_product(vel,k)/planetary_mu(this_%central_body) - pos/r
+
+       ! alpha = rv^2/mu
+       alpha = r*DOT_PRODUCT(vel,vel)/planetary_mu(this%central_body)
+       ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+       ! -> a = r / (2 - rv^2/mu)
+       IF (ABS(2.0_bp - alpha) < 10.0_bp*EPSILON(alpha)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "a is approaching infinity.", 1)
+          RETURN
+       END IF
+       a = r / (2.0_bp - alpha)
+       IF (a < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Semimajor axis is negative.", 1)
+          RETURN
+       END IF
+       ! gamma = sqrt(mu*a)
+       gamma = SQRT(planetary_mu(this%central_body)*a)
+       IF (ABS(gamma) < TINY(gamma)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Gamma is computationally too small.", 1)
+          RETURN
+       END IF
+       ! r(1+e*cos(f))=a|1-e^2|, r*cos(f)=a*cos(E)-ae, and for elliptical 
+       ! orbits a=r/(2-rv^2/mu) (see above) and |1-e^2|=1-e^2
+       ! -> e*cos(E)=rv^2/mu-1=alpha-1
+       e_cos_ea = alpha - 1.0_bp
+       !
+       e_sin_ea = DOT_PRODUCT(pos,vel)/gamma
+       e = SQRT(e_cos_ea**2.0_bp + e_sin_ea**2.0_bp)
+       IF (e > 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Orbit is hyperbolic.", 1)
+          RETURN
+       ELSE IF (e == 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Orbit is parabolic.", 1)
+          RETURN
+       ELSE IF (e < EPSILON(e)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Orbit is (almost) circular.", 1)
+          WRITE(stderr,*) e
+          RETURN
+       END IF
+       cos_ea = e_cos_ea/e
+       sin_ea = e_sin_ea/e
+       IF (ABS(cos_ea) > 1.0_bp) cos_ea = SIGN(1.0_bp, cos_ea)
+       ea = ACOS(cos_ea)
+       IF (sin_ea < 0.0_bp) ea = two_pi - ea
+       ma = ea - e_sin_ea
+       IF (ma == two_pi) THEN
+          ma = 0.0_bp
+       END IF
+
+       ! Inclination and ascending node:
+       ru = SQRT(DOT_PRODUCT(k,k))
+       IF (ru < EPSILON(ru)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &   
+               "Position and velocity almost parallel.", 1)
+          RETURN
+       END IF
+       k = k/ru
+       cos_angles(1) = k(3) ! = cos(i)
+       IF (ABS(cos_angles(1)) > 1.0_bp) THEN
+          cos_angles(1) = SIGN(1.0_bp, cos_angles(1))
+       END IF
+       i = ACOS(cos_angles(1))
+       ! Notice computational abs!!
+       ru = SQRT(ABS(1.0_bp - k(3)**2.0_bp)) ! = sin(i)
+       IF (ru < EPSILON(ru)) THEN
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Warning: Inclination (almost) zero, setting Longitude of Node to 0 deg.", 1)
+          an = 0.0_bp
+       ELSE
+          cos_angles(2) = -k(2)/ru
+          IF (ABS(cos_angles(2)) > 1.0_bp) THEN
+             cos_angles(2) = SIGN(1.0_bp, cos_angles(2))
+          END IF
+          an = ACOS(cos_angles(2))
+          IF (k(1) < 0.0_bp) THEN
+             an = two_pi - an
+          END IF
+       END IF
+       IF (an == two_pi) THEN
+          an = 0.0_bp
+       END IF
+
+       ! Argument of periapsis:
+       div = 1.0_bp + k(3)
+       fb(1) = 1.0_bp - k(1)**2.0_bp/div
+       fb(2) = -k(1)*k(2)/div
+       fb(3) = -k(1)
+       gb = cross_product(k, fb)
+       tmp1 = DOT_PRODUCT(evec, gb)
+       tmp2 = DOT_PRODUCT(evec, fb)
+       varpi = ATAN2(tmp1, tmp2)
+       ap = varpi - an
+       ap = MODULO(ap,two_pi)
+       IF (ap == two_pi) THEN
+          ap = 0.0_bp
+       END IF
+
+       getKeplerianElements = (/ a, e, i, an, ap, ma /)
+       CALL NULLIFY(this_)
+
+    CASE ("cometary")
+
+       IF (this%elements(2) >= 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "Hyperbolic orbit; cannot return Keplerian elements.", 1)
+          RETURN
+       END IF
+
+       ! Semimajor axis:
+       getKeplerianElements(1) = &
+            this%elements(1) / (1.0_bp - this%elements(2))
+       ! Mean anomaly:
+       t = copy(this%t)
+       mjd_tt = getMJD(t, "TT")
+       CALL NULLIFY(t)
+       getKeplerianElements(6) = &
+            SQRT(planetary_mu(this%central_body) / &
+            getKeplerianElements(1)**3.0_bp) * &
+            (mjd_tt - this%elements(6))
+       getKeplerianElements(6) = &
+            MODULO(getKeplerianElements(6), two_pi)
+
+    CASE ("cometary_ta")
+
+       this_ = copy(this)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       CALL toCometary(this_)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       getKeplerianElements = getElements(this_, "keplerian")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getKeplerianElements", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+
+    CASE default
+
+       error = .TRUE.
+       CALL errorMessage("Orbit / getKeplerianElements", &
+            "Conversion from " // TRIM(this%element_type) // &
+            " elements to keplerian elements has not yet been implemented.", 1)
+       RETURN
+
+    END SELECT
+
+  END FUNCTION getKeplerianElements
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Calculates the k-vector.
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getKVector(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)   :: getKVector
+    REAL(bp), DIMENSION(6)   :: elements
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getKVector", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this, "cartesian", "ecliptic")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getKVector", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    getKVector = cross_product(elements(1:3),elements(4:6))
+
+  END FUNCTION getKVector
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes the light-time corrected epoch via linear extrapolation
+  !! from the objects orbital elements (this) to the retarded,
+  !! apparent position seen from the observer's coordinates
+  !! (observer) at the epoch of the object's orbital elements
+  !! (this).
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getLightTimeCorrectedTime(this, observer)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: observer
+    TYPE (Time)                             :: getLightTimeCorrectedTime
+    TYPE (Orbit)                            :: this_
+    TYPE (CartesianCoordinates)             :: observer_
+    REAL(bp), DIMENSION(6)                  :: observer_coord
+    REAL(bp)                                :: lt, rr, rv, vv, mjd_tt
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getLightTimeCorrectedTime", &
+            "Object object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getLightTimeCorrectedTime", &
+            "Observer object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    this_ = copy(this)
+    observer_ = copy(observer)
+    mjd_tt = getMJD(this_%t, "TT")
+    CALL toCartesian(this_, frame="equatorial")
+    CALL rotateToEquatorial(observer_)
+    observer_coord = getCoordinates(observer_)
+    rr = DOT_PRODUCT((this_%elements(1:3) - observer_coord(1:3)), &
+         (this_%elements(1:3) - observer_coord(1:3)))
+    rv = DOT_PRODUCT((this_%elements(1:3) - observer_coord(1:3)), &
+         this_%elements(4:6))
+    vv = DOT_PRODUCT(this_%elements(4:6),this_%elements(4:6))
+    IF (rv**2.0_bp+rr*(sol**2.0_bp-vv) < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getLightTimeCorrectedTime", &
+            "Object is moving faster than light.", 1)
+       RETURN
+    END IF
+    lt = (SQRT(rv**2.0_bp+rr*(sol**2.0_bp-vv))-rv) / (sol**2.0_bp-vv)
+    CALL NULLIFY(this_)
+    CALL NULLIFY(observer_)
+    CALL NEW(getLightTimeCorrectedTime, mjd_tt-lt, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getLightTimeCorrectedTime", &
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getLightTimeCorrectedTime
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The Sitarski algorithm (Acta Astronomica, Vol.18, No.2, p.171)
+  !! for computing the minimum distance between two Keplerian orbits
+  !! (MOID = minimum orbital intersection distance).
+  !!
+  REAL(bp) FUNCTION getMOID(this, that)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this, that
+    TYPE (Orbit) :: this_, that_
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: ta2
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: ta1
+    REAL(bp), DIMENSION(10,10) :: local_minima
+    REAL(bp), DIMENSION(3,3) :: rot1, rot2
+    REAL(bp), DIMENSION(2,2) :: rot
+    REAL(bp), DIMENSION(6) :: elem1, elem2
+    REAL(bp), DIMENSION(3) :: coord1, coord2, coord11, coord22, &
+         rad1, rad2, dr, der2
+    REAL(bp), DIMENSION(2) :: sine, cosine, f1, f2, ff
+    REAL(bp) :: par1, par2, par11, par22, r1, r2, ta0, dta, q1, q2, &
+         f, ea, sin_ea, cos_ea, ma
+    INTEGER :: i, j, k, N, m1, m2, err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getMOID", &
+            "Object object has not yet been initialized (1).", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getMOID", &
+            "Object object has not yet been initialized (2).", 1)
+       RETURN
+    END IF
+
+    this_ = copy(this)
+    that_ = copy(that)
+
+    ! Propagate orbital elements of "that" to 
+    ! the epoch of "this" if needed:
+    IF (.NOT.equal(getTime(this_),getTime(that_))) THEN
+       t = getTime(this_)
+       CALL propagate(that_, t)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getMOID", &
+               "TRACE TRACK (5).", 1)
+          RETURN
+       END IF
+    END IF
+
+    ! Convert to Keplerian elements:
+    CALL toKeplerian(this_)
+    CALL toKeplerian(that_)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getMOID", &
+            "TRACE TRACK (10).", 1)
+       RETURN
+    END IF
+
+    ! Rotation matrix of the first orbit (polar->ecliptic):
+    rot1 = getTransformationMatrix(this_)
+    ! Rotation matrix of the second orbit (--- " ---):
+    rot2 = getTransformationMatrix(that_)
+
+    rot(1,1) = rot1(1,1)*rot2(1,1) + rot1(2,1)*rot2(2,1) + rot1(3,1)*rot2(3,1)
+    rot(1,2) = rot1(1,1)*rot2(1,2) + rot1(2,1)*rot2(2,2) + rot1(3,1)*rot2(3,2)
+    rot(2,1) = rot1(1,2)*rot2(1,1) + rot1(2,2)*rot2(2,1) + rot1(3,2)*rot2(3,1)
+    rot(2,2) = rot1(1,2)*rot2(1,2) + rot1(2,2)*rot2(2,2) + rot1(3,2)*rot2(3,2)
+
+    ! Orbital parameters:
+    elem1 = getElements(this_, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getMOID", &
+            "TRACE TRACK (15).", 1)
+       RETURN
+    END IF
+    elem2 = getElements(that_, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getMOID", &
+            "TRACE TRACK (20).", 1)
+       RETURN
+    END IF
+    IF (info_verb >= 3) THEN
+       WRITE(stdout,"(A)") "Orbit #1:"
+       WRITE(stdout,"(6(1X,F20.15))") elem1(1:2), elem1(3:6)/rad_deg
+       WRITE(stdout,"(A)") "Orbit #2:"
+       WRITE(stdout,"(6(1X,F20.15))") elem2(1:2), elem2(3:6)/rad_deg
+    END IF
+
+    par1 = (1-elem1(2)**2)*elem1(1)
+    par2 = (1-elem2(2)**2)*elem2(1)
+    q1 = elem1(1)*(1.0_bp - elem1(2))
+    q2 = elem2(1)*(1.0_bp - elem2(2))
+
+    k = 0
+    N = 360
+    local_minima(:,1) = HUGE(local_minima(:,1))
+
+    !-----------------------------------------------------------
+    ! Find minimum, increase true anomaly sampling if necessary:
+    !-----------------------------------------------------------
+
+    DO WHILE (N <= 360000 .AND. &
+         (k == 0 .OR. MINVAL(local_minima(:,1)) > q2 + q1))
+
+       ALLOCATE(ta1(N), ta2(2,N), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getMOID", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+
+       dta = two_pi/N
+       ta0 = 0.0_bp
+
+       ! Moving along the first orbit with steps of dta:
+       ! (N=360, dta=1 deg)
+       DO i=1,N
+          ta1(i) = ta0 + (i-1)*dta
+          CALL SOLVE(elem1, ta1(i), elem2, rot, sine, cosine)
+          ta2(1,i) = angle(cosine(1), sine(1))
+          ta2(2,i) = angle(cosine(2), sine(2))
+       END DO
+
+       ! Sign-changes-intervals:
+       ! Find intervals of true anomalies (F,f) where the second
+       ! derivative of the function to be minimized (see Sitarski) 
+       ! changes its sign.
+
+       DO i=1,N
+          DO j=1,2
+
+             ! Set (F,f) intervals
+             IF (i == 1) THEN
+                f1(1) = ta1(N)
+                f1(2) = ta1(i)
+                f2(1) = ta2(j,N)
+                f2(2) = ta2(j,i)
+             ELSE
+                f1(1) = ta1(i-1)
+                f1(2) = ta1(i)
+                f2(1) = ta2(j,i-1)
+                f2(2) = ta2(j,i)
+             END IF
+
+             ! Check that upper interval limits are less than 0 deg,
+             ! ie 359.9999... deg:
+             IF (f1(2) == 0.0_bp) THEN
+                f1(2) = two_pi - 100*EPSILON(f1(2))
+             END IF
+             IF (f2(2) == 0.0_bp) THEN
+                f2(2) = two_pi - 100*EPSILON(f2(2))
+             END IF
+
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(A)") "(F,f) intervals:"
+                WRITE(stdout,"(4(1X,F10.6))") f1/rad_deg, f2/rad_deg
+             END IF
+
+             par11 = (1.0_bp - elem1(2)**2)*elem1(1)
+             r1 = par11/(1.0_bp + elem1(2)*COS(f1(1)))
+             coord1(1) = r1*COS(f1(1))
+             coord1(2) = r1*SIN(f1(1))
+             coord1(3) = 0.0_bp
+
+             par22 = (1.0_bp - elem2(2)**2)*elem2(1)
+             r2 = par22/(1.0_bp + elem2(2)*COS(f2(1)))
+             coord2(1) = r2*COS(f2(1))
+             coord2(2) = r2*SIN(f2(1))
+             coord2(3) = 0.0_bp
+
+             m1 = NINT(SIGN(1.0_bp, derivative(coord1, coord2, r2, rot, elem2)))
+
+             par11 = (1.0_bp - elem1(2)**2)*elem1(1)
+             r1 = par11/(1.0_bp + elem1(2)*COS(f1(2)))
+             coord1(1) = r1*COS(f1(2))
+             coord1(2) = r1*SIN(f1(2))
+             coord1(3) = 0.0_bp
+
+             par22 = (1.0_bp - elem2(2)**2)*elem2(1)
+             r2 = par22/(1.0_bp + elem2(2)*COS(f2(2)))
+             coord2(1) = r2*COS(f2(2))
+             coord2(2) = r2*SIN(f2(2))
+             coord2(3) = 0.0_bp
+
+             m2 = NINT(SIGN(1.0_bp, derivative(coord1, coord2, r2, rot, elem2)))
+
+             IF (m1*m2 < 0) THEN
+
+                ! Refine the initial interval by successive halving
+
+                CALL HALF(j, elem1, f1, elem2, f2, rot, m1, m2, ff)
+
+                par11 = (1.0_bp - elem1(2)**2)*elem1(1)
+                r1 = par11/(1.0_bp + elem1(2)*COS(ff(1)))
+                coord11(1) = r1*COS(ff(1))
+                coord11(2) = r1*SIN(ff(1))
+                coord11(3) = 0.0_bp
+
+                par22 = (1.0_bp - elem2(2)**2)*elem2(1)
+                r2 = par22/(1.0_bp + elem2(2)*COS(ff(2)))
+                coord22(1) = r2*COS(ff(2))
+                coord22(2) = r2*SIN(ff(2))
+                coord22(3) = 0.0_bp
+
+                ! Study the found extrema, compute second derivatives:
+                der2(1) = (r1/par1)*(elem1(2)*r1**2/par1*(elem1(2)*r1+coord11(1)) + &
+                     coord11(1)*(rot(1,1)*coord22(1)+rot(1,2)*coord22(2)) + &
+                     coord11(2)*(rot(2,1)*coord22(1)+rot(2,2)*coord22(2)))
+
+                der2(2) = (r2/par2)*(elem2(2)*r2**2/par2*(elem2(2)*r2+coord22(1)) + &
+                     coord22(1)*(rot(1,1)*coord11(1)+rot(2,1)*coord11(2)) + &
+                     coord22(2)*(rot(1,2)*coord11(1)+rot(2,2)*coord11(2)))
+
+                der2(3) = (r1*r2/par1/par2)*((elem2(2)*r2+coord22(1))*(rot(2,2)* &
+                     (elem1(2)*r1+coord11(1)) - rot(1,2)*coord11(2)) - &
+                     coord22(2)*(rot(2,1)*(elem1(2)*r1+coord11(1)) - &
+                     rot(1,1)*coord11(2)))
+
+                ! Check for local minimum:
+                IF (der2(1) > 0.0_bp .AND. der2(2) > 0.0_bp .AND.&
+                     (der2(1)*der2(2)-der2(3)**2) > 0.0_bp) THEN
+                   k = k + 1
+                   IF (k > 10) THEN
+                      error = .TRUE.
+                      CALL errorMessage("Orbit / getMOID", &
+                           "More than 10 minima in the MOID function.", 1)
+                      RETURN
+                   END IF
+
+                   ! Compute distance in local minimum:
+                   rad1 = MATMUL(rot1, coord11)
+                   rad2 = MATMUL(rot2, coord22)
+                   dr = rad1 - rad2
+                   IF (i == 1) THEN
+                      local_minima(k,1:6) = (/ &
+                           SQRT(SUM(dr**2)), &
+                           REAL(N,bp), &
+                           ta1(N), &
+                           ta1(i), &
+                           ta2(j,N), &
+                           ta2(j,i) /)
+                   ELSE
+                      local_minima(k,1:6) = (/ &
+                           SQRT(SUM(dr**2)), &
+                           REAL(N,bp), &
+                           ta1(i-1), &
+                           ta1(i), &
+                           ta2(j,i-1), &
+                           ta2(j,i) /)
+                   END IF
+                   local_minima(k,7:10) = (/ &
+                        f1(1), &
+                        f1(2), &
+                        f2(1), &
+                        f2(2) /)
+                END IF
+             END IF
+          END DO
+       END DO
+
+       DEALLOCATE(ta1, ta2, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getMOID", &
+               "Could not deallocate memory.", 1)
+          DEALLOCATE(ta1, stat=err)
+          DEALLOCATE(ta2, stat=err)
+          RETURN
+       END IF
+
+       ! Increase the true anomaly sampling in case no minimum was found:
+       N = 10*N
+
+    END DO
+
+    !----------------------
+    ! Global minimum, MOID:
+    !----------------------
+    IF (k /= 0) THEN
+       getMOID = MINVAL(local_minima(1:k,1),1)
+       IF (info_verb >= 2) THEN
+          i = MINLOC(local_minima(1:k,1),1)
+          WRITE(stdout,"(10(F13.9,1X))") local_minima(i,1:2), &
+               local_minima(i,3:10)/rad_deg
+          f = 0.5_bp*SUM(local_minima(i,7:8))
+          cos_ea = (elem1(2) + COS(f))/(1.0_bp + elem1(2)*COS(f))
+          sin_ea = (SQRT(1.0_bp - elem1(2)**2)*SIN(f))/(1.0_bp + elem1(2)*COS(f))
+          ea = ATAN2(sin_ea, cos_ea)
+          ma = MODULO(ea - elem1(2)*SIN(ea), two_pi)
+          WRITE(stdout,"(A,6(1X,F15.10))") &
+               "Keplerian elements for the 1st orbit at the epoch:", &
+               elem1(1:2), elem1(3:6)/rad_deg
+          WRITE(stdout,"(A,1X,F15.10)") &
+               "Mean anomaly M for the 1st orbit when MOID takes place:", &
+               ma/rad_deg
+          f = 0.5_bp*SUM(local_minima(i,9:10))
+          cos_ea = (elem2(2) + COS(f))/(1.0_bp + elem2(2)*COS(f))
+          sin_ea = (SQRT(1.0_bp - elem2(2)**2)*SIN(f))/(1.0_bp + elem2(2)*COS(f))
+          ea = ATAN2(sin_ea, cos_ea)
+          ma = MODULO(ea - elem2(2)*SIN(ea), two_pi)
+          WRITE(stdout,"(A,6(1X,F15.10))") &
+               "Keplerian elements for the 2nd orbit at the epoch of the 1st orbit:", &
+               elem2(1:2), elem2(3:6)/rad_deg
+          WRITE(stdout,"(A,1X,F15.10)") &
+               "Mean anomaly M for the 2nd orbit when MOID takes place:", &
+               ma/rad_deg
+       END IF
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / getMOID", &
+            "Minimum not found.", 1)       
+       getMOID = HUGE(local_minima(1,1))
+    END IF
+
+    CALL NULLIFY(this_)
+    CALL NULLIFY(that_)
+
+  END FUNCTION getMOID
+
+
+
+
+
+  SUBROUTINE solve(elem1, ta1, elem2, rot, v1, v2)
+
+    ! See Sitarski, Eq. (10).
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(2,2), INTENT(in) :: rot
+    REAL(bp), DIMENSION(6), INTENT(in) :: elem1, elem2
+    REAL(bp), DIMENSION(2), INTENT(out) :: v1, v2
+    REAL(bp), INTENT(in) :: ta1
+
+    COMPLEX(cbp), DIMENSION(2) :: z1, z2, zz
+    COMPLEX(cbp) :: s, t, w
+    REAL(bp), DIMENSION(3) :: coord1
+    REAL(bp) :: r1, par1, par2
+
+    par1 = (1.0_bp - elem1(2)**2)*elem1(1)
+    r1 = par1/(1.0_bp + elem1(2)*COS(ta1))
+    coord1(1) = r1*COS(ta1)
+    coord1(2) = r1*SIN(ta1)
+    coord1(3) = 0.0_bp
+
+    par2 = (1-elem2(2)**2)*elem2(1)
+    s = elem1(2)*r1*coord1(2)/par2
+    t = rot(1,2)*coord1(2)-rot(2,2)*(elem1(2)*r1+coord1(1))
+    w = elem2(2)*s+rot(1,1)*coord1(2)-rot(2,1)*(elem1(2)*r1+coord1(1))
+
+    z1(1) = (-t*s+w*SQRT(t**2+w**2-s**2))/(t**2+w**2)
+    z1(2) = (-t*s-w*SQRT(t**2+w**2-s**2))/(t**2+w**2)
+
+    zz = CMPLX(z1)
+    IF (AIMAG(zz(1)) == 0.0_bp) THEN
+       v1(1) = REAL(z1(1),bp)
+    END IF
+    IF (AIMAG(zz(2)) == 0.0_bp) THEN
+       v1(2) = REAL(z1(2),bp)
+    END IF
+
+    z2(1) = (-w*s-t*SQRT(t**2+w**2-s**2))/(t**2+w**2)
+    z2(2) = (-w*s+t*SQRT(t**2+w**2-s**2))/(t**2+w**2)
+
+    zz = CMPLX(z2)
+    IF (AIMAG(zz(1)) == 0.0_bp) THEN
+       v2(1) = REAL(z2(1),bp)
+    END IF
+    IF (AIMAG(zz(2)) == 0.0_bp) THEN
+       v2(2) = REAL(z2(2),bp)
+    END IF
+
+  END SUBROUTINE solve
+
+
+
+
+
+  SUBROUTINE half(i, elem1, f1, elem2, f2, rot, m1, m2, df)
+
+    ! Halving of the sign-change-intervals.
+    ! Generalize?
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(2,2) :: rot
+    REAL(bp), DIMENSION(6) :: elem1, elem2
+    REAL(bp), DIMENSION(3) :: coord1, coord2
+    REAL(bp), DIMENSION(2) :: df, f1, f2, sine, cosine
+    REAL(bp) :: par1, par2, r1, r2, eps
+    INTEGER :: i, m, m1, m2
+
+    eps = 1.e-10_bp
+    DO WHILE (ABS(f1(1)-f1(2)) > eps)
+       df(1) = 0.5_bp*(f1(1) + f1(2))
+
+       CALL solve(elem1, df(1), elem2, rot, sine, cosine)
+       df(2) = angle(cosine(i),sine(i))
+
+       par1 = (1.0_bp - elem1(2)**2)*elem1(1)
+       r1 = par1/(1.0_bp + elem1(2)*COS(df(1)))
+       coord1(1) = r1*COS(df(1))
+       coord1(2) = r1*SIN(df(1))
+       coord1(3) = 0.0_bp
+       par2 = (1.0_bp - elem2(2)**2)*elem2(1)
+       r2 = par2/(1.0_bp + elem2(2)*COS(df(2)))
+       coord2(1) = r2*COS(df(2))
+       coord2(2) = r2*SIN(df(2))
+       coord2(3) = 0.0_bp
+
+       m = NINT(SIGN(1.0_bp, derivative(coord1, coord2, r2, rot, elem2)))
+       IF (m == m1) THEN
+          f1(1) = df(1)
+          f2(1) = df(2)
+       ELSE IF (m == m2) THEN
+          f1(2) = df(1)
+          f2(2) = df(2)
+       END IF
+    END DO
+
+  END SUBROUTINE half
+
+
+
+
+
+  !! Partial derivative of the function to be minimized
+  !! (df/dv, see Sitarski 1968).
+  !!
+  REAL(bp) FUNCTION derivative(coord1, coord2, r2, rot, elem2)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(2,2) :: rot
+    REAL(bp), DIMENSION(6)   :: elem2
+    REAL(bp), DIMENSION(3)   :: coord1, coord2
+    REAL(bp)                 :: r2, par2
+
+    par2 = (1.0_bp-elem2(2)**2.0_bp)*elem2(1)
+    derivative = (r2/par2) * &
+         (coord2(2)*(elem2(2)*r2 + rot(1,1)*coord1(1) + rot(2,1)*coord1(2)) - &
+         (elem2(2)*r2 + coord2(1)) * (rot(1,2)*coord1(1) + rot(2,2)*coord1(2)))
+
+  END FUNCTION derivative
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the semimajor axis for the input orbit.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getSemimajorAxis(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)       :: this
+
+    TYPE (Orbit) :: this_
+    REAL(bp), DIMENSION(3) :: pos, vel
+    REAL(bp) :: alpha, r
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getSemimajorAxis", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cometary")
+
+       getSemimajorAxis = this%elements(1) / &
+            (1.0_bp - this%elements(2))
+
+    CASE ("keplerian")
+
+       getSemimajorAxis = this%elements(1)
+
+    CASE ("cartesian")
+
+       this_ = copy(this)
+       CALL rotateToEcliptic(this_)
+       pos = this_%elements(1:3)
+       vel = this_%elements(4:6)
+       r = SQRT(DOT_PRODUCT(pos,pos))
+       ! alpha = rv^2/mu
+       alpha = r*DOT_PRODUCT(vel,vel)/planetary_mu(this_%central_body)
+       ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+       ! -> a = r / (2 - rv^2/mu)
+       IF (ABS(2.0_bp - alpha) < 10.0_bp*EPSILON(alpha)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getSemimajorAxis", &
+               "a is approaching infinity.", 1)
+          RETURN
+       END IF
+       getSemimajorAxis = r / (2.0_bp - alpha)
+
+    END SELECT
+
+  END FUNCTION getSemimajorAxis
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getParameters_Orb(this, mass, dyn_model, &
+       integration_step, integrator, finite_diff, &
+       additional_perturbers)
+
+    IMPLICIT NONE
+    TYPE(Orbit), INTENT(in) :: this
+    REAL(bp), INTENT(out), OPTIONAL :: mass
+    CHARACTER(len=DYN_MODEL_LEN), INTENT(out), OPTIONAL :: dyn_model
+    REAL(bp), INTENT(out), OPTIONAL :: integration_step
+    CHARACTER(len=INTEGRATOR_LEN), INTENT(out), OPTIONAL :: integrator
+    REAL(bp), DIMENSION(6), INTENT(out), OPTIONAL :: finite_diff
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL :: additional_perturbers
+
+    INTEGER :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getParameters", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(mass)) THEN
+       mass = this%mass_prm
+    END IF
+
+    IF (PRESENT(dyn_model)) THEN
+       dyn_model = this%dyn_model_prm
+    END IF
+    IF (PRESENT(integration_step)) THEN
+       integration_step = this%integration_step_prm
+    END IF
+    IF (PRESENT(integrator)) THEN
+       integrator = this%integrator_prm
+    END IF
+    IF (PRESENT(finite_diff)) THEN
+       finite_diff = this%finite_diff_prm
+    END IF
+    IF (PRESENT(additional_perturbers)) THEN
+       !! Returns the current set of orbital elements for additional
+       !! perturbers if available. The shape of the table is (1:n,1:8)
+       !! where n is the number of perturbers. The first six elements on a
+       !! row (n,1:6) contain the Cartesian equatorial orbital elements,
+       !! (n,7) is the epoch given as MJD TT, and (n,8) is the mass of the
+       !! perturber given as solar masses.
+       IF (ASSOCIATED(this%additional_perturbers)) THEN
+          ALLOCATE(additional_perturbers(SIZE(this%additional_perturbers,dim=1), &
+               SIZE(this%additional_perturbers,dim=2)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getParameters", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          additional_perturbers = this%additional_perturbers
+       ELSE
+          NULLIFY(additional_perturbers)
+       END IF
+    END IF
+
+  END SUBROUTINE getParameters_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the periapsis distance q for the input orbit. The
+  !! semimajor axis 'a' is computed if it is not given as a
+  !! parameter. Optionally, returns partial derivatives between q and
+  !! Keplerian elements.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getPeriapsisDistance_Orb(this, q, a, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                      :: this
+    REAL(bp), INTENT(out)                         :: q
+    REAL(bp), INTENT(in), OPTIONAL                :: a
+    REAL(bp), DIMENSION(6), INTENT(out), OPTIONAL :: partials ! Partials
+
+    TYPE (Orbit) :: this_
+    REAL(bp), DIMENSION(3) :: pos, vel
+    REAL(bp) :: a_, e, r, e_sin_ea, e_cos_ea, alpha, gamma
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPeriapsisDistance", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    SELECT CASE (this%element_type)
+
+    CASE ("cometary")
+
+       q = this%elements(1)
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1) = 1.0_bp 
+       END IF
+
+    CASE ("keplerian")
+
+       q = this%elements(1) * (1.0_bp - this%elements(2))
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1:2) = (/ 1.0_bp - this%elements(2), -this%elements(1) /)
+       END IF
+
+    CASE ("cartesian")
+
+       this_ = copy(this)
+       CALL rotateToEcliptic(this_)
+       pos = this_%elements(1:3)
+       vel = this_%elements(4:6)
+       r = SQRT(DOT_PRODUCT(pos,pos))
+       ! alpha = rv^2/mu
+       alpha = r*DOT_PRODUCT(vel,vel)/planetary_mu(this_%central_body)
+       IF (PRESENT(a)) THEN
+          a_ = a
+       ELSE
+          ! h = v^2/2 - mu/r and for elliptical orbits a = -mu/2h
+          ! -> a = r / (2 - rv^2/mu)
+          IF (ABS(2.0_bp - alpha) < 10.0_bp*EPSILON(alpha)) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getPeriapsisDistance", &
+                  "a is approaching infinity.", 1)
+             RETURN
+          END IF
+          a_ = r / (2.0_bp - alpha)
+          IF (a_ < 0.0_bp) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getPeriapsisDistance", &
+                  "Semimajor axis is negative.", 1)
+             RETURN
+          END IF
+       END IF
+       ! gamma = sqrt(mu*a)
+       gamma = SQRT(planetary_mu(this_%central_body)*a_)
+       IF (ABS(gamma) < TINY(gamma)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "Gamma is computationally too small.", 1)
+          RETURN
+       END IF
+       ! r(1+e*cos(f))=a|1-e^2|, r*cos(f)=a*cos(E)-ae, and for elliptical 
+       ! orbits a=r/(2-rv^2/mu) (see above) and |1-e^2|=1-e^2
+       ! -> e*cos(E)=rv^2/mu-1=alpha-1
+       e_cos_ea = alpha - 1.0_bp
+       !
+       e_sin_ea = DOT_PRODUCT(pos,vel)/gamma
+       e = SQRT(e_cos_ea**2.0_bp + e_sin_ea**2.0_bp)
+       IF (e > 1.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "Orbit is hyperbolic.", 1)
+          RETURN
+       ELSE IF (e < 10.0_bp*EPSILON(e)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "Orbit is almost circular (1).", 1)
+          WRITE(stderr,*) e
+          RETURN
+       END IF
+       CALL NULLIFY(this_)
+       q = a_*(1.0_bp - e)
+
+       IF (PRESENT(partials)) THEN
+          partials = 0.0_bp
+          partials(1:2) = (/ 1.0_bp - e, -a_ /)
+       END IF
+
+    END SELECT
+
+  END SUBROUTINE getPeriapsisDistance_Orb
+
+
+
+
+
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the previous Newtonian periapsis time computed in the
+  !! 2-b approximation. Optionally, returns periapsis time closest to
+  !! the given date.
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getPeriapsisTime(this, t)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)          :: this
+    TYPE (Time), INTENT(in), OPTIONAL :: t
+    TYPE (Time)                       :: getPeriapsisTime
+
+    TYPE (Time) :: t_
+    REAL(bp), DIMENSION(6) :: elements 
+    REAL(bp) :: tt_mjd, mean_motion, tt_mjd_periapsis, &
+         tt_mjd_periapsis_, period, dt_min
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPeriapsisTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this,"keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPeriapsisTime", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    t_ = copy(this%t)
+    tt_mjd = getMJD(t_, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPeriapsisTime", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t_)
+    mean_motion = SQRT(planetary_mu(this%central_body)/elements(1)**3.0_bp)
+    tt_mjd_periapsis = tt_mjd - elements(6)/mean_motion
+
+    IF (PRESENT(t)) THEN
+       IF (.NOT.exist(t)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisTime", &
+               "Date not initialized.", 1)
+          RETURN
+       END IF
+       t_ = copy(t)
+       tt_mjd = getMJD(t_, "TT")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPeriapsisTime", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(t_)
+       period = two_pi/mean_motion
+       tt_mjd_periapsis_ = tt_mjd_periapsis
+       dt_min = ABS(tt_mjd - tt_mjd_periapsis_)
+       IF (tt_mjd_periapsis_ < tt_mjd) THEN
+          DO WHILE (tt_mjd_periapsis_ < tt_mjd)
+             tt_mjd_periapsis_ = tt_mjd_periapsis_ + period
+             IF (ABS(tt_mjd - tt_mjd_periapsis_) < dt_min) THEN
+                tt_mjd_periapsis = tt_mjd_periapsis_
+                dt_min = ABS(tt_mjd - tt_mjd_periapsis_)
+             END IF
+          END DO
+       ELSE
+          DO WHILE (tt_mjd_periapsis_ > tt_mjd)
+             tt_mjd_periapsis_ = tt_mjd_periapsis_ - period
+             IF (ABS(tt_mjd - tt_mjd_periapsis_) < dt_min) THEN
+                tt_mjd_periapsis = tt_mjd_periapsis_
+                dt_min = ABS(tt_mjd - tt_mjd_periapsis_)
+             END IF
+          END DO
+       END IF
+    END IF
+
+    CALL NEW(getPeriapsisTime, tt_mjd_periapsis, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPeriapsisTime", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getPeriapsisTime
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the phase angle for an object on this orbit at a given
+  !! epoch as seen from a given observer. Optionally, returns partials
+  !! of phase angle wrt the cartesian position.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPhaseAngle_Orb(this, observer, phase_angle, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                   :: this
+    TYPE (CartesianCoordinates), INTENT(in)       :: observer
+    REAL(bp), INTENT(out)                         :: phase_angle
+    REAL(bp), DIMENSION(6), INTENT(out), OPTIONAL :: partials
+
+    TYPE (Orbit)                :: this_lt_corr
+    TYPE (CartesianCoordinates) :: ephemeris_ccoord, observer_
+    TYPE (SphericalCoordinates) :: ephemeris_scoord
+    REAL(bp), DIMENSION(6,6)    :: jacobian, jacobian_lt_corr, jacobian_prop
+    REAL(bp), DIMENSION(1,6)    :: partials_
+    REAL(bp), DIMENSION(3)      :: observer_pos, ephemeris_pos, heliocentric_pos
+    REAL(bp)                    :: cos_alpha, sqrt_
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Observer object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Topocentric light-time-corrected ephemeris:
+    IF (PRESENT(partials)) THEN
+       CALL getEphemeris(this, observer, ephemeris_scoord, &
+            this_lt_corr=this_lt_corr, &
+            jacobian_lt_corr=jacobian_lt_corr, &
+            jacobian_prop=jacobian_prop)
+       jacobian = MATMUL(jacobian_lt_corr, jacobian_prop)
+    ELSE
+       CALL getEphemeris(this, observer, ephemeris_scoord, &
+            this_lt_corr=this_lt_corr)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+    CALL NEW(ephemeris_ccoord, ephemeris_scoord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+
+    IF (getFrame(this) == "equatorial") THEN
+       CALL rotateToEquatorial(ephemeris_ccoord)
+       CALL rotateToEquatorial(this_lt_corr)
+    ELSE IF (getFrame(this) == "ecliptic") THEN
+       CALL rotateToEcliptic(ephemeris_ccoord)
+       CALL rotateToEcliptic(this_lt_corr)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Unknown frame.", 1)
+       RETURN       
+    END IF
+    ephemeris_pos = getPosition(ephemeris_ccoord)
+    heliocentric_pos = getPosition(this_lt_corr)
+
+    ! Cosine of phase angle:
+    cos_alpha = DOT_PRODUCT(heliocentric_pos,ephemeris_pos)/ &
+         (SQRT(DOT_PRODUCT(heliocentric_pos,heliocentric_pos))* &
+         SQRT(DOT_PRODUCT(ephemeris_pos,ephemeris_pos)))
+    IF (ABS(cos_alpha) > 1.0_bp) THEN
+       cos_alpha = SIGN(1.0_bp,cos_alpha)
+    END IF
+
+    ! Phase angle:
+    IF (cos_alpha == -1.0_bp) THEN
+       phase_angle = pi
+    ELSE IF (cos_alpha == 1.0_bp) THEN
+       phase_angle = 0.0_bp
+    ELSE
+       phase_angle = ACOS(cos_alpha)
+    END IF
+
+    ! Partials of phase angle wrt Cartesian position:
+    IF (PRESENT(partials)) THEN
+       observer_ = copy(observer)
+       IF (getFrame(this) == "equatorial") THEN
+          CALL rotateToEquatorial(observer_)
+       ELSE IF (getFrame(this) == "ecliptic") THEN
+          CALL rotateToEcliptic(observer_)
+       END IF
+       observer_pos = getPosition(observer_)
+       CALL NULLIFY(observer_)
+       partials_ = 0.0_bp
+       sqrt_ = DOT_PRODUCT(heliocentric_pos,heliocentric_pos) * &
+            DOT_PRODUCT(ephemeris_pos,ephemeris_pos) * (1.0_bp - &
+            DOT_PRODUCT(heliocentric_pos,ephemeris_pos)**2.0_bp / &
+            (DOT_PRODUCT(heliocentric_pos,heliocentric_pos) * &
+            DOT_PRODUCT(ephemeris_pos,ephemeris_pos)))
+       IF (sqrt_ < 10.0_bp*EPSILON(sqrt_)) THEN
+          partials_(1,1:3) = 1.0E-07_bp
+       ELSE
+          sqrt_ = SQRT(sqrt_)
+       END IF
+       partials_(1,1:3) = (observer_pos - heliocentric_pos * (2.0_bp - &
+            DOT_PRODUCT(heliocentric_pos,ephemeris_pos) * &
+            (1.0_bp / DOT_PRODUCT(ephemeris_pos,ephemeris_pos) + &
+            1.0_bp / DOT_PRODUCT(heliocentric_pos,heliocentric_pos)))) / &
+            sqrt_
+       partials_ = MATMUL(partials_,jacobian)
+       partials(1:3) = partials_(1,1:3)
+    END IF
+
+  END SUBROUTINE getPhaseAngle_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the phase angles for an object on this orbit at a given
+  !! epoch as seen from given observers.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPhaseAngles_Orb(this, observers, phase_angles)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                           :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: observers
+    REAL(bp), DIMENSION(:), POINTER                       :: phase_angles
+
+    TYPE (Orbit), DIMENSION(:), POINTER :: this_lt_corr_arr
+    TYPE (CartesianCoordinates) :: ephemeris_ccoord, observer_
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemerides
+!!$    REAL(bp), DIMENSION(:,:,:), POINTER :: jacobian_lt_corr_arr, jacobian_prop_arr
+!!$    REAL(bp), DIMENSION(6,6) :: jacobian
+!!$    REAL(bp), DIMENSION(1,6) :: partials_
+    REAL(bp), DIMENSION(3) :: observer_pos, ephemeris_pos, heliocentric_pos
+    REAL(bp) :: cos_alpha, sqrt_
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngles", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,SIZE(observers)
+       IF (.NOT.exist(observers(i))) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPhaseAngles", &
+               "Observer object has not been initialized.", 1)
+          RETURN
+       END IF
+    END DO
+
+    ALLOCATE(phase_angles(SIZE(observers)))
+    ! Topocentric light-time-corrected ephemeris:
+!!$    IF (PRESENT(partials)) THEN
+!!$       ALLOCATE(partials(SIZE(observers),6))
+!!$       CALL getEphemerides(this, observers, ephemerides, &
+!!$            this_lt_corr_arr=this_lt_corr_arr, &
+!!$            jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+!!$            jacobian_prop_arr=jacobian_prop_arr)
+!!$    ELSE
+    CALL getEphemerides(this, observers, ephemerides, &
+         this_lt_corr_arr=this_lt_corr_arr)
+!!$    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPhaseAngles", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+
+    DO i=1,SIZE(observers)
+
+       CALL NEW(ephemeris_ccoord, ephemerides(i))
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPhaseAngles", &
+               "TRACE BACK 10", 1)
+          RETURN
+       END IF
+
+       IF (getFrame(this) == "equatorial") THEN
+          CALL rotateToEquatorial(ephemeris_ccoord)
+          CALL rotateToEquatorial(this_lt_corr_arr(i))
+       ELSE IF (getFrame(this) == "ecliptic") THEN
+          CALL rotateToEcliptic(ephemeris_ccoord)
+          CALL rotateToEcliptic(this_lt_corr_arr(i))
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPhaseAngles", &
+               "Unknown frame.", 1)
+          RETURN       
+       END IF
+       ephemeris_pos = getPosition(ephemeris_ccoord)
+       heliocentric_pos = getPosition(this_lt_corr_arr(i))
+       CALL NULLIFY(ephemeris_ccoord)
+
+       ! Cosine of phase angle:
+       cos_alpha = DOT_PRODUCT(heliocentric_pos,ephemeris_pos)/ &
+            (SQRT(DOT_PRODUCT(heliocentric_pos,heliocentric_pos))* &
+            SQRT(DOT_PRODUCT(ephemeris_pos,ephemeris_pos)))
+       IF (ABS(cos_alpha) > 1.0_bp) THEN
+          cos_alpha = SIGN(1.0_bp,cos_alpha)
+       END IF
+
+       ! Phase angle:
+       IF (cos_alpha == -1.0_bp) THEN
+          phase_angles(i) = pi
+       ELSE IF (cos_alpha == 1.0_bp) THEN
+          phase_angles(i) = 0.0_bp
+       ELSE
+          phase_angles(i) = ACOS(cos_alpha)
+       END IF
+
+!!$       ! Partials of phase angle wrt Cartesian position:
+!!$       IF (PRESENT(partials)) THEN
+!!$          observer_ = copy(observers(i))
+!!$          IF (getFrame(this) == "equatorial") THEN
+!!$             CALL rotateToEquatorial(observer_)
+!!$          ELSE IF (getFrame(this) == "ecliptic") THEN
+!!$             CALL rotateToEcliptic(observer_)
+!!$          END IF
+!!$          observer_pos = getPosition(observer_)
+!!$          CALL NULLIFY(observer_)
+!!$          partials_ = 0.0_bp
+!!$          sqrt_ = DOT_PRODUCT(heliocentric_pos,heliocentric_pos) * &
+!!$               DOT_PRODUCT(ephemeris_pos,ephemeris_pos) * (1.0_bp - &
+!!$               DOT_PRODUCT(heliocentric_pos,ephemeris_pos)**2.0_bp / &
+!!$               (DOT_PRODUCT(heliocentric_pos,heliocentric_pos) * &
+!!$               DOT_PRODUCT(ephemeris_pos,ephemeris_pos)))
+!!$          IF (sqrt_ < 10.0_bp*EPSILON(sqrt_)) THEN
+!!$             partials_(1,1:3) = 1.0E-07_bp
+!!$          ELSE
+!!$             sqrt_ = SQRT(sqrt_)
+!!$          END IF
+!!$          partials_(1,1:3) = (observer_pos - heliocentric_pos * (2.0_bp - &
+!!$               DOT_PRODUCT(heliocentric_pos,ephemeris_pos) * &
+!!$               (1.0_bp / DOT_PRODUCT(ephemeris_pos,ephemeris_pos) + &
+!!$               1.0_bp / DOT_PRODUCT(heliocentric_pos,heliocentric_pos)))) / &
+!!$               sqrt_
+!!$          jacobian = MATMUL(jacobian_lt_corr_arr(i,:,:), jacobian_prop_arr(i,:,:))
+!!$          partials_ = MATMUL(partials_,jacobian)
+!!$          partials(i,1:3) = partials_(1,1:3)
+!!$          partials(i,4:6) = 0.0_bp
+!!$          CALL NULLIFY(observer_)
+!!$       END IF
+
+    END DO
+
+!!$    IF (PRESENT(partials)) THEN
+!!$       DEALLOCATE(this_lt_corr_arr)
+!!$       DEALLOCATE(jacobian_lt_corr_arr)
+!!$       DEALLOCATE(jacobian_prop_arr)
+!!$    END IF
+
+  END SUBROUTINE getPhaseAngles_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the previous Newtonian plane-crossing (corresponding to
+  !! the date when the object is at the ascending node) time computed
+  !! in the 2-b approximation. Optionally, returns plane-crossing time
+  !! closest to the given date.
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getPlaneCrossingTime(this, t)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)          :: this
+    TYPE (Time), INTENT(in), OPTIONAL :: t
+    TYPE (Time)                       :: getPlaneCrossingTime
+
+    TYPE (Time) :: t_
+    REAL(bp), DIMENSION(6) :: elements 
+    REAL(bp) :: tt_mjd, mean_motion, tt_mjd_planecrossing, &
+         tt_mjd_planecrossing_, period, dt_min
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPlaneCrossingTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this,"keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPlaneCrossingTime", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    t_ = copy(this%t)
+    tt_mjd = getMJD(t_, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPlaneCrossingTime", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t_)
+    mean_motion = SQRT(planetary_mu(this%central_body)/elements(1)**3.0_bp)
+    tt_mjd_planecrossing = tt_mjd - MODULO(SUM(elements(5:6)), two_pi)/mean_motion
+
+    IF (PRESENT(t)) THEN
+       IF (.NOT.exist(t)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPlaneCrossingTime", &
+               "Date not initialized.", 1)
+          RETURN
+       END IF
+       t_ = copy(t)
+       tt_mjd = getMJD(t_, "TT")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPlaneCrossingTime", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(t_)
+       period = two_pi/mean_motion
+       tt_mjd_planecrossing_ = tt_mjd_planecrossing
+       dt_min = ABS(tt_mjd - tt_mjd_planecrossing_)
+       IF (tt_mjd_planecrossing_ < tt_mjd) THEN
+          DO WHILE (tt_mjd_planecrossing_ < tt_mjd)
+             tt_mjd_planecrossing_ = tt_mjd_planecrossing_ + period
+             IF (ABS(tt_mjd - tt_mjd_planecrossing_) < dt_min) THEN
+                tt_mjd_planecrossing = tt_mjd_planecrossing_
+                dt_min = ABS(tt_mjd - tt_mjd_planecrossing_)
+             END IF
+          END DO
+       ELSE
+          DO WHILE (tt_mjd_planecrossing_ > tt_mjd)
+             tt_mjd_planecrossing_ = tt_mjd_planecrossing_ - period
+             IF (ABS(tt_mjd - tt_mjd_planecrossing_) < dt_min) THEN
+                tt_mjd_planecrossing = tt_mjd_planecrossing_
+                dt_min = ABS(tt_mjd - tt_mjd_planecrossing_)
+             END IF
+          END DO
+       END IF
+    END IF
+
+    CALL NEW(getPlaneCrossingTime, tt_mjd_planecrossing, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPlaneCrossingTime", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getPlaneCrossingTime
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns Poincaré elements calculated from Delaunay's
+  !! elements. The mass of the target body is assumed to be negligible
+  !! compared to the mass of the Sun.
+  !  (&radic = square root)
+  !!
+  !!   - pv(1) = &Lambda = L
+  !!   - pv(2) = &xi     = &radic(2(L - G)) * cos(g + &theta)
+  !!   - pv(3) = p       = &radic(2(G - &Theta)) * cos(&theta)
+  !!   - pv(4) = &lambda = l + g + &theta
+  !!   - pv(5) = &eta    = -&radic(2(L - G)) * sin(g + &theta)
+  !!   - pv(6) = q       = -&radic(2(G - &Theta)) * sin(&theta)
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getPoincareElements(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)   :: getPoincareElements
+    REAL(bp), DIMENSION(6)   :: de
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPoincareElements", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    de = getDelaunayElements(this)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPoincareElements", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    getPoincareElements(1) = de(4)
+    getPoincareElements(2) = SQRT(2.0_bp*(de(4) - de(5))) * COS(de(2) + de(3))
+    getPoincareElements(3) = SQRT(2.0_bp*(de(5) - de(6))) * COS(de(3))
+    getPoincareElements(4) = de(1) + de(2) + de(3)
+    ! Make sure that lambda=[0,2*pi]:
+    getPoincareElements(4) = MODULO(getPoincareElements(4),two_pi)
+    getPoincareElements(5) = -1.0_bp * SQRT(2.0_bp*(de(4) - de(5))) * SIN(de(2) + de(3))
+    getPoincareElements(6) = -1.0_bp * SQRT(2.0_bp*(de(5) - de(6))) * SIN(de(3))
+
+  END FUNCTION getPoincareElements
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian position vector as AUs.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPosition_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)   :: getPosition_Orb
+    REAL(bp), DIMENSION(6)   :: celements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPosition", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    celements(1:6) = getCartesianElements(this, this%frame)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPosition", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    getPosition_Orb(1:3) = celements(1:3)
+
+  END FUNCTION getPosition_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns equatorial spherical elements.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getSCoord_Orb(this, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)    :: this
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+    TYPE (SphericalCoordinates) :: getSCoord_Orb
+    TYPE (CartesianCoordinates) :: ccoord
+    CHARACTER(len=FRAME_LEN)    :: frame_
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getSCoord", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+       CALL locase(frame_, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / getSCoord", &
+               "The frame string contains forbidden characters.", 1)
+          RETURN
+       END IF
+    ELSE IF (this%element_type == "cartesian") THEN
+       frame_ = this%frame
+    ELSE IF (this%element_type == "keplerian" .OR. &
+         this%element_type == "cometary") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getSCoord", &
+            "Frame must be given explicitly if the " // &
+            "input is Keplerian or cometary elements.", 1)
+       RETURN
+    END IF
+    ! orbit -> cartesian coordinates
+    ccoord = getCCoord(this, frame_) 
+    IF (error) THEN
+       CALL errorMessage("Orbit / getSCoord", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    ! cartesian coordinates -> spherical coordinates
+    CALL NULLIFY(getSCoord_Orb)
+    getSCoord_Orb = getSCoord(ccoord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getSCoord", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(ccoord)
+
+  END FUNCTION getSCoord_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the values of the Stumpff c0, c1, c2, and c3 
+  !! functions.
+  !!
+  !! Returns error.
+  !!
+  !! Reference: 
+  !! Danby, J. M.: Fundamentals of Celestial Mechanics, 2nd ed., 
+  !!               rev. ed. Richmond, VA: Willmann-Bell, pp. 170-178, 1988
+  !!
+  SUBROUTINE getStumpffFunctions(x, stumpff_c)
+
+    USE functions
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)                  :: x
+    REAL(bp), DIMENSION(0:3), INTENT(out) :: stumpff_c
+    REAL(bp), PARAMETER                   :: xm = 0.1_bp 
+    REAL(bp), PARAMETER                   :: xc = -1.0e5_bp
+    REAL(bp)                              :: y
+    INTEGER                               :: n, i
+
+    IF (x < xc) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getStumpffFunctions", &
+            "x < xc", 1)
+       RETURN
+    END IF
+
+    y = x
+    n = 0
+    DO WHILE (.NOT. ABS(y) < xm)
+       n = n + 1
+       y = y/4.0_bp
+    END DO
+
+    stumpff_c(3) = stumpff(y,3)
+    stumpff_c(2) = stumpff(y,2)
+    stumpff_c(1) = stumpff(y,1,stumpff_c(3))
+    stumpff_c(0) = stumpff(y,0,stumpff_c(2))
+
+    DO i=n, 1, -1
+       stumpff_c(3) = 0.25_bp * (stumpff_c(2) + &
+            stumpff_c(0)*stumpff_c(3))
+       stumpff_c(2) = 0.5_bp * stumpff_c(1)**2.0_bp
+       stumpff_c(1) = stumpff_c(0) * stumpff_c(1)
+       stumpff_c(0) = 2.0_bp * stumpff_c(0)**2.0_bp - 1.0_bp
+    END DO
+
+  END SUBROUTINE getStumpffFunctions
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Time-object corresponding to this orbit.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTime_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    TYPE (Time)                       :: getTime_Orb
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getTime_Orb = copy(this%t)
+
+  END FUNCTION getTime_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Tisserand's parameters for this orbit wrt the 8
+  !! planets, Pluto, and the Moon.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTisserandsParameters_Orb(this) RESULT(tisserands_parameter)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(10) :: tisserands_parameter 
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(:,:), POINTER :: planeph
+    REAL(bp), DIMENSION(6) :: elements, elements_
+    REAL(bp) :: mjd_tt
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTisserandsParameters", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this,"keplerian")
+    t = getTime(this)
+    mjd_tt = getMJD(t, "TT")
+    planeph => JPL_ephemeris(mjd_tt, -10, 11, error)
+
+    DO i=1,SIZE(planeph,dim=1)
+       CALL NEW(orb, planeph(i,1:6), "cartesian", "equatorial", t) 
+       elements_ = getElements(orb, "keplerian")
+       CALL NULLIFY(orb)
+       tisserands_parameter(i) = elements_(1)/elements(1) + &
+            2.0_bp*SQRT(elements(1)/elements_(1)*(1.0_bp-elements(2)**2)) * &
+            COS(elements(3)-elements_(3))
+    END DO
+    DEALLOCATE(planeph)
+    CALL NULLIFY(t)
+
+  END FUNCTION getTisserandsParameters_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Jacobi constants, C, for this orbit wrt the 8
+  !! planets, Pluto, and the Moon.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getJacobiConstants_Orb(this) RESULT(jacobi_constant)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(10) :: jacobi_constant 
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(:,:), POINTER :: planeph
+    REAL(bp), DIMENSION(6) :: elements, elements_, coordinates, &
+         coordinates_
+    REAL(bp) :: mjd_tt, d, mass_ratio
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getJacobiConstants", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this,"keplerian")
+    coordinates = getElements(this,"cartesian","ecliptic")
+    t = getTime(this)
+    mjd_tt = getMJD(t, "TT")
+    planeph => JPL_ephemeris(mjd_tt, -10, 11, error)
+
+    DO i=1,SIZE(planeph,dim=1)
+       CALL NEW(orb, planeph(i,1:6), "cartesian", "equatorial", t) 
+       IF (error) THEN
+          RETURN
+       END IF
+       !elements_ = getElements(orb, "keplerian")
+       coordinates_ = getElements(orb,"cartesian","ecliptic")
+       d = SQRT(SUM(coordinates_(1:3)**2))
+       mass_ratio = planetary_masses(i) / (1.0_bp+planetary_masses(i))
+       CALL NULLIFY(orb)
+       jacobi_constant(i) = -1.0_bp/(2.0_bp*elements(1)) - &
+            SQRT(elements(1)*(1.0_bp-elements(2)**2)) * &
+            COS(elements(3)-elements_(3)) - mass_ratio * &
+            (d/SQRT(SUM((coordinates_(1:3)-coordinates(1:3))**2)) - &
+            d/SQRT(SUM(coordinates(1:3)**2)))
+    END DO
+    DEALLOCATE(planeph)
+    CALL NULLIFY(t)
+
+  END FUNCTION getJacobiConstants_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial
+  !! coordinates from the object's heliocentric Cartesian orbit and 
+  !! the observers" heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial coordinates
+  !! wrt object's heliocentric Cartesian orbital elements are
+  !! calculated.
+  !! 
+  !! Returns error.
+  !!
+  SUBROUTINE getTopocentricSCoords(this, topocenters, scoords_tc, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                           :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: topocenters
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER    :: scoords_tc
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL         :: partials
+    INTEGER                                               :: i, err
+
+    ALLOCATE(scoords_tc(SIZE(topocenters)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTopocentricSCoords", &
+            "Could not allocate pointer (1).", 1)
+       DEALLOCATE(scoords_tc, stat=err)
+       RETURN
+    END IF
+    IF (PRESENT(partials)) THEN
+       ALLOCATE(partials(6,6,SIZE(topocenters)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getTopocentricSCoords", &
+               "Could not allocate pointer (2).", 1)
+          DEALLOCATE(scoords_tc, stat=err)
+          DEALLOCATE(partials, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    CALL toCartesian(this, frame="equatorial")
+    DO i=1, SIZE(topocenters,dim=1)
+       !       if (present(partials)) then
+       !          CALL getTopocentricSCoord(this, topocenters(i), scoords_tc(i), partials(:,:,i))
+       !       else
+       CALL getTopocentricSCoord(this, topocenters(i), scoords_tc(i))
+       !       end if
+       IF (error) THEN
+          CALL errorMessage("Orbit / getTopocentricSCoords", &
+               "TRACE BACK 10", 1)
+          DEALLOCATE(scoords_tc, stat=err)
+          IF (PRESENT(partials)) THEN
+             DEALLOCATE(partials, stat=err)
+             RETURN
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE getTopocentricSCoords
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes spherical topocentric equatorial
+  !! coordinates from the object's heliocentric Cartesian orbit and 
+  !! the observer's heliocentric Cartesian coordinates. Both 
+  !! Cartesian elements and coordinates can be given either as 
+  !! equatorial or ecliptic. Optionally, partial derivatives of the
+  !! spherical topocentric equatorial coordinates
+  !! wrt object's heliocentric Cartesian orbital elements are
+  !! calculated. NOT APPLICABLE FOR THE TIME BEING: The given orbit is
+  !! propagated to the coordinate epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getTopocentricSCoord(this, topocenter, scoord_tc, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                     :: this
+    TYPE (CartesianCoordinates), INTENT(in)         :: topocenter
+    TYPE (SphericalCoordinates), INTENT(out)        :: scoord_tc
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: partials
+    TYPE (Orbit)                                    :: this_
+    TYPE (CartesianCoordinates)                     :: topocenter_
+    TYPE (Time)                                     :: t_topocenter
+    REAL(bp), DIMENSION(6,6)                        :: jacobian
+    REAL(bp), DIMENSION(6,6)                        :: scoord_partials
+    REAL(bp), DIMENSION(6)                          :: topocenter_coordinates
+    INTEGER                                         :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTopocentricSCoord", &
+            "This object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(topocenter)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTopocentricSCoord", &
+            "'topocenter' has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this_ = copy(this)
+    topocenter_ = copy(topocenter)
+    t_topocenter = getTime(topocenter)
+    IF (PRESENT(partials)) THEN 
+       CALL propagate(this_, t_topocenter, jacobian=jacobian)
+    ELSE
+       CALL propagate(this_, t_topocenter)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / getTopocentricSCoord", &
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+
+    ! Transform to topocentric coordinates:
+    !    this_ = copy(this)
+    CALL toCartesian(this_, frame="equatorial")
+    CALL rotateToEquatorial(topocenter_)
+    topocenter_coordinates(1:6) = getCoordinates(topocenter_)
+    this_%elements(1:6) = this_%elements(1:6) - &
+         topocenter_coordinates(1:6)
+    scoord_tc = getSCoord(this_)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getTopocentricSCoord", &
+            "TRACE BACK 6", 1)
+       RETURN
+    END IF
+
+    ! Partial derivatives:
+    IF (PRESENT(partials)) THEN
+
+       SELECT CASE (this%element_type)
+
+       CASE ("cartesian")
+
+          ! Rotate each row of Jacobian (gradient) to ecliptical frame.
+          DO i=1,6
+             CALL rotateToEcliptic(jacobian(i,:))
+          END DO
+          ! Topocentric equatorial (ra,dec) wrt topocentric equatorial Cartesian. 
+          CALL partialsSCoordWrtCartesian_d(this_, scoord_partials)
+          IF (error) THEN
+             CALL errorMessage("Orbit / getTopocentricSCoord", &
+                  "TRACE BACK 8", 1)
+             RETURN
+          END IF
+
+       CASE ("keplerian")
+
+          ! Topocentric equatorial (ra,dec) wrt Keplerian orbital elements.
+          CALL partialsSCoordWrtKeplerian(this_, topocenter_, scoord_partials)
+          IF (error) THEN
+             CALL errorMessage("Orbit / getTopocentricSCoord", &
+                  "TRACE BACK 10", 1)
+             RETURN
+          END IF
+
+       CASE default
+
+          error = .TRUE.
+          CALL errorMessage("Orbit / getTopocentricSCoord", &
+               "Could not choose between element types" // &
+               "('cartesian' or 'keplerian'): " // &
+               TRIM(this%element_type), 1)
+          RETURN
+
+       END SELECT
+
+       ! Chain rule.
+       partials = MATMUL(scoord_partials, jacobian)
+
+    END IF
+
+  END SUBROUTINE getTopocentricSCoord
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the transformation matrix from polar coordinate
+  !! system to the ecliptical one.
+  !!
+  !!
+  !! Returns error.
+  !! 
+  FUNCTION getTransformationMatrix(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(3,3) :: getTransformationMatrix
+    REAL(bp), DIMENSION(6)   :: elements
+    REAL(bp), DIMENSION(3)   :: sin_angles, cos_angles
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getTransformationMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%element_type == "keplerian" .OR. &
+         this%element_type == "cometary") THEN
+       sin_angles = (/ SIN(this%elements(3)), SIN(this%elements(4)), SIN(this%elements(5)) /)
+       cos_angles = (/ COS(this%elements(3)), COS(this%elements(4)), COS(this%elements(5)) /)
+    ELSE
+       elements = getElements(this, "keplerian")
+       sin_angles = (/ SIN(elements(3)), SIN(elements(4)), SIN(elements(5)) /)
+       cos_angles = (/ COS(elements(3)), COS(elements(4)), COS(elements(5)) /)       
+    END IF
+
+    getTransformationMatrix(1,1) = cos_angles(2)*cos_angles(3) - &
+         sin_angles(2)*sin_angles(3)*cos_angles(1)
+    getTransformationMatrix(1,2) = -(cos_angles(2)*sin_angles(3) + &
+         sin_angles(2)*cos_angles(3)*cos_angles(1))
+    getTransformationMatrix(1,3) = sin_angles(2)*sin_angles(1)
+
+    getTransformationMatrix(2,1) = sin_angles(2)*cos_angles(3) + &
+         cos_angles(2)*sin_angles(3)*cos_angles(1)
+    getTransformationMatrix(2,2) = -(sin_angles(2)*sin_angles(3) - &
+         cos_angles(2)*cos_angles(3)*cos_angles(1))
+    getTransformationMatrix(2,3) = -cos_angles(2)*sin_angles(1)
+
+    getTransformationMatrix(3,1) = sin_angles(3)*sin_angles(1)
+    getTransformationMatrix(3,2) = cos_angles(3)*sin_angles(1)
+    getTransformationMatrix(3,3) = cos_angles(1)
+
+  END FUNCTION getTransformationMatrix
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the Cartesian velocity vector as AUs per day.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getVelocity_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)   :: getVelocity_Orb
+    REAL(bp), DIMENSION(6)   :: celements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getVelocity", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    celements(1:6) = getCartesianElements(this, this%frame)
+    IF (error) THEN
+       CALL errorMessage("Orbit / getVelocity", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    getVelocity_Orb(1:3) = celements(4:6)
+
+  END FUNCTION getVelocity_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes the opposite Cartesian orbit, e.g., position and
+  !! velocity multiplied by -1.
+  !!
+  !! Returns error. 
+  !!
+  FUNCTION opposite_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: this
+    TYPE (Orbit)             :: opposite_Orb
+
+    opposite_Orb = copy(this)
+    IF (opposite_Orb%element_type /= "cartesian") THEN
+       CALL toCartesian(opposite_Orb, frame=this%frame)
+    END IF
+    opposite_Orb%elements = -1.0_bp * this%elements
+
+  END FUNCTION opposite_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of Cartesian orbital elements
+  !! wrt cometary orbital elements.
+  !!
+  !!       dx/dq      dx/de      dx/di      dx/dOmega      dx/domega      dx/dt
+  !!
+  !!       dy/dq      dy/de      dy/di      dy/dOmega      dy/domega      dy/dt
+  !!
+  !!       dz/dq      dz/de      dz/di      dz/dOmega      dz/domega      dz/dt
+  !!
+  !!      ddx/dq     ddx/de     ddx/di     ddx/dOmega     ddx/domega     ddx/dt
+  !!
+  !!      ddy/dq     ddy/de     ddy/di     ddy/dOmega     ddy/domega     ddy/dt
+  !!
+  !!      ddz/dq     ddz/de     ddz/di     ddz/dOmega     ddz/domega     ddz/dt
+  !!
+  SUBROUTINE partialsCartesianWrtCometary(this, partials, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+
+    CHARACTER(len=1024) :: errstr
+
+    ! Cometary wrt Cartesian:
+    IF (PRESENT(frame)) THEN
+       CALL partialsCometaryWrtCartesian(this, partials, frame)
+    ELSE
+       CALL partialsCometaryWrtCartesian(this, partials)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCartesianWrtCometary", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+    errstr = ""
+    partials = matinv(partials, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCartesianWrtCometary", &
+            "From matinv in linal: " // TRIM(errstr), 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE partialsCartesianWrtCometary
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of Cartesian orbital elements
+  !! wrt Keplerian orbital elements.
+  !!
+  !!       dx/da      dx/de      dx/di      dx/dOmega      dx/domega      dx/dM
+  !!
+  !!       dy/da      dy/de      dy/di      dy/dOmega      dy/domega      dy/dM
+  !!
+  !!       dz/da      dz/de      dz/di      dz/dOmega      dz/domega      dz/dM
+  !!
+  !!      ddx/da     ddx/de     ddx/di     ddx/dOmega     ddx/domega     ddx/dM
+  !!
+  !!      ddy/da     ddy/de     ddy/di     ddy/dOmega     ddy/domega     ddy/dM
+  !!
+  !!      ddz/da     ddz/de     ddz/di     ddz/dOmega     ddz/domega     ddz/dM
+  !!
+  SUBROUTINE partialsCartesianWrtKeplerian(this, partials, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+
+    REAL(bp), DIMENSION(6,6) :: pecl
+    REAL(bp), DIMENSION(4,6) :: ppolar
+    REAL(bp), DIMENSION(3,3) :: RM
+    REAL(bp), DIMENSION(6) :: kep_elements
+    REAL(bp), DIMENSION(4) :: polar_coord
+    REAL(bp), DIMENSION(3) :: vector3, sin_angles, cos_angles
+    REAL(bp) :: tmp1, tmp2, tmp3, tmp4, b, mm
+    INTEGER :: i
+    CHARACTER(len=FRAME_LEN) :: frame_
+
+    partials = 0.0_bp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    kep_elements = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+            "TRACE BACK 1", 1)
+       RETURN
+    END IF
+
+    ! Semiminor axis:
+    b = kep_elements(1) * SQRT(1.0_bp - kep_elements(2)**2)
+
+    ! Mean motion:
+    mm = SQRT(planetary_mu(this%central_body))/SQRT(kep_elements(1)**3.0_bp)
+
+    ! Sines and cosines of the inclination, the longitude of the
+    ! ascending node, and the argument of periapsis:
+    sin_angles(1) = SIN(kep_elements(3))
+    sin_angles(2) = SIN(kep_elements(4))
+    sin_angles(3) = SIN(kep_elements(5))
+    cos_angles(1) = COS(kep_elements(3))
+    cos_angles(2) = COS(kep_elements(4))
+    cos_angles(3) = COS(kep_elements(5))
+
+    CALL partialsPolarCoordWrtKeplerian(this, ppolar, polar_coord)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+
+    ! Partials for Cartesian ecliptic: a, e, M
+    DO i=1,3
+       vector3(:) = 0.0_bp
+       RM = getTransformationMatrix(this)
+       IF (error) THEN
+          CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       vector3(1:2) = ppolar(1:2,i)
+       pecl(1:3,i) = MATMUL(RM,vector3)
+
+       vector3(:) = 0.0_bp
+       vector3(1:2) = ppolar(3:4,i)
+       pecl(4:6,i) = MATMUL(RM,vector3)
+    END DO
+    pecl(:,6) = pecl(:,3)
+
+    ! Partials for Cartesian ecliptic: i, Om, om
+    tmp1 = -sin_angles(2)*cos_angles(3) - &
+         cos_angles(2)*sin_angles(3)*cos_angles(1)
+
+    tmp2 =  sin_angles(2)*sin_angles(3) - &
+         cos_angles(2)*cos_angles(3)*cos_angles(1)
+
+    tmp3 =  cos_angles(2)*cos_angles(3) - &
+         sin_angles(2)*sin_angles(3)*cos_angles(1)
+
+    tmp4 = -cos_angles(2)*sin_angles(3) - &
+         sin_angles(2)*cos_angles(3)*cos_angles(1)
+
+    ! Inclination:
+    ! coordinates
+    pecl(1,3) = polar_coord(1)*sin_angles(2)*sin_angles(3)*sin_angles(1) + &
+         polar_coord(2)*sin_angles(2)*cos_angles(3)*sin_angles(1)
+    pecl(2,3) =-polar_coord(1)*cos_angles(2)*sin_angles(3)*sin_angles(1) - &
+         polar_coord(2)*cos_angles(2)*cos_angles(3)*sin_angles(1)
+    pecl(3,3) = polar_coord(1)*sin_angles(3)*cos_angles(1) + &
+         polar_coord(2)*cos_angles(3)*cos_angles(1)
+    ! velocities
+    pecl(4,3) = polar_coord(3)*sin_angles(2)*sin_angles(3)*sin_angles(1) + &
+         polar_coord(4)*sin_angles(2)*cos_angles(3)*sin_angles(1)
+    pecl(5,3) =-polar_coord(3)*cos_angles(2)*sin_angles(3)*sin_angles(1) - &
+         polar_coord(4)*cos_angles(2)*cos_angles(3)*sin_angles(1)
+    pecl(6,3) = polar_coord(3)*sin_angles(3)*cos_angles(1) + &
+         polar_coord(4)*cos_angles(3)*cos_angles(1)
+
+    ! Longitude of ascending node
+    pecl(1,4) = polar_coord(1) * tmp1 + polar_coord(2) * tmp2
+    pecl(2,4) = polar_coord(1) * tmp3 + polar_coord(2) * tmp4
+    pecl(3,4) = 0.0_bp
+    pecl(4,4) = polar_coord(3) * tmp1 + polar_coord(4) * tmp2
+    pecl(5,4) = polar_coord(3) * tmp3 + polar_coord(4) * tmp4
+    pecl(6,4) = 0.0_bp
+
+    ! Argument of periapsis
+    pecl(1,5) = polar_coord(1) * tmp4 - polar_coord(2) * tmp3
+    pecl(2,5) =-polar_coord(1) * tmp2 + polar_coord(2) * tmp1
+    pecl(3,5) = polar_coord(1)*cos_angles(3)*sin_angles(1) - &
+         polar_coord(2)*sin_angles(3)*sin_angles(1)
+    pecl(4,5) = polar_coord(3) * tmp4 - polar_coord(4) * tmp3
+    pecl(5,5) =-polar_coord(3) * tmp2 + polar_coord(4) * tmp1
+    pecl(6,5) = polar_coord(3)*cos_angles(3)*sin_angles(1) - &
+         polar_coord(4)*sin_angles(3)*sin_angles(1)
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+       CALL locase(frame_, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+               "The frame string contains forbidden characters.", 1)
+          RETURN
+       END IF
+    ELSE IF (this%element_type == "cartesian") THEN
+       frame_ = this%frame
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+            "Coordinate frame undefined.", 1)
+       RETURN
+    END IF
+
+    IF (frame_ == "equatorial") THEN
+       DO i=1,6 ! i is element
+          CALL rotateToEquatorial(pecl(:,i))
+          partials(:,i) = pecl(:,i)
+       END DO
+    ELSE IF (frame_ == "ecliptic") THEN
+       partials = pecl
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCartesianWrtKeplerian", &
+            "Unknown frame:" // TRIM(frame_) // ".", 1)
+       RETURN       
+    END IF
+
+  END SUBROUTINE partialsCartesianWrtKeplerian
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of cometary orbital elements
+  !! wrt Keplerian orbital elements.
+  !!
+  !!       dq/da      dq/de      dq/di      dq/dOmega      dq/domega      dq/dM
+  !!
+  !!       de/da      de/de      de/di      de/dOmega      de/domega      de/dM
+  !!
+  !!       di/da      di/de      di/di      di/dOmega      di/domega      di/dM
+  !!
+  !!   dOmega/da  dOmega/de  dOmega/di  dOmega/dOmega  dOmega/domega  dOmega/dM
+  !!
+  !!   domega/da  domega/de  domega/di  domega/dOmega  domega/domega  domega/dM
+  !!
+  !!       dt/da      dt/de      dt/di      dt/dOmega      dt/domega      dt/dM
+  !!
+  SUBROUTINE partialsCometaryWrtKeplerian(this, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+
+    REAL(bp), DIMENSION(6) :: elements
+
+    ! Keplerian elements:
+    elements = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCometaryWrtKeplerian", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+    partials = identity_matrix(6)
+    ! 1 - e
+    partials(1,1) = 1.0_bp - elements(2)
+    ! a
+    partials(1,2) = elements(1)
+    ! Inverse of mean motion:
+    partials(6,6) = SQRT(elements(1)**3.0_bp)/SQRT(planetary_mu(this%central_body))
+
+  END SUBROUTINE partialsCometaryWrtKeplerian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of Keplerian orbital elements
+  !! wrt Cartesian orbital elements.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dq/dx     dq/dy     dq/dz     dq/ddx     dq/ddy     dq/ddz
+  !!       de/dx     de/dy     de/dz     de/ddx     de/ddy     de/ddz
+  !!       di/dx     di/dy     di/dz     di/ddx     di/ddy     di/ddz
+  !!   dOmega/dx dOmega/dy dOmega/dz dOmega/ddx dOmega/ddy dOmega/ddz
+  !!   domega/dx domega/dy domega/dz domega/ddx domega/ddy domega/ddz
+  !!       dt/dx     dt/dy     dt/dz     dt/ddx     dt/ddy     dt/ddz
+  !!
+  SUBROUTINE partialsCometaryWrtCartesian(this, partials, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+
+    CHARACTER(len=FRAME_LEN) :: frame_
+    REAL(bp), DIMENSION(6,6) :: com_kep, kep_car
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+       CALL locase(frame_, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+               "The frame string contains forbidden characters.", 1)
+          RETURN
+       END IF
+    ELSE IF (this%element_type == "cartesian") THEN
+       frame_ = this%frame
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+            "Coordinate frame undefined.", 1)
+       RETURN
+    END IF
+    IF (frame_ /= "ecliptic" .AND. frame_ /= "equatorial") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+            "Unknown frame:" // TRIM(frame_) // ".", 1)
+       RETURN       
+    END IF
+
+    CALL partialsKeplerianWrtCartesian(this, kep_car, frame_)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    CALL partialsCometaryWrtKeplerian(this, com_kep)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsCometaryWrtCartesian", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    partials = MATMUL(com_kep,kep_car)
+
+  END SUBROUTINE partialsCometaryWrtCartesian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of Keplerian orbital elements
+  !! wrt Cartesian orbital elements.
+  !!
+  !! partials-matrix:
+  !!
+  !!       da/dx     da/dy     da/dz     da/ddx     da/ddy     da/ddz
+  !!       de/dx     de/dy     de/dz     de/ddx     de/ddy     de/ddz
+  !!       di/dx     di/dy     di/dz     di/ddx     di/ddy     di/ddz
+  !!   dOmega/dx dOmega/dy dOmega/dz dOmega/ddx dOmega/ddy dOmega/ddz
+  !!   domega/dx domega/dy domega/dz domega/ddx domega/ddy domega/ddz
+  !!       dM/dx     dM/dy     dM/dz     dM/ddx     dM/ddy     dM/ddz
+  !!
+  SUBROUTINE partialsKeplerianWrtCartesian(this, partials, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+
+    CHARACTER(len=FRAME_LEN) :: frame_
+    REAL(bp), DIMENSION(6) :: kep_elements, car_elements, dr, dv, &
+         da, db, dc, du, dea
+    REAL(bp), DIMENSION(3) :: vector3, sin_angles, cos_angles
+    REAL(bp) :: tmp4, tmp5, ea, cea, sea, b, r, v, rv
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+       CALL locase(frame_, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+               "The frame string contains forbidden characters.", 1)
+          RETURN
+       END IF
+    ELSE IF (this%element_type == "cartesian") THEN
+       frame_ = this%frame
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "Coordinate frame undefined.", 1)
+       RETURN
+    END IF
+    IF (frame_ /= "ecliptic" .AND. frame_ /= "equatorial") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "Unknown frame:" // TRIM(frame_) // ".", 1)
+       RETURN       
+    END IF
+
+    ! (Ecliptic heliocentric) Keplerian elements:
+    kep_elements = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+
+    ! Ecliptic heliocentric Cartesian elements:
+    car_elements = getElements(this, "cartesian", frame="ecliptic")
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+
+    ! Semiminor axis:
+    b = kep_elements(1) * SQRT(1.0_bp - kep_elements(2)**2)
+
+    ! Sines and cosines of the inclination, the longitude of the
+    ! ascending node, and the argument of periapsis:
+    sin_angles(1) = SIN(kep_elements(3))
+    sin_angles(2) = SIN(kep_elements(4))
+    sin_angles(3) = SIN(kep_elements(5))
+    cos_angles(1) = COS(kep_elements(3))
+    cos_angles(2) = COS(kep_elements(4))
+    cos_angles(3) = COS(kep_elements(5))
+
+    ! Sine and cosine of eccentric anomaly:
+    CALL solveKeplerEquation(this, this%t, ea)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsKeplerianWrtCartesian", &
+            "TRACE BACK 15", 1)
+       RETURN
+    END IF
+    cea = COS(ea)
+    sea = SIN(ea)
+
+    ! r
+    r = SQRT(DOT_PRODUCT(car_elements(1:3),car_elements(1:3)))
+    ! v
+    v = SQRT(DOT_PRODUCT(car_elements(4:6),car_elements(4:6)))
+    ! rv
+    rv = DOT_PRODUCT(car_elements(1:3),car_elements(4:6))
+
+    dr(1:3) = car_elements(1:3)/r
+    dr(4:6) = 0.0_bp
+    dv(1:3) = 0.0_bp
+    dv(4:6) = car_elements(4:6)/v
+
+    ! Semimajor axis
+    partials(1,1:6) = kep_elements(1)*(1.0_bp + &
+         kep_elements(1)*v**2/planetary_mu(this%central_body))*dr/r + &
+         2.0_bp*kep_elements(1)**2*v*dv/planetary_mu(this%central_body)
+
+    ! Eccentricity and mean anomaly
+    da      = v*(v*dr+2.0_bp*r*dv)/planetary_mu(this%central_body)
+    db(1:3) = (car_elements(4:6)-rv*partials(1,1:3)/(2.0_bp*kep_elements(1))) / &
+         (SQRT(planetary_mu(this%central_body))*SQRT(kep_elements(1)))
+    db(4:6) = (car_elements(1:3)-rv*partials(1,4:6)/(2.0_bp*kep_elements(1))) / &
+         (SQRT(planetary_mu(this%central_body))*SQRT(kep_elements(1)))
+    dea     = (-sea*da+cea*db)/kep_elements(2)
+
+    partials(2,1:6) = cea*da+sea*db
+    partials(6,1:6) = dea*(1.0_bp-kep_elements(2)*cea) - &
+         sea*partials(2,1:6)
+
+    ! Inclination and longitude of ascending node
+    vector3 = cross_product(car_elements(1:3),car_elements(4:6))
+    tmp4 = SQRT(DOT_PRODUCT(vector3,vector3))
+
+    da = (/ 0.0_bp, car_elements(6), -car_elements(5), &
+         0.0_bp, -car_elements(3), car_elements(2) /)
+    db = (/ -car_elements(6), 0.0_bp, car_elements(4), &
+         car_elements(3), 0.0_bp, -car_elements(1) /)
+    dc = (/ car_elements(5), -car_elements(4), 0.0_bp, &
+         -car_elements(2), car_elements(1), 0.0_bp /)
+
+    du = (vector3(1)*da + vector3(2)*db + vector3(3)*dc)/tmp4
+    da = da/tmp4 - vector3(1)*du/tmp4**2
+    db = db/tmp4 - vector3(2)*du/tmp4**2
+    dc = dc/tmp4 - vector3(3)*du/tmp4**2
+
+    tmp5 = SQRT(1.0_bp-(vector3(3)/tmp4)**2)
+
+    partials(3,1:6) = -dc/sin_angles(1)
+    partials(4,1:6) = (cos_angles(2)*da + sin_angles(2)*db + &
+         (cos_angles(2)*vector3(1) + &
+         sin_angles(2)*vector3(2))*vector3(3)*dc/ &
+         (tmp4*tmp5)**2)/tmp5
+
+    ! Argument of periapsis
+    da = partials(1,1:6)*(cea-kep_elements(2)) + &
+         kep_elements(1)*(-sea*dea-partials(2,1:6))
+    db = partials(1,1:6)*SQRT(1.0_bp-kep_elements(2)**2)*sea - &
+         partials(2,1:6)*kep_elements(1)*kep_elements(2)*sea / &
+         SQRT(1.0_bp-kep_elements(2)**2) + dea*b*cea
+    dc = 0.0_bp
+    dc(3) = 1.0_bp
+
+    da = da*sin_angles(1) + &
+         kep_elements(1)*(cea-kep_elements(2))*cos_angles(1)*partials(3,1:6)
+    db = db*sin_angles(1) + b*sea*cos_angles(1)*partials(3,1:6)
+
+    partials(5,1:6) = (dc-da*sin_angles(3)-db*cos_angles(3)) / &
+         (kep_elements(1)*(cea-kep_elements(2))*sin_angles(1)*cos_angles(3) - &
+         b*sea*sin_angles(1)*sin_angles(3))
+
+    IF (frame_ == "equatorial") THEN
+       DO i=1,6 ! i is element
+          CALL rotateToEquatorial(partials(i,:))
+       END DO
+    END IF
+
+  END SUBROUTINE partialsKeplerianWrtCartesian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of Keplerian orbital elements
+  !! wrt cometary orbital elements.
+  !!
+  !!       da/dq      da/de      da/di      da/dOmega      da/domega      da/dt
+  !!
+  !!       de/dq      de/de      de/di      de/dOmega      de/domega      de/dt
+  !!
+  !!       di/dq      di/de      di/di      di/dOmega      di/domega      di/dt
+  !!
+  !!   dOmega/dq  dOmega/de  dOmega/di  dOmega/dOmega  dOmega/domega  dOmega/dt
+  !!
+  !!   domega/dq  domega/de  domega/di  domega/dOmega  domega/domega  domega/dt
+  !!
+  !!       dM/dq      dM/de      dM/di      dM/dOmega      dM/domega      dM/dt
+  !!
+  SUBROUTINE partialsKeplerianWrtCometary(this, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)               :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out)  :: partials
+
+    CHARACTER(len=1024) :: errstr
+
+    ! Cometary wrt Keplerian:
+    CALL partialsCometaryWrtKeplerian(this, partials)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsKeplerianWrtCometary", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+    errstr = ""
+    partials = matinv(partials, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsKeplerianWrtCometary", &
+            "From matinv in linal: " // TRIM(errstr), 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE partialsKeplerianWrtCometary
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of polar coordinates
+  !! wrt Keplerian orbital elements.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dr/da      dr/de      dr/di      dr/dOmega      dr/domega      dr/dM
+  !!
+  !!   dalpha/da  dalpha/de  dalpha/di  dalpha/dOmega  dalpha/domega  dalpha/dM
+  !!
+  !!   ddelta/da  ddelta/de  ddelta/di  ddelta/dOmega  ddelta/domega  ddelta/dM
+  !!
+  !!      ddr/da     ddr/de     ddr/di     ddr/dOmega     ddr/domega     ddr/dM
+  !!
+  !!  ddalpha/da ddalpha/de ddalpha/di ddalpha/dOmega ddalpha/domega ddalpha/dM
+  !!
+  !!  dddelta/da dddelta/de dddelta/di dddelta/dOmega dddelta/domega dddelta/dM
+  !!
+  SUBROUTINE partialsPolarCoordWrtKeplerian(this, partials, polar_coord)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                      :: this
+    REAL(bp), DIMENSION(4,6), INTENT(out)         :: partials
+    REAL(bp), DIMENSION(4), INTENT(out), OPTIONAL :: polar_coord
+
+    REAL(bp), DIMENSION(3) :: xpolar
+    REAL(bp), DIMENSION(6) :: kep_elements
+    REAL(bp) :: ea, cea, sea, r, b, mm
+
+    partials = 0.0_bp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsPolarCoordWrtKeplerian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    kep_elements = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsPolarCoordWrtKeplerian", &
+            "TRACE BACK 5", 1)
+       RETURN
+    END IF
+
+    ! Semiminor axis:
+    b = kep_elements(1) * SQRT(1.0_bp - kep_elements(2)**2)
+    ! Mean motion:
+    mm = SQRT(planetary_mu(this%central_body))/SQRT(kep_elements(1)**3.0_bp)
+
+    CALL solveKeplerEquation(this, this%t, ea)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsPolarCoordWrtKeplerian", &
+            "TRACE BACK 15", 1)
+       RETURN
+    END IF
+
+    cea = COS(ea)
+    sea = SIN(ea)
+    r = kep_elements(1)*(1.0_bp - kep_elements(2)*cea)
+    xpolar(1) = kep_elements(1)*(cea-kep_elements(2))
+    xpolar(2) = b*sea
+    xpolar(3) = 0.0_bp
+
+    IF (PRESENT(polar_coord)) THEN
+       polar_coord(1:2)=xpolar(1:2)
+       polar_coord(3)=-mm*kep_elements(1)**2*sea/r
+       polar_coord(4)=mm*kep_elements(1)*b*cea/r
+    END IF
+
+    ! NOTE: THE USE OF ARRAY ELEMENTS CAN BE MISLEADING,
+    ! partials wrt M should be the 6th?
+    ! Partials for polar coordinates: a, e, M (others -> 0.0)
+    ! Position: 
+    partials(1,1) = cea-kep_elements(2)
+    partials(1,2) = -(kep_elements(1)*sea)**2/r - &
+         kep_elements(1)
+    partials(1,3) = -sea*kep_elements(1)**2/r
+
+    partials(2,1) = b*sea/kep_elements(1)
+    partials(2,2) = sea*(cea-kep_elements(2)) * &
+         kep_elements(1)**3/(b*r)
+    partials(2,3) = kep_elements(1)*b*cea/r
+
+    ! Velocity:
+    !partials(3,1) = 0.5_bp*mm*kep_elements(1) * &
+    !     xpolar(2)/(r*b) + 1.5_bp*(ma-this%ma)*mm*kep_elements(1)**2*xpolar(1)/r**3
+    partials(3,1) = 0.5_bp*mm*kep_elements(1) * &
+         xpolar(2)/(r*b)
+    partials(3,2) = -mm*kep_elements(1)**2*xpolar(2) * &
+         ((kep_elements(1)+r)*xpolar(1) + &
+         r*kep_elements(1)*kep_elements(2))/(b*r**3)
+    partials(3,3) = -mm*kep_elements(1)**3*xpolar(1)/r**3
+
+    partials(4,1) = -0.5_bp * mm * b * &
+         (xpolar(1)+kep_elements(1)*kep_elements(2)) / &
+         (kep_elements(1)*r) 
+    !    partials(4,1) = -0.5_bp * mm * b * &
+    !         (xpolar(1)+kep_elements(1)*kep_elements(2)) / &
+    !         (kep_elements(1)*r) + 1.5_bp*(ma-this%ma)*mm*kep_elements(1)**2*xpolar(2)/r**3
+    partials(4,2) = mm * kep_elements(1)**2 * b * &
+         (xpolar(1) * (xpolar(1) + kep_elements(1) * &
+         kep_elements(2)) / kep_elements(1)- &
+         r**2*(kep_elements(1)-r+xpolar(2)**2/r)/b**2)/r**3
+    partials(4,3) = -mm * kep_elements(1)**3 * xpolar(2) / &
+         r**3
+
+  END SUBROUTINE partialsPolarCoordWrtKeplerian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of spherical coordinates wrt
+  !! Cartesian orbital elements. The partial derivatives are obtained
+  !! indirectly by utilizing partial derivatives of Keplerian elements
+  !! in the process.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dr/dx      dr/dy      dr/dz      dr/ddx      dr/ddy      dr/ddz
+  !!
+  !!   dalpha/dx  dalpha/dy  dalpha/dz  dalpha/ddx  dalpha/ddy  dalpha/ddz
+  !!
+  !!   ddelta/dx  ddelta/dy  ddelta/dz  ddelta/ddx  ddelta/ddy  ddelta/ddz
+  !!
+  !!      ddr/dx     ddr/dy     ddr/dz     ddr/ddx     ddr/ddy     ddr/ddz
+  !!
+  !!  ddalpha/dx ddalpha/dy ddalpha/dz ddalpha/ddx ddalpha/ddy ddalpha/ddz
+  !!
+  !!  dddelta/dx dddelta/dy dddelta/dz dddelta/ddx dddelta/ddy dddelta/ddz
+  !!
+  SUBROUTINE partialsSCoordWrtCartesian_i(this, observer, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: observer
+    REAL(bp), DIMENSION(6,6), INTENT(out)   :: partials
+
+    REAL(bp), DIMENSION(6,6) :: scoord_kep, kep_car
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtCartesian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtCartesian", &
+            "Observer has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL partialsSCoordWrtKeplerian(this, observer, scoord_kep)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtCartesian", &
+            "TRACE BACK (5).", 1)
+       RETURN
+    END IF
+
+    ! Partials between Keplerian and cometary elements
+    CALL partialsKeplerianWrtCartesian(this, kep_car, this%frame)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtCartesian", &
+            "TRACE BACK (10).", 1)
+       RETURN
+    END IF
+    partials = MATMUL(scoord_kep,kep_car)
+
+  END SUBROUTINE partialsSCoordWrtCartesian_i
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of spherical coordinates wrt
+  !! Cartesian orbital elements. Note that the origin and frame for
+  !! both coordinate systems must coincide.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dr/dx      dr/dy      dr/dz      dr/ddx      dr/ddy      dr/ddz
+  !!
+  !!   dalpha/dx  dalpha/dy  dalpha/dz  dalpha/ddx  dalpha/ddy  dalpha/ddz
+  !!
+  !!   ddelta/dx  ddelta/dy  ddelta/dz  ddelta/ddx  ddelta/ddy  ddelta/ddz
+  !!
+  !!      ddr/dx     ddr/dy     ddr/dz     ddr/ddx     ddr/ddy     ddr/ddz
+  !!
+  !!  ddalpha/dx ddalpha/dy ddalpha/dz ddalpha/ddx ddalpha/ddy ddalpha/ddz
+  !!
+  !!  dddelta/dx dddelta/dy dddelta/dz dddelta/ddx dddelta/ddy dddelta/ddz
+  !!
+  SUBROUTINE partialsSCoordWrtCartesian_d(this, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)              :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out) :: partials
+
+    REAL(bp), DIMENSION(3) :: pos, vel
+    REAL(bp) :: x2, y2, z2, xy, xy2, x2y2, x2y2z2, inv_x2y2, &
+         inv_sqrt_x2y2, inv_x2y2z2, inv_sqrt_x2y2z2, xdxydy, &
+         sum3x23y2z2
+
+    partials = 0.0_bp
+
+    ! Common terms.
+    pos = getPosition(this)
+    vel = getVelocity(this)
+    x2 = pos(1)**2.0_bp
+    y2 = pos(2)**2.0_bp
+    z2 = pos(3)**2.0_bp
+    xy = SUM(pos(1:2))
+    xy2 = xy**2.0_bp
+    x2y2 = x2 + y2
+    inv_x2y2 = 1.0_bp/x2y2
+    inv_sqrt_x2y2 = SQRT(inv_x2y2)
+    x2y2z2 = x2y2 + z2    
+    inv_x2y2z2 = 1.0_bp/x2y2z2
+    inv_sqrt_x2y2z2 = SQRT(inv_x2y2z2)
+    xdxydy = pos(1)*vel(1) + pos(2)*vel(2)
+    sum3x23y2z2 = 3.0_bp*x2 + 3.0_bp*y2 + z2
+
+    ! First row: r
+    partials(1,1) = pos(1)*inv_sqrt_x2y2z2
+    partials(1,2) = pos(2)*inv_sqrt_x2y2z2
+    partials(1,3) = pos(3)*inv_sqrt_x2y2z2
+
+    ! Second row: ra
+    partials(2,1) = -pos(2)*inv_x2y2
+    partials(2,2) = pos(1)*inv_x2y2
+
+    ! Third row: dec
+    partials(3,1) = -pos(1)*pos(3)*inv_sqrt_x2y2*inv_x2y2z2
+    partials(3,2) = -pos(2)*pos(3)*inv_sqrt_x2y2*inv_x2y2z2
+    partials(3,3) = inv_x2y2z2/inv_sqrt_x2y2
+
+    ! Fourth row: dr/dt
+    partials(4,1) = (vel(1)*(y2 + z2) - &
+         pos(1)*(pos(2)*vel(2) + pos(3)*vel(3))) * inv_x2y2z2
+    partials(4,2) = (vel(2)*(x2 + z2) - &
+         pos(2)*(pos(1)*vel(1) + pos(3)*vel(3))) * inv_x2y2z2
+    partials(4,3) = (vel(3)*x2y2 - pos(3)*xdxydy) * inv_x2y2z2
+    partials(4,4) = pos(1)*inv_sqrt_x2y2z2
+    partials(4,5) = pos(2)*inv_sqrt_x2y2z2
+    partials(4,6) = pos(3)*inv_sqrt_x2y2z2
+
+    ! Fifth row: dra/dt
+    partials(5,1) = (vel(1)*pos(2)*(2.0_bp*pos(1)+pos(2)) - &
+         x2*vel(2)) / (x2*xy2)
+    partials(5,2) = -(vel(1) + vel(2)) / xy2
+    partials(5,4) = -pos(2) / (pos(1)*xy)
+    partials(5,5) = 1.0_bp / xy
+
+    ! Sixth row: ddec/dt
+    partials(6,1) = ((2.0_bp*vel(3)*pos(1) - pos(3)*vel(1))*x2y2z2 * &
+         x2y2 - pos(1)*sum3x23y2z2*(vel(3)*x2y2 - pos(3)*xdxydy)) * &
+         inv_x2y2z2**2.0_bp * inv_sqrt_x2y2**3.0_bp
+    partials(6,2) = ((2.0_bp*vel(3)*pos(2) - pos(3)*vel(2))*x2y2z2 * &
+         x2y2 - pos(2)*sum3x23y2z2*(vel(3)*x2y2 - pos(3)*xdxydy)) * &
+         inv_x2y2z2**2.0_bp * inv_sqrt_x2y2**3.0_bp
+    partials(6,3) = (-xdxydy*(x2y2-z2) - 2.0_bp*pos(3)*vel(3)*x2y2)* &
+         inv_x2y2z2**2.0_bp*inv_sqrt_x2y2
+    partials(6,4) = -pos(1)*pos(3)*inv_x2y2z2*inv_sqrt_x2y2
+    partials(6,5) = -pos(2)*pos(3)*inv_x2y2z2*inv_sqrt_x2y2
+    partials(6,6) = inv_x2y2z2 * SQRT(x2y2)
+
+  END SUBROUTINE partialsSCoordWrtCartesian_d
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of spherical coordinates wrt
+  !! cometary orbital elements.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dr/dq      dr/de      dr/di      dr/dOmega      dr/domega      dr/dt
+  !!
+  !!   dalpha/dq  dalpha/de  dalpha/di  dalpha/dOmega  dalpha/domega  dalpha/dt
+  !!
+  !!   ddelta/dq  ddelta/de  ddelta/di  ddelta/dOmega  ddelta/domega  ddelta/dt
+  !!
+  !!      ddr/dq     ddr/de     ddr/di     ddr/dOmega     ddr/domega     ddr/dt
+  !!
+  !!  ddalpha/dq ddalpha/de ddalpha/di ddalpha/dOmega ddalpha/domega ddalpha/dt
+  !!
+  !!  dddelta/dq dddelta/de dddelta/di dddelta/dOmega dddelta/domega dddelta/dt
+  !!
+  SUBROUTINE partialsSCoordWrtCometary(this, observer, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: observer
+    REAL(bp), DIMENSION(6,6), INTENT(out)   :: partials
+
+    REAL(bp), DIMENSION(6,6) :: scoord_kep, kep_com
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtCometary", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtCometary", &
+            "Observer has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL partialsSCoordWrtKeplerian(this, observer, scoord_kep)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtCometary", &
+            "TRACE BACK (5).", 1)
+       RETURN
+    END IF
+
+    ! Partials between Keplerian and cometary elements
+    CALL partialsKeplerianWrtCometary(this, kep_com)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtCometary", &
+            "TRACE BACK (10).", 1)
+       RETURN
+    END IF
+    partials = MATMUL(scoord_kep,kep_com)
+
+  END SUBROUTINE partialsSCoordWrtCometary
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the partial derivatives of spherical coordinates wrt
+  !! Keplerian orbital elements.
+  !!
+  !! partials-matrix:
+  !!
+  !!       dr/da      dr/de      dr/di      dr/dOmega      dr/domega      dr/dM
+  !!
+  !!   dalpha/da  dalpha/de  dalpha/di  dalpha/dOmega  dalpha/domega  dalpha/dM
+  !!
+  !!   ddelta/da  ddelta/de  ddelta/di  ddelta/dOmega  ddelta/domega  ddelta/dM
+  !!
+  !!      ddr/da     ddr/de     ddr/di     ddr/dOmega     ddr/domega     ddr/dM
+  !!
+  !!  ddalpha/da ddalpha/de ddalpha/di ddalpha/dOmega ddalpha/domega ddalpha/dM
+  !!
+  !!  dddelta/da dddelta/de dddelta/di dddelta/dOmega dddelta/domega dddelta/dM
+  !!
+  SUBROUTINE partialsSCoordWrtKeplerian(this, observer, partials)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in)                :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: observer
+    REAL(bp), DIMENSION(6,6), INTENT(out)   :: partials
+
+    CHARACTER(len=FRAME_LEN) :: frame
+    REAL(bp), DIMENSION(6,6) :: pcar_equ
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp), DIMENSION(3) :: xequ
+    REAL(bp) :: tmp1, tmp2, tmp3, tmp4, tmp5
+    INTEGER :: i
+
+    partials = 0.0_bp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtKeplerian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtKeplerian", &
+            "Observer has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    frame = getFrame(observer)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / partialsSCoordWrtKeplerian", &
+            "TRACE BACK (30).", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this, "cartesian", frame)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtKeplerian", &
+            "TRACE BACK (20).", 1)
+       RETURN
+    END IF
+    xequ = elements(1:3)
+
+    ! Partials for Cartesian equatorial coordinates
+    CALL partialsCartesianWrtKeplerian(this, pcar_equ, frame=frame)
+    IF (error) THEN
+       CALL errorMessage("Orbit / partialsSCoordWrtKeplerian", &
+            "TRACE BACK (25).", 1)
+       RETURN
+    END IF
+
+    ! Partials for spherical equatorial coordinates
+    ! Topocentric coordinates:
+    xequ = xequ - getPosition(observer)
+
+    tmp1 = SQRT(DOT_PRODUCT(xequ,xequ))
+    tmp2 = SQRT(xequ(1)**2+xequ(2)**2)/tmp1
+    tmp3 = xequ(3)/tmp1
+    tmp4 = xequ(1)/(tmp1*tmp2)
+    tmp5 = xequ(2)/(tmp1*tmp2)
+
+    DO i=1,6 ! i is element
+       ! rho
+       partials(1,i) = tmp2*tmp4*pcar_equ(1,i) + &
+            tmp2*tmp5*pcar_equ(2,i) + tmp3*pcar_equ(3,i)
+       ! RA
+       partials(2,i) = (tmp4*pcar_equ(2,i) - &
+            tmp5*pcar_equ(1,i))/(tmp1*tmp2)
+       ! Dec
+       partials(3,i) = (tmp2*pcar_equ(3,i) - &
+            tmp3*tmp4*pcar_equ(1,i) - tmp3*tmp5*pcar_equ(2,i))/tmp1
+    END DO
+
+    ! Note that x/dx and dx/x are missing! the following numbers are
+    ! there to allow, e.g., computation of the determinant of the
+    ! matrix:
+    partials(4,4)   = 1.0_bp
+    partials(5,5)   = 1.0_bp
+    partials(6,6)   = 1.0_bp
+
+  END SUBROUTINE partialsSCoordWrtKeplerian
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Propagates the Cartesian or Keplerian orbital elements to the
+  !! given epoch using either the 2-body or the n-body model. The
+  !! dynamical model as well as other propagation parameters can be
+  !! set with the _setParameters_-routine. Optionally,
+  !! the Jacobian matrix of final coordinates wrt. initial coordinates
+  !! is calculated. Doesn"t alter the original orbit, if an error occurs.
+  !!
+  !! *2-body*propagation*:
+  !! 
+  !! In Keplerian elements, trivially computes a new mean anomaly.
+  !!
+  !! In Cartesian elements, transforms position and velocity at one
+  !! epoch into those at another epoch by using f- and g-functions.
+  !!
+  !! *N-body*propagation*:
+  !!
+  !! If necessary, transforms input orbit to equatorial Cartesian
+  !! (assumed heliocentric).
+  !!
+  !! Transforms position and velocity at one epoch into those at
+  !! another epoch, using the Bulirsch-Stoer method, full force
+  !! integration including nine planets and the Moon.
+  !!
+  !! Transforms output to match the element type of the input orbit.
+  !!
+  !! *Jacobian*:
+  !! 
+  !! Optionally, a Jacobian matrix (partial derivatives between final
+  !! orbital elements and initial orbital elements) is
+  !! computed. Depending on the elements used, the layout of the
+  !! Jacobian matrix is either (Keplerian elements)
+  !!
+  !!  da1/da0     da1/de0     da1/di0     da1/dOmega0     da1/domega0     da1/dM0
+  !!
+  !!  de1/da0     de1/de0     de1/di0     de1/dOmega0     de1/domega0     de1/dM0
+  !!
+  !!  di1/da0     di1/de0     di1/di0     di1/dOmega0     di1/domega0     di1/dM0
+  !!
+  !!  dOmega1/da0 dOmega1/de0 dOmega1/di0 dOmega1/dOmega0 dOmega1/domega0 dOmega1/dM0
+  !!
+  !!  domega1/da0 domega1/de0 domega1/di0 domega1/dOmega0 domega1/domega0 domega1/dM0
+  !!
+  !!  dM1/da0     dM1/de0     dM1/di0     dM1/dOmega0     dM1/domega0     dM1/dM0
+  !!
+  !!
+  !! or (Cartesian elements)
+  !!  
+  !!  dx1/dx0     dx1/dy0     dx1/dz0     dx1/ddx0        dx1/ddy0        dx1/ddz0
+  !!
+  !!  dy1/dx0     dy1/dy0     dy1/dz0     dy1/ddx0        dy1/ddy0        dy1/ddz0
+  !!
+  !!  dz1/dx0     dz1/dy0     dz1/dz0     dz1/ddx0        dz1/ddy0        dz1/ddz0
+  !!
+  !!  ddx1/dx0    ddx1/dy0    ddx1/dz0    ddx1/ddx0       ddx1/ddy0       ddx1/ddz0
+  !!
+  !!  ddy1/dx0    ddy1/dy0    ddy1/dz0    ddy1/ddx0       ddy1/ddy0       ddy1/ddz0
+  !!
+  !!  ddz1/dx0    ddz1/dy0    ddz1/dz0    ddz1/ddx0       ddz1/ddy0       ddz1/ddz0
+  !!
+  !!
+  !! Returns error.
+  !!
+  !!
+  SUBROUTINE propagate_Orb_single(this, t, jacobian, encounters)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)                     :: this
+    TYPE (Time), INTENT(in)                         :: t
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: jacobian
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL   :: encounters
+
+    TYPE (Orbit), DIMENSION(1)                      :: this_
+    REAL(bp), DIMENSION(:,:,:), POINTER             :: jacobian_
+    INTEGER :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / propagate (single)", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    this_(1) = copy(this)
+    IF (PRESENT(jacobian)) THEN
+       IF (PRESENT(encounters)) THEN
+          CALL propagate(this_, t, jacobian=jacobian_, encounters=encounters)
+       ELSE
+          CALL propagate(this_, t, jacobian=jacobian_)
+       END IF
+       IF (.NOT.error) THEN
+          jacobian = jacobian_(1,:,:)
+          DEALLOCATE(jacobian_, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (single)", &
+                  "Could not deallocate memory.", 1)
+             CALL NULLIFY(this_(1))
+             RETURN
+          END IF
+       END IF
+    ELSE
+       IF (PRESENT(encounters)) THEN
+          CALL propagate(this_, t, encounters=encounters)
+       ELSE
+          CALL propagate(this_, t)
+       END IF
+    END IF
+    IF (error) THEN
+       CALL errorMessage("Orbit / propagate (single)", &
+            "TRACE BACK (single orbit)", 1)
+       IF (PRESENT(jacobian)) THEN
+          jacobian = identity_matrix(6)
+          DEALLOCATE(jacobian_, stat=err)
+       END IF
+       CALL NULLIFY(this_(1))
+       RETURN
+    END IF
+    CALL NULLIFY(this)
+    this = copy(this_(1))
+    CALL NULLIFY(this_(1))
+
+  END SUBROUTINE propagate_Orb_single
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Propagates the Cartesian or Keplerian orbital elements to the
+  !! given epoch using either the 2-body or the n-body model. The
+  !! dynamical model as well as other propagation parameters can be
+  !! set with the _setParameters_-routine. Optionally,
+  !! the Jacobian matrix of final coordinates wrt. initial coordinates
+  !! is calculated. Doesn"t alter the original orbit, if an error occurs.
+  !!
+  !! *2-body*propagation*:
+  !! 
+  !! In Keplerian elements, trivially computes a new mean anomaly.
+  !!
+  !! In Cartesian elements, transforms position and velocity at one
+  !! epoch into those at another epoch by using f- and g-functions.
+  !!
+  !! *N-body*propagation*:
+  !!
+  !! If necessary, transforms input orbit to equatorial Cartesian
+  !! (assumed heliocentric).
+  !!
+  !! Transforms position and velocity at one epoch into those at
+  !! another epoch, using the Bulirsch-Stoer method, full force
+  !! integration including nine planets and the Moon.
+  !!
+  !! Transforms output to match the element type of the input orbit.
+  !!
+  !! *Jacobian*:
+  !! 
+  !! Optionally, a Jacobian matrix (partial derivatives between final
+  !! orbital elements and initial orbital elements) is computed for
+  !! each orbit. Depending on the elements used, the layout of the
+  !! Jacobian matrix is either (Keplerian elements)
+  !!
+  !!  da1/da0     da1/de0     da1/di0     da1/dOmega0     da1/domega0     da1/dM0
+  !!
+  !!  de1/da0     de1/de0     de1/di0     de1/dOmega0     de1/domega0     de1/dM0
+  !!
+  !!  di1/da0     di1/de0     di1/di0     di1/dOmega0     di1/domega0     di1/dM0
+  !!
+  !!  dOmega1/da0 dOmega1/de0 dOmega1/di0 dOmega1/dOmega0 dOmega1/domega0 dOmega1/dM0
+  !!
+  !!  domega1/da0 domega1/de0 domega1/di0 domega1/dOmega0 domega1/domega0 domega1/dM0
+  !!
+  !!  dM1/da0     dM1/de0     dM1/di0     dM1/dOmega0     dM1/domega0     dM1/dM0
+  !!
+  !!
+  !! or (Cartesian elements)
+  !!  
+  !!  dx1/dx0     dx1/dy0     dx1/dz0     dx1/ddx0        dx1/ddy0        dx1/ddz0
+  !!
+  !!  dy1/dx0     dy1/dy0     dy1/dz0     dy1/ddx0        dy1/ddy0        dy1/ddz0
+  !!
+  !!  dz1/dx0     dz1/dy0     dz1/dz0     dz1/ddx0        dz1/ddy0        dz1/ddz0
+  !!
+  !!  ddx1/dx0    ddx1/dy0    ddx1/dz0    ddx1/ddx0       ddx1/ddy0       ddx1/ddz0
+  !!
+  !!  ddy1/dx0    ddy1/dy0    ddy1/dz0    ddy1/ddx0       ddy1/ddy0       ddy1/ddz0
+  !!
+  !!  ddz1/dx0    ddz1/dy0    ddz1/dz0    ddz1/ddx0       ddz1/ddy0       ddz1/ddz0
+  !!
+  !!
+  !! Returns error.
+  !!
+  !!
+  SUBROUTINE propagate_Orb_multiple(this_arr, t, jacobian, encounters)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:), INTENT(inout)     :: this_arr
+    TYPE (Time), INTENT(in)                       :: t
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: jacobian
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: encounters
+
+    TYPE (Time) :: t_
+    TYPE (Orbit) :: this_
+    CHARACTER(len=ELEMENT_TYPE_LEN), DIMENSION(:), ALLOCATABLE :: &
+         element_type_arr
+    CHARACTER(len=FRAME_LEN) , DIMENSION(:), ALLOCATABLE :: frame_arr
+    CHARACTER(len=DYN_MODEL_LEN) :: dyn_model
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE :: partials0, jacobian_
+    REAL(bp), DIMENSION(:,:), POINTER :: elm_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: masses
+    REAL(bp), DIMENSION(6,6) :: partials1
+    REAL(bp), DIMENSION(0:3) :: stumpff_cs, ffs
+    REAL(bp), DIMENSION(3) :: pos, vel
+    REAL(bp) :: mjd_tt, mjd_tt0, dt, r0, u, alpha, s, f, g, df, &
+         dg, mean_motion, step, mu_, p
+    INTEGER :: i, j, err, nthis, central_body, naddit, nmassive
+    LOGICAL :: multiple_t0
+
+    nthis = SIZE(this_arr,dim=1)
+    IF (nthis == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / propagate (multiple)", &
+            "Orbit array is of zero length.", 1)
+       RETURN
+    END IF
+    DO i=1,nthis
+       IF (.NOT. this_arr(i)%is_initialized) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "All objects have not yet been initialized.", 1)
+          WRITE(stderr,*) i
+          RETURN
+       END IF
+    END DO
+
+    multiple_t0 = .FALSE.
+    DO i=1,nthis
+       IF (.NOT.equal(this_arr(1)%t,this_arr(i)%t)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)",&
+               "All orbits do not have an equal starting epoch.", 1)          
+          RETURN
+          multiple_t0 = .TRUE.
+       END IF
+       IF (error) THEN
+          CALL errorMessage("Orbit / propagate (multiple)",&
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    END DO
+
+    IF (PRESENT(jacobian)) THEN
+       ALLOCATE(jacobian(nthis,6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+    END IF
+
+    IF (PRESENT(encounters)) THEN
+       ALLOCATE(encounters(nthis,11,4), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "Could not allocate memory (10).", 1)
+          RETURN
+       END IF
+    END IF
+
+    t_ = copy(t)
+    IF (equal(this_arr(1)%t,t_)) THEN
+       IF (PRESENT(jacobian)) THEN
+          DO i=1,nthis
+             jacobian(i,:,:) = identity_matrix(6)
+          END DO
+       END IF
+       CALL NULLIFY(t_)
+       RETURN
+    END IF
+
+    dyn_model = this_arr(1)%dyn_model_prm
+    IF (error) THEN
+       CALL errorMessage("Orbit / propagate (multiple)",&
+            "TRACE BACK (10)", 1)
+       IF (PRESENT(jacobian)) THEN
+          DEALLOCATE(jacobian, stat=err)
+       END IF
+       RETURN
+    END IF
+    DO i=2,nthis
+       IF (dyn_model /= this_arr(i)%dyn_model_prm) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "All orbits do not share the same propagation scheme.", 1)
+          IF (PRESENT(jacobian)) THEN
+             DEALLOCATE(jacobian, stat=err)
+          END IF
+          RETURN
+       END IF
+    END DO
+
+    mjd_tt0 = getMJD(this_arr(1)%t, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / propagate (multiple)",&
+            "TRACE BACK (15)", 1)
+       IF (PRESENT(jacobian)) THEN
+          DEALLOCATE(jacobian, stat=err)
+       END IF
+       RETURN
+    END IF
+    mjd_tt = getMJD(t_, "TT")
+    IF (error) THEN
+       CALL errorMessage("Orbit / propagate (multiple)",&
+            "TRACE BACK (20)", 1)
+       IF (PRESENT(jacobian)) THEN
+          DEALLOCATE(jacobian, stat=err)
+       END IF
+       RETURN
+    END IF
+
+    central_body = this_arr(1)%central_body
+    DO i=1,nthis
+       IF (central_body /= this_arr(i)%central_body) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "All orbits do not share the same central body.", 1)
+          IF (PRESENT(jacobian)) THEN
+             DEALLOCATE(jacobian, stat=err)
+          END IF
+          RETURN
+       END IF
+    END DO
+    ! Define mu parameter
+    mu_ = planetary_mu(central_body)
+
+    ! Select dynamical model; either 2-body or n-body: 
+    SELECT CASE (TRIM(dyn_model))
+
+    CASE ("2-body")
+
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,A)") &
+               "Orbit / propagate_Orb_multiple:", &
+               "Preparing for 2-body propagation..."
+       END IF
+
+       dt = mjd_tt - mjd_tt0
+       IF (PRESENT(jacobian) .AND. ALL(this_arr(1)%finite_diff_prm > 0.0_bp)) THEN
+          ALLOCATE(elm_arr(2,6), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Could not allocate memory (15).", 1)
+             DEALLOCATE(jacobian, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             RETURN
+          END IF
+       END IF
+
+       DO i=1,nthis
+
+          SELECT CASE (TRIM(this_arr(i)%element_type))
+
+          CASE ("cartesian")
+
+             IF (info_verb >= 4) THEN
+                WRITE(stdout,"(2X,A,1X,A,I0,A)") &
+                     "Orbit / propagate_Orb_multiple:", &
+                     "Carrying out 2-body propagation for orbit #", i, "..."
+             END IF
+             r0      = SQRT(DOT_PRODUCT(this_arr(i)%elements(1:3),this_arr(i)%elements(1:3))) ! r_0
+             u       = DOT_PRODUCT(this_arr(i)%elements(1:3),this_arr(i)%elements(4:6)) 
+             alpha   = 2.0_bp*mu_/r0 - DOT_PRODUCT(this_arr(i)%elements(4:6),this_arr(i)%elements(4:6)) ! 
+             CALL solveKeplerEquation(r0, u, alpha, dt, stumpff_cs, ffs, s, &
+                  this_arr(i)%central_body)
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "2-body propagation using Stumpff-functions was unsuccessful.", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(elm_arr, stat=err)
+                RETURN
+             END IF
+             f   = 1.0_bp - (mu_/r0) * stumpff_cs(2)
+             g   = dt - mu_*stumpff_cs(3)
+             df  = -mu_/(ffs(1)*r0) * stumpff_cs(1)
+             dg  = 1.0_bp - (mu_/ffs(1)) * stumpff_cs(2)
+             pos(1:3) = f * this_arr(i)%elements(1:3) +  g * this_arr(i)%elements(4:6)
+             vel(1:3) = df * this_arr(i)%elements(1:3) + dg * this_arr(i)%elements(4:6)
+             IF (PRESENT(jacobian)) THEN
+                CALL GaussfgJacobian(this_arr(i), r0, u, alpha, stumpff_cs, s, &
+                     f, g, df, dg, pos, ffs(1), jacobian(i,:,:))
+                IF (error) THEN
+                   CALL errorMessage("Orbit / propagate (multiple)",&
+                        "TRACE BACK (25)", 1)
+                   DEALLOCATE(jacobian, stat=err)
+                   DEALLOCATE(elm_arr, stat=err)
+                   RETURN
+                END IF
+             END IF
+             this_arr(i)%elements(1:3) = pos(1:3)
+             this_arr(i)%elements(4:6) = vel(1:3)
+             IF (info_verb >= 4) THEN
+                WRITE(stdout,"(2X,A,1X,A,I0,A)") &
+                     "Orbit / propagate_Orb_multiple:", &
+                     "2-body propagation carried out for orbit #", i, "."
+             END IF
+
+
+          CASE ("cometary")
+
+             IF (PRESENT(jacobian)) THEN
+                error = .TRUE.
+                CALL errorMessage("Orbit / propagate (multiple)",&
+                     "Jacobians not available for cometary elements.", 1)
+                RETURN
+             END IF
+             p = two_pi * SQRT((this_arr(i)%elements(1) / &
+                  (1.0_bp-this_arr(i)%elements(2)))**3.0_bp / &
+                  planetary_mu(this_arr(i)%central_body))
+             ! Select time of perihelion closest to epoch:
+             IF (ABS(MOD(dt,p)) <= 0.5*p) THEN
+                this_arr(i)%elements(6) = this_arr(i)%elements(6) + INT(dt/p)*p
+             ELSE
+                this_arr(i)%elements(6) = this_arr(i)%elements(6) + INT(dt/p)*p + SIGN(p,dt)
+             END IF
+
+          CASE ("keplerian")
+
+             IF (PRESENT(jacobian) .AND. &
+                  .NOT.ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                jacobian(i,:,:) = identity_matrix(6)
+                mean_motion = SQRT(mu_/this_arr(i)%elements(1)**3.0_bp)
+                ! The only nonzero element (apart from the diagonal) is dM/da:
+                jacobian(i,6,1) = -1.5_bp * mean_motion*dt/this_arr(i)%elements(1)
+             ELSE IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                DO j=1,6
+                   elm_arr(1,:) = this_arr(i)%elements
+                   elm_arr(2,:) = this_arr(i)%elements
+                   elm_arr(1,j) = elm_arr(1,j) + this_arr(i)%finite_diff_prm(j)
+                   elm_arr(2,j) = elm_arr(2,j) - this_arr(i)%finite_diff_prm(j)
+                   mean_motion = SQRT(mu_/elm_arr(1,1)**3.0_bp)
+                   elm_arr(1,6) = MODULO(elm_arr(1,6) + mean_motion*dt, two_pi)
+                   mean_motion = SQRT(mu_/elm_arr(2,1)**3.0_bp)
+                   elm_arr(2,6) = MODULO(elm_arr(2,6) + mean_motion*dt, two_pi)
+                   jacobian(i,:,j) = (elm_arr(1,:) - elm_arr(2,:)) / &
+                        (2.0_bp*this_arr(i)%finite_diff_prm(j))
+                END DO
+             END IF
+             mean_motion = SQRT(mu_/this_arr(i)%elements(1)**3.0_bp)
+             this_arr(i)%elements(6) = MODULO(this_arr(i)%elements(6) + mean_motion*dt, two_pi)
+
+          CASE default
+
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Element type cannot be propagated: " // &
+                  TRIM(this_arr(i)%element_type), 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(elm_arr, stat=err)
+             RETURN
+
+          END SELECT
+
+          this_arr(i)%t = copy(t_)
+
+       END DO
+
+       IF (ASSOCIATED(elm_arr)) THEN
+          DEALLOCATE(elm_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Could not deallocate memory (5).", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             RETURN
+          END IF
+       END IF
+
+    CASE ("n-body")
+
+       ! Check for inconcistensies:
+       DO i=2,nthis
+          IF (ANY(this_arr(1)%perturbers_prm .NEQV. this_arr(i)%perturbers_prm)) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Different orbits require different perturbers.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             RETURN
+          END IF
+       END DO
+       integrator = this_arr(1)%integrator_prm
+       step = this_arr(1)%integration_step_prm
+       DO i=2,nthis
+          IF (integrator /= this_arr(i)%integrator_prm) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "All orbits do not share the same integrator option.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             RETURN
+          END IF
+          IF ((ALL(this_arr(1)%finite_diff_prm > 0.0_bp) .AND. &
+               .NOT.ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) .OR. &
+               (.NOT.ALL(this_arr(1)%finite_diff_prm > 0.0_bp) .AND. &
+               ALL(this_arr(i)%finite_diff_prm > 0.0_bp))) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "All orbits do not share the same jacobian approach.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             RETURN
+          END IF
+          IF (ABS(step-this_arr(i)%integration_step_prm) > &
+               100.0_bp*EPSILON(step)) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "All orbits do not share the same integration step.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             RETURN
+          END IF
+       END DO
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,1X,I0)") "Number of standard perturbers:", &
+               COUNT(this_arr(1)%perturbers_prm)
+       END IF
+
+       IF (ASSOCIATED(this_arr(1)%additional_perturbers)) THEN
+          naddit = SIZE(this_arr(1)%additional_perturbers,dim=1)
+       ELSE
+          naddit = 0
+       END IF
+
+       ALLOCATE(elm_arr(6,nthis+naddit), element_type_arr(nthis), frame_arr(nthis), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "Could not allocate memory (20).", 1)
+          IF (PRESENT(jacobian)) THEN
+             DEALLOCATE(jacobian, stat=err)
+          END IF
+          DEALLOCATE(element_type_arr, stat=err)
+          DEALLOCATE(frame_arr, stat=err)
+          DEALLOCATE(elm_arr, stat=err)
+          RETURN
+       END IF
+       DO i=1,nthis
+          elm_arr(1:6,i) = this_arr(i)%elements
+       END DO
+       DO i=1,naddit
+          elm_arr(1:6,nthis+i) = this_arr(1)%additional_perturbers(i,1:6)
+       END DO
+       IF (PRESENT(jacobian) .AND. ALL(this_arr(1)%finite_diff_prm > 0.0_bp)) THEN
+          elm_arr => reallocate(elm_arr, 6, 13*(nthis+naddit))
+          ! Initialize for finite difference technique:
+          DO i=1,nthis+naddit
+             DO j=1,6
+                ! Change one element at a time by adding and subtracting by a finite amount
+                elm_arr(:,nthis+naddit+(i-1)*12+j) = elm_arr(:,i)
+                elm_arr(:,nthis+naddit+(i-1)*12+j+6) = elm_arr(:,i)
+                elm_arr(j,nthis+naddit+(i-1)*12+j) = elm_arr(j,nthis+naddit+(i-1)*12+j) + &
+                     this_arr(i)%finite_diff_prm(j)
+                elm_arr(j,nthis+naddit+(i-1)*12+j+6) = elm_arr(j,nthis+naddit+(i-1)*12+j+6) - &
+                     this_arr(i)%finite_diff_prm(j)
+             END DO
+          END DO
+       ELSE IF (PRESENT(jacobian) .AND. .NOT.ALL(this_arr(1)%finite_diff_prm > 0.0_bp)) THEN
+          ALLOCATE(jacobian_(6,6,nthis+naddit), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Could not allocate memory (25).", 1)
+             DEALLOCATE(jacobian, stat=err)
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             DEALLOCATE(jacobian_, stat=err)
+             RETURN
+          END IF
+       END IF
+
+       ! Make copies of original element types and frames, and make
+       ! sure equatorial Cartesian elements are used during integration:
+       DO i=1,nthis
+          element_type_arr(i) = "cartesian"
+          IF (this_arr(i)%element_type /= "cartesian") THEN
+             ! Non-Cartesian elements
+             element_type_arr(i) = this_arr(i)%element_type
+             this_ = copy(this_arr(i))
+             this_%elements = elm_arr(:,i)
+             elm_arr(:,i) = getElements(this_, "cartesian", frame="equatorial")
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "TRACE BACK (30)", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                RETURN
+             END IF
+             IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                DO j=1,12
+                   this_%elements = elm_arr(:,nthis+naddit+(i-1)*12+j)
+                   elm_arr(:,nthis+naddit+(i-1)*12+j) = getElements(this_, "cartesian", frame="equatorial")
+                   IF (error) THEN
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "TRACE BACK (35)", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      RETURN
+                   END IF
+                END DO
+             END IF
+             CALL NULLIFY(this_)
+             IF (PRESENT(jacobian) .AND. .NOT.ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                IF (.NOT.ALLOCATED(partials0)) THEN
+                   ALLOCATE(partials0(nthis+naddit,6,6), stat=err)
+                   IF (err /= 0) THEN
+                      error = .TRUE.
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "Could not allocate memory (30).", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      DEALLOCATE(partials0, stat=err)
+                      RETURN
+                   END IF
+                END IF
+                IF (this_arr(i)%element_type == "keplerian") THEN
+                   CALL partialsCartesianWrtKeplerian(this_arr(i), partials0(i,:,:), frame="equatorial")
+                ELSE IF (this_arr(i)%element_type == "cometary") THEN
+                   CALL partialsCartesianWrtCometary(this_arr(i), partials0(i,:,:), frame="equatorial")                   
+                END IF
+                IF (error) THEN
+                   CALL errorMessage("Orbit / propagate (multiple)", &
+                        "TRACE BACK (40)", 1)
+                   DEALLOCATE(jacobian, stat=err)
+                   DEALLOCATE(element_type_arr, stat=err)
+                   DEALLOCATE(frame_arr, stat=err)
+                   DEALLOCATE(elm_arr, stat=err)
+                   DEALLOCATE(jacobian_, stat=err)
+                   DEALLOCATE(partials0, stat=err)
+                   RETURN
+                END IF
+             END IF
+          ELSE
+             ! Cartesian elements
+             frame_arr(i) = this_arr(i)%frame
+             IF (this_arr(i)%frame /= "equatorial") THEN
+                ! Non-equatorial frame (here assumed to be ecliptic):
+                CALL rotateToEquatorial(elm_arr(1:6,i))
+                IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                   DO j=1,12
+                      CALL rotateToEquatorial(elm_arr(1:6,nthis+naddit+(i-1)*12+j))
+                   END DO
+                END IF
+             END IF
+          END IF
+       END DO
+
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,1X,I0)") "Number of additional perturbers:", naddit
+       END IF
+       ALLOCATE(masses(nthis+naddit), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)",&
+               "Could not allocate memory (35).", 1)          
+          RETURN
+       END IF
+       DO i=1,nthis
+          masses(i) = this_arr(i)%mass_prm
+       END DO
+       IF (naddit /= 0) THEN
+          masses(nthis+1:nthis+naddit) = this_arr(1)%additional_perturbers(1:naddit,8)
+       END IF
+
+       SELECT CASE (integrator)
+
+       CASE ("bulirsch-stoer")
+
+          ! Check whether the additional perturbers share the same epoch
+          ! with the orbits to be integrated and integrate them to the
+          ! correct epoch if required:
+          IF (ASSOCIATED(this_arr(1)%additional_perturbers) .AND. &
+               SIZE(this_arr(1)%additional_perturbers,dim=1) > 0) THEN
+             IF (naddit >= 2) THEN
+                DO i=2,naddit
+                   IF (ABS(this_arr(1)%additional_perturbers(i-1,7) - &
+                        this_arr(1)%additional_perturbers(i,7)) > &
+                        10.0*EPSILON(this_arr(1)%additional_perturbers(1,7))) THEN
+                      error = .TRUE.
+                      CALL errorMessage("Orbit / propagate (multiple)",&
+                           "Additional perturbers do not have a common epoch.", 1)          
+                      RETURN
+                   END IF
+                END DO
+             END IF
+             IF (ABS(mjd_tt0 - this_arr(1)%additional_perturbers(1,7)) > &
+                  10.0*EPSILON(this_arr(1)%additional_perturbers(1,7))) THEN
+                IF (info_verb >= 3) THEN
+                   WRITE(stdout,"(2X,2(A,1X,F15.7,1X),A)") &
+                        "Integrating additional perturbers from epoch", &
+                        this_arr(1)%additional_perturbers(1,7), &
+                        "to starting epoch", mjd_tt0, "."
+                   WRITE(stdout,"(2X,A)") &
+                        "Initial elements (cartesian equatorial), epoch, and mass:"
+                   DO i=1,naddit
+                      WRITE(stdout,"(2X,I0,7(1X,F17.9),1X,E10.4)") &
+                           i, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+i), &
+                           this_arr(1)%additional_perturbers(i,7:8)
+                   END DO
+                END IF
+                CALL bulirsch_full_jpl(this_arr(1)%additional_perturbers(1,7), &
+                     mjd_tt0, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+1:), &
+                     this_arr(1)%perturbers_prm, error, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, &
+                     masses=this_arr(1)%additional_perturbers(:,8), &
+                     info_verb=info_verb)
+             END IF
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(2X,A)") &
+                     "Orbital elements for additional perturbers (cartesian equatorial), " // &
+                     "their epoch, and mass at starting epoch:"
+                DO i=1,naddit
+                   WRITE(stdout,"(2X,I0,7(1X,F17.9),1X,E10.4)") &
+                        i, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+i), &
+                        mjd_tt0, this_arr(1)%additional_perturbers(i,8)
+                END DO
+             END IF
+          END IF
+
+          IF (PRESENT(jacobian) .AND. .NOT.ALL(this_arr(1)%finite_diff_prm > 0.0_bp)) THEN
+             ! Variational equations technique:
+             DO i=1,nthis+naddit
+                jacobian_(:,:,i) = identity_matrix(6)
+             END DO
+             IF (PRESENT(encounters)) THEN
+                CALL bulirsch_full_jpl(mjd_tt0, mjd_tt, elm_arr, &
+                     this_arr(1)%perturbers_prm, &
+                     error, step=this_arr(1)%integration_step_prm, &
+                     jacobian=jacobian_, ncenter=central_body, &
+                     encounters=encounters, masses=masses, &
+                     info_verb=info_verb)
+             ELSE
+                CALL bulirsch_full_jpl(mjd_tt0, mjd_tt, elm_arr, &
+                     this_arr(1)%perturbers_prm, &
+                     error, step=this_arr(1)%integration_step_prm, &
+                     jacobian=jacobian_, ncenter=central_body, &
+                     masses=masses, info_verb=info_verb)
+             END IF
+             DO i=1,nthis+naddit
+                jacobian(i,1:6,1:6) = jacobian_(1:6,1:6,i)
+             END DO
+          ELSE IF (.NOT.PRESENT(jacobian) .OR. &
+               (PRESENT(jacobian) .AND. ALL(this_arr(1)%finite_diff_prm > 0.0_bp))) THEN
+             ! No Jacobian requested or Jacobian requested through
+             ! finite differences technique:
+             IF (PRESENT(encounters)) THEN
+                CALL bulirsch_full_jpl(mjd_tt0, mjd_tt, elm_arr, &
+                     this_arr(1)%perturbers_prm, error, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, &
+                     encounters=encounters, &
+                     masses=masses, &
+                     info_verb=info_verb)
+             ELSE
+                CALL bulirsch_full_jpl(mjd_tt0, mjd_tt, elm_arr, &
+                     this_arr(1)%perturbers_prm, error, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, masses=masses, &
+                     info_verb=info_verb)
+             END IF
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Bulirsch-Stoer integration was unsuccessful.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             DEALLOCATE(jacobian_, stat=err)
+             DEALLOCATE(partials0, stat=err)
+             RETURN
+          END IF
+
+       CASE ("gauss-radau")
+
+          ! Check whether the additional perturbers share the same epoch
+          ! with the orbits to be integrated and integrate them to the
+          ! correct epoch if required:
+          IF (ALLOCATED(masses)) THEN
+             IF (naddit >= 2) THEN
+                DO i=2,naddit
+                   IF (ABS(this_arr(1)%additional_perturbers(i-1,7) - &
+                        this_arr(1)%additional_perturbers(i,7)) > &
+                        10.0*EPSILON(this_arr(1)%additional_perturbers(1,7))) THEN
+                      error = .TRUE.
+                      CALL errorMessage("Orbit / propagate (multiple)",&
+                           "Additional perturbers do not have a common epoch.", 1)          
+                      RETURN
+                   END IF
+                END DO
+             END IF
+             IF (ABS(mjd_tt0 - this_arr(1)%additional_perturbers(1,7)) > &
+                  10.0*EPSILON(this_arr(1)%additional_perturbers(1,7))) THEN
+                IF (info_verb >= 3) THEN
+                   WRITE(stdout,"(2X,2(A,1X,F15.7,1X),A)") &
+                        "Integrating additional perturbers from epoch", &
+                        this_arr(1)%additional_perturbers(1,7), &
+                        "to starting epoch", mjd_tt0, "."
+                   WRITE(stdout,"(2X,A)") &
+                        "Initial elements (cartesian equatorial), epoch, and mass:"
+                   DO i=1,naddit
+                      WRITE(stdout,"(2X,I0,7(1X,F17.9),1X,E10.4)") &
+                           i, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+i), &
+                           this_arr(1)%additional_perturbers(i,7:8)
+                   END DO
+                END IF
+                CALL gauss_radau_15_full_jpl( &
+                     this_arr(1)%additional_perturbers(1,7), &
+                     mjd_tt0, &
+                     elm_arr(:,SIZE(elm_arr,dim=2)-naddit+1:), 12, &
+                     2, this_arr(1)%perturbers_prm, error, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, &
+                     masses=masses)
+             END IF
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(2X,A)") &
+                     "Orbital elements for additional perturbers (cartesian equatorial), " // &
+                     "their epoch, and mass at starting epoch:"
+                DO i=1,naddit
+                   WRITE(stdout,"(2X,I0,7(1X,F17.9),1X,E10.4)") &
+                        i, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+i), &
+                        mjd_tt0, masses
+                END DO
+             END IF
+          END IF
+
+          IF (PRESENT(jacobian) .AND. .NOT.ALL(this_arr(1)%finite_diff_prm > 0.0_bp)) THEN
+             ! Jacobians through variational equations technique:
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)",&
+                  "Variational equations technique not available for Gauss-Radau.", 1)          
+             RETURN             
+             DO i=1,nthis+naddit
+                jacobian_(:,:,i) = identity_matrix(6)
+             END DO
+             IF (PRESENT(encounters)) THEN
+                CALL gauss_radau_15_full_jpl(mjd_tt0, mjd_tt, &
+                     elm_arr, 12, 2, this_arr(1)%perturbers_prm, &
+                     error, jacobian=jacobian_, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, encounters=encounters, &
+                     masses=masses)
+             ELSE
+                CALL gauss_radau_15_full_jpl(mjd_tt0, mjd_tt, &
+                     elm_arr, 12, 2, this_arr(1)%perturbers_prm, &
+                     error, jacobian=jacobian_, &
+                     step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, &
+                     masses=masses)
+             END IF
+             DO i=1,nthis+naddit
+                jacobian(i,1:6,1:6) = jacobian_(1:6,1:6,i)
+             END DO
+          ELSE IF (.NOT.PRESENT(jacobian) .OR. &
+               (PRESENT(jacobian) .AND. ALL(this_arr(1)%finite_diff_prm > 0.0_bp))) THEN
+             ! No Jacobian requested or Jacobian requested through
+             ! finite differences technique:
+             IF (PRESENT(encounters)) THEN
+                CALL gauss_radau_15_full_jpl(mjd_tt0, mjd_tt, &
+                     elm_arr, 12, 2, this_arr(1)%perturbers_prm, &
+                     error, step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, encounters=encounters, &
+                     masses=masses)
+             ELSE
+                CALL gauss_radau_15_full_jpl(mjd_tt0, mjd_tt, &
+                     elm_arr, 12, 2, this_arr(1)%perturbers_prm, &
+                     error, step=this_arr(1)%integration_step_prm, &
+                     ncenter=central_body, &
+                     masses=masses)
+             END IF
+          END IF
+          IF (error) THEN
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Gauss-Radau integration was unsuccessful.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             DEALLOCATE(jacobian_, stat=err)
+             DEALLOCATE(partials0, stat=err)
+             RETURN
+          END IF
+
+       CASE default
+
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "No such integrator:" // TRIM(this_arr(1)%integrator_prm), 1)
+          IF (PRESENT(jacobian)) THEN
+             DEALLOCATE(jacobian, stat=err)
+          END IF
+          DEALLOCATE(element_type_arr, stat=err)
+          DEALLOCATE(frame_arr, stat=err)
+          DEALLOCATE(elm_arr, stat=err)
+          DEALLOCATE(jacobian_, stat=err)
+          DEALLOCATE(partials0, stat=err)
+          RETURN
+
+       END SELECT
+
+       IF (naddit > 0 .AND. info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A)") &
+               "Orbital elements for additional perturbers (cartesian equatorial), " // &
+               "their epoch, and mass at final epoch:"
+          DO i=1,naddit
+             WRITE(stdout,"(2X,I0,7(1X,F17.9),1X,E10.4)") &
+                  i, elm_arr(:,SIZE(elm_arr,dim=2)-naddit+i), &
+                  mjd_tt, this_arr(1)%additional_perturbers(i,8)
+          END DO
+       END IF
+
+       DO i=1,nthis
+          this_arr(i)%t = copy(t_)
+          IF (element_type_arr(i) == "cartesian" .AND. frame_arr(i) == "equatorial") THEN
+             this_arr(i)%elements = elm_arr(:,i)
+          ELSE IF (element_type_arr(i) == "cartesian" .AND. frame_arr(i) == "ecliptic") THEN
+             CALL rotateToEcliptic(elm_arr(1:6,i))
+             this_arr(i)%elements = elm_arr(:,i)
+             IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                DO j=1,12
+                   CALL rotateToEcliptic(elm_arr(1:6,nthis+naddit+(i-1)*12+j))
+                END DO
+             END IF
+          ELSE IF (element_type_arr(i) == "keplerian") THEN
+             CALL NEW(this_, elm_arr(1:6,i), "cartesian", "equatorial", copy(t_))
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "TRACE BACK (45)", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                DEALLOCATE(partials0, stat=err)
+                RETURN
+             END IF
+             CALL toKeplerian(this_)
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "TRACE BACK (50)", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                DEALLOCATE(partials0, stat=err)
+                RETURN
+             END IF
+             this_arr(i)%elements = this_%elements
+             CALL NULLIFY(this_)
+             IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                DO j=1,12
+                   CALL NEW(this_, elm_arr(1:6,nthis+naddit+(i-1)*12+j), "cartesian", "equatorial", copy(t_))
+                   IF (error) THEN
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "TRACE BACK (55)", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      DEALLOCATE(partials0, stat=err)
+                      RETURN
+                   END IF
+                   elm_arr(1:6,nthis+naddit+(i-1)*12+j) = getElements(this_, "keplerian")
+                   IF (error) THEN
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "TRACE BACK (60)", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      DEALLOCATE(partials0, stat=err)
+                      RETURN
+                   END IF
+                   CALL NULLIFY(this_)
+                END DO
+             END IF
+          ELSE IF (element_type_arr(i) == "cometary") THEN
+             CALL NEW(this_, elm_arr(1:6,i), "cartesian", "equatorial", copy(t_))
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "TRACE BACK (45)", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                DEALLOCATE(partials0, stat=err)
+                RETURN
+             END IF
+             CALL toCometary(this_)
+             IF (error) THEN
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "TRACE BACK (50)", 1)
+                IF (PRESENT(jacobian)) THEN
+                   DEALLOCATE(jacobian, stat=err)
+                END IF
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                DEALLOCATE(partials0, stat=err)
+                RETURN
+             END IF
+             this_arr(i)%elements = this_%elements
+             CALL NULLIFY(this_)
+             IF (PRESENT(jacobian) .AND. ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                DO j=1,12
+                   CALL NEW(this_, elm_arr(1:6,nthis+naddit+(i-1)*12+j), "cartesian", "equatorial", copy(t_))
+                   IF (error) THEN
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "TRACE BACK (55)", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      DEALLOCATE(partials0, stat=err)
+                      RETURN
+                   END IF
+                   elm_arr(1:6,nthis+naddit+(i-1)*12+j) = getElements(this_, "cometary")
+                   IF (error) THEN
+                      CALL errorMessage("Orbit / propagate (multiple)", &
+                           "TRACE BACK (60)", 1)
+                      DEALLOCATE(jacobian, stat=err)
+                      DEALLOCATE(element_type_arr, stat=err)
+                      DEALLOCATE(frame_arr, stat=err)
+                      DEALLOCATE(elm_arr, stat=err)
+                      DEALLOCATE(jacobian_, stat=err)
+                      DEALLOCATE(partials0, stat=err)
+                      RETURN
+                   END IF
+                   CALL NULLIFY(this_)
+                END DO
+             END IF
+          ELSE 
+             error =.TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "'" // TRIM(element_type_arr(i)) // &
+                  "' elements not supported.", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             DEALLOCATE(jacobian_, stat=err)
+             DEALLOCATE(partials0, stat=err)
+             RETURN
+          END IF
+
+          IF (PRESENT(jacobian)) THEN
+             IF (ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                ! If fd approach, compute the Jacobian in the following way 
+                ! for all element types and frames:
+                DO j=1,6
+                   jacobian(i,:,j) = (elm_arr(:,nthis+naddit+(i-1)*12+j) - &
+                        elm_arr(:,nthis+naddit+(i-1)*12+j+6)) / &
+                        (2.0_bp*this_arr(i)%finite_diff_prm(j))
+                END DO
+             ELSE IF ((element_type_arr(i) == "keplerian" .OR. &
+                  element_type_arr(i) == "cometary") .AND. &
+                  .NOT.ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                ! If element type is Keplerian and ve approach:
+                IF (element_type_arr(i) == "keplerian") THEN
+                   CALL partialsKeplerianWrtCartesian(this_arr(i), &
+                        partials1, frame="equatorial")
+                ELSE IF (element_type_arr(i) == "cometary") THEN
+                   CALL partialsCometaryWrtCartesian(this_arr(i), &
+                        partials1, frame="equatorial")                   
+                END IF
+                IF (error) THEN
+                   CALL errorMessage("Orbit / propagate (multiple)", &
+                        "TRACE BACK (65)", 1)
+                   DEALLOCATE(jacobian, stat=err)
+                   DEALLOCATE(element_type_arr, stat=err)
+                   DEALLOCATE(frame_arr, stat=err)
+                   DEALLOCATE(elm_arr, stat=err)
+                   DEALLOCATE(jacobian_, stat=err)
+                   DEALLOCATE(partials0, stat=err)
+                   RETURN
+                END IF
+                jacobian(i,:,:) = MATMUL(MATMUL(partials1,jacobian(i,:,:)),partials0(i,:,:))
+             ELSE IF (element_type_arr(i) == "cartesian" .AND. frame_arr(i) == "ecliptic" .AND. &
+                  .NOT.ALL(this_arr(i)%finite_diff_prm > 0.0_bp)) THEN
+                ! If element type is Cartesian, frame is ecliptical and ve approach:
+                DO j=1,6
+                   CALL rotateToEcliptic(jacobian(i,:,j))
+                END DO
+                DO j=1,6
+                   CALL rotateToEcliptic(jacobian(i,j,:))
+                END DO
+             ELSE IF (element_type_arr(i) /= "cartesian" .AND. &
+                  element_type_arr(i) /= "cometary" .AND. &
+                  element_type_arr(i) /= "keplerian") THEN 
+                error =.TRUE.
+                CALL errorMessage("Orbit / propagate (multiple)", &
+                     "Jacobian of '" // TRIM(element_type_arr(i)) // &
+                     "' elements not supported.", 1)
+                DEALLOCATE(element_type_arr, stat=err)
+                DEALLOCATE(frame_arr, stat=err)
+                DEALLOCATE(elm_arr, stat=err)
+                DEALLOCATE(jacobian, stat=err)
+                DEALLOCATE(jacobian_, stat=err)
+                DEALLOCATE(partials0, stat=err)
+                RETURN
+             END IF
+          END IF
+          ! Update additional perturbers' orbital elements and epochs
+          DO j=1,naddit
+             this_arr(i)%additional_perturbers(j,1:6) = elm_arr(:,nthis+j)
+             this_arr(i)%additional_perturbers(j,7) = mjd_tt
+          END DO
+       END DO
+
+       IF (ALLOCATED(partials0)) THEN
+          DEALLOCATE(partials0, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Could not deallocate memory (10).", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             DEALLOCATE(jacobian_, stat=err)
+             RETURN
+          END IF
+       END IF
+       IF (ALLOCATED(jacobian_)) THEN
+          DEALLOCATE(jacobian_, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / propagate (multiple)", &
+                  "Could not deallocate memory (15).", 1)
+             IF (PRESENT(jacobian)) THEN
+                DEALLOCATE(jacobian, stat=err)
+             END IF
+             DEALLOCATE(element_type_arr, stat=err)
+             DEALLOCATE(frame_arr, stat=err)
+             DEALLOCATE(elm_arr, stat=err)
+             RETURN
+          END IF
+       END IF
+       DEALLOCATE(elm_arr, element_type_arr, frame_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / propagate (multiple)", &
+               "Could not deallocate memory (20).", 1)
+          IF (PRESENT(jacobian)) THEN
+             DEALLOCATE(jacobian, stat=err)
+          END IF
+          DEALLOCATE(element_type_arr, stat=err)
+          DEALLOCATE(frame_arr, stat=err)
+          DEALLOCATE(elm_arr, stat=err)
+          RETURN
+       END IF
+
+    CASE default
+
+       error = .TRUE.
+       CALL errorMessage("Orbit / propagate (multiple)", &
+            "Could not choose between 2-body and n-body: " // &
+            TRIM(dyn_model), 1)
+       IF (PRESENT(jacobian)) THEN
+          DEALLOCATE(jacobian, stat=err)
+       END IF
+       DEALLOCATE(element_type_arr, stat=err)
+       DEALLOCATE(frame_arr, stat=err)
+       DEALLOCATE(elm_arr, stat=err)
+       DEALLOCATE(jacobian_, stat=err)
+       DEALLOCATE(partials0, stat=err)
+       RETURN
+
+    END SELECT
+
+    CALL NULLIFY(this_)
+    CALL NULLIFY(t_)
+
+  END SUBROUTINE propagate_Orb_multiple
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Orbit-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myorbits => reallocate(myorbits,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_Orb_1(array,n)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:), POINTER :: reallocate_Orb_1, array
+    INTEGER, INTENT(in)                 :: n
+    INTEGER                             :: i, nold, err
+
+    ALLOCATE(reallocate_Orb_1(n), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_Orb_1 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    DO i=1, MIN(n,nold)
+       CALL NULLIFY(reallocate_Orb_1(i))
+       reallocate_Orb_1(i) = copy(array(i))
+    END DO
+    DO i=1,nold
+       CALL NULLIFY(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_Orb_1
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Orbit-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myorbits => reallocate(myorbits,4,2)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_Orb_2(array, n, m)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:,:), POINTER :: reallocate_Orb_2, array
+    INTEGER, INTENT(in)                   :: n, m
+    INTEGER                               :: i, j, nold, mold, err
+
+    ALLOCATE(reallocate_Orb_2(n,m), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_Orb_2 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    mold = SIZE(array,dim=2)
+    DO i=1, MIN(n,nold)
+       DO j=1, MIN(m,mold)
+          CALL NULLIFY(reallocate_Orb_2(i,j))
+          reallocate_Orb_2(i,j) = copy(array(i,j))
+       END DO
+    END DO
+    DO i=1,nold
+       DO j=1,mold
+          CALL NULLIFY(array(i,j))
+       END DO
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_Orb_2
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Orbit-objects by removing
+  !! non-initialized objects.
+  !!
+  !! *Usage*:
+  !!
+  !! myorbits => reallocate(myorbits)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_Orb(array)
+
+    IMPLICIT NONE
+    TYPE (Orbit), DIMENSION(:), POINTER :: reallocate_Orb, array
+    INTEGER                             :: i, j, err
+
+    IF (.NOT. ASSOCIATED(array)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Parameter pointer is not associated.", 1)
+       reallocate_Orb => NULL()
+       RETURN
+    END IF
+
+    ALLOCATE(reallocate_Orb(SIZE(array,dim=1)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_Orb => NULL()
+       RETURN
+    END IF
+    j = 0
+    DO i=1, SIZE(array,dim=1)
+       IF (exist(array(i))) THEN
+          j = j + 1 
+          reallocate_Orb(j) = copy(array(i))
+       END IF
+    END DO
+    DO i=1,SIZE(array)
+       CALL NULLIFY(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+    reallocate_Orb => reallocate(reallocate_Orb,j)
+
+  END FUNCTION reallocate_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates to the ecliptical coordinate frame, if not
+  !! already the case.
+  !!
+  SUBROUTINE rotateToEcliptic_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout) :: this
+
+    IF (this%frame /= "ecliptic" .AND. this%is_initialized &
+         .AND. this%element_type == "cartesian") THEN
+       CALL rotateToEcliptic(this%elements)
+       this%frame = "ecliptic"
+    END IF
+
+  END SUBROUTINE rotateToEcliptic_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates coordinates to the equatorial coordinate frame, if not
+  !! already the case.
+  !!
+  SUBROUTINE rotateToEquatorial_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout) :: this
+
+    IF (this%frame /= "equatorial" .AND. this%is_initialized &
+         .AND. this%element_type == "cartesian") THEN
+       CALL rotateToEquatorial(this%elements)
+       this%frame = "equatorial"
+    END IF
+
+  END SUBROUTINE rotateToEquatorial_Orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Use finite diffference approach instead of the default
+  !! variational equations in n-body integrations. Note that also the
+  !! setParameters routine must be called to force n-body integration
+  !! to be used instead of the default 2-body approximations.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setParameters_Orb(this, &
+       mass, &
+       dyn_model, &
+       integration_step, &
+       integrator, &
+       finite_diff, &
+       perturbers, &
+       additional_perturbers)
+
+    IMPLICIT NONE
+    TYPE(Orbit), INTENT(inout)                   :: this
+    CHARACTER(len=*), INTENT(in), OPTIONAL       :: dyn_model
+    CHARACTER(len=*), INTENT(in), OPTIONAL       :: integrator
+    REAL(bp), DIMENSION(:,:), OPTIONAL           :: additional_perturbers ! (car equ + mjd_tt + mass)
+    REAL(bp), DIMENSION(6), INTENT(in), OPTIONAL :: finite_diff
+    REAL(bp), INTENT(in), OPTIONAL               :: integration_step
+    REAL(bp), INTENT(in), OPTIONAL               :: mass
+    LOGICAL, DIMENSION(10), OPTIONAL             :: perturbers
+
+    CHARACTER(len=256) :: str
+    INTEGER :: err
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / setParameters", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(mass)) THEN
+       this%mass_prm = mass
+    END IF
+    IF (PRESENT(dyn_model)) THEN
+       IF (LEN_TRIM(dyn_model) > DYN_MODEL_LEN) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / setParameters", &
+               "Parameter 'propagation' too long.", 1)
+          RETURN
+       END IF
+       str = dyn_model
+       CALL locase(str, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / setParameters", &
+               "The dynamical model string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       IF (str /= "2-body" .AND. &
+            str /= "n-body") THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / setParameters", &
+               "Option " // TRIM(dyn_model) // " not available.", 1)
+          RETURN
+       END IF
+       this%dyn_model_prm = TRIM(str)
+    END IF
+    IF (PRESENT(integration_step)) THEN
+       this%integration_step_prm = integration_step
+    END IF
+    IF (PRESENT(integrator)) THEN
+       str = integrator
+       CALL locase(str, error)
+       IF (error) THEN
+          CALL errorMessage("Orbit / setParameters", &
+               "The integrator string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       this%integrator_prm = TRIM(str)
+    END IF
+    IF (PRESENT(finite_diff)) THEN
+       ! Only use the finite difference technique, if all finite
+       ! differences are positive.
+       IF (ALL(finite_diff > 0.0_bp)) THEN
+          this%finite_diff_prm = finite_diff
+       ELSE
+          this%finite_diff_prm = -1.0_bp
+       END IF
+    END IF
+    IF (PRESENT(perturbers)) THEN
+       this%perturbers_prm = perturbers
+    END IF
+    IF (PRESENT(additional_perturbers)) THEN
+       IF (SIZE(additional_perturbers,dim=2) < 8) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / setParameters", &
+               "Too few parameters provided for additional perturbers. " // &
+               "Minimum information includes orbital elements, epoch, and perturber mass.", 1)
+          RETURN          
+       END IF
+       IF (.NOT.ASSOCIATED(this%additional_perturbers)) THEN
+          ALLOCATE(this%additional_perturbers(SIZE(additional_perturbers,dim=1), &
+               SIZE(additional_perturbers,dim=2)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / setParameters", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+       END IF
+       this%additional_perturbers = additional_perturbers
+    END IF
+
+  END SUBROUTINE setParameters_Orb
+
+
+
+
+  !! *Description*:
+  !!
+  !! Iterates Kepler's equation for input Keplerian orbital elements
+  !! and epoch with accelerated Newton's method, and returns the 
+  !! eccentric anomaly at the given time. If an error occurs, the
+  !! subroutine returns a negative eccentric anomaly.
+  !!
+  !! References:
+  !!
+  !! J. M. A. Danby: "Fundamentals of Celestial mechanics"
+  !! pp. 149-154
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE solveKeplerEquation_newton(this, t, ea)
+
+    IMPLICIT NONE 
+    TYPE(Orbit), INTENT(in) :: this
+    TYPE(Time), INTENT(in)  :: t
+    REAL(bp), INTENT(out)   :: ea
+    INTEGER, PARAMETER      :: nmax = 10000
+    TYPE(Time)              :: t_
+    REAL(bp), PARAMETER     :: k = 0.85_bp
+    REAL(bp), PARAMETER     :: tol = 1.0e-14_bp
+    REAL(bp), DIMENSION(6)  :: elements
+    REAL(bp)                :: mjd_tt0, mjd_tt, ma, sigma, x, dx, &
+         esinx, ecosx, f, fp, fpp, fppp
+    INTEGER                 :: i
+
+    ea = -HUGE(ea)
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / solveKeplerEquation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%element_type == "keplerian") THEN
+       elements = this%elements
+    ELSE
+       elements = getElements(this, "keplerian")
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "TRACE BACK 5", 1)
+          RETURN
+       END IF
+    END IF
+    t_ = copy(this%t)
+    mjd_tt0 = getMJD(t_, "TT")
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / solveKeplerEquation", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t_)
+    t_ = copy(t)
+    mjd_tt = getMJD(t_, "TT")
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / solveKeplerEquation", &
+            "TRACE BACK 15", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t_)
+
+    ! Find initial guess:
+    ma = elements(6) + SQRT(planetary_mu(this%central_body)/elements(1)**3.0_bp)*(mjd_tt-mjd_tt0)
+    ma = MODULO(ma,two_pi)
+    sigma = SIGN(1.0_bp,SIN(ma))
+    x = ma + sigma*k*elements(2)
+
+    ! Solve Kepler's equation iteratively using Newton's accelerated method:
+    i = 1
+    esinx = elements(2)*SIN(x)
+    f = x - esinx - ma
+    DO WHILE (ABS(f) >= tol)
+       IF (i > nmax) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "Uncertain convergence.", 1)
+          RETURN
+       END IF
+       ecosx = elements(2)*COS(x)
+       fp    = 1.0_bp - ecosx
+       fpp   = esinx
+       fppp  = ecosx
+       dx    = -f/fp
+       dx    = -f/(fp+0.5_bp*dx*fpp)
+       dx    = -f/(fp+0.5_bp*dx*fpp+dx*dx*fppp/6.0_bp)
+       x     = x + dx
+       esinx = elements(2)*SIN(x)
+       f     = x - esinx - ma
+       i     = i + 1
+    END DO
+    ea = MODULO(x,two_pi)
+
+  END SUBROUTINE solveKeplerEquation_newton
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Solves Kepler's equation using universal variables and returns the values 
+  !! of the scaled Stumpff functions c1, c2, and c3. 
+  !!
+  !! Returns error.
+  !!
+  !! Reference: 
+  !! Danby, J. M.: Fundamentals of Celestial Mechanics, 2nd ed., 
+  !!               rev. ed. Richmond, VA: Willmann-Bell, pp. 170-178, 1988
+  !!
+  SUBROUTINE solveKeplerEquation_stumpff(r0, u, alpha, dt, stumpff_cs, ffs, s, central_body)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)                  :: r0, u, alpha
+    REAL(bp), INTENT(inout)               :: dt
+    REAL(bp), DIMENSION(0:3), INTENT(out) :: stumpff_cs, ffs
+    INTEGER, INTENT(in)                   :: central_body
+    REAL(bp), INTENT(out)                 :: s
+    INTEGER,  PARAMETER                   :: nnew = 8 ! 8
+    INTEGER,  PARAMETER                   :: nlag = 20 ! 20
+    ! Care must be taken that tols is not too small!
+    REAL(bp), PARAMETER                   :: tols = 1.0e-10_bp ! e-10
+    REAL(bp), DIMENSION(0:3)              :: stumpff_c
+    REAL(bp)                              :: s_, ds, a, e, en, ec, es, tmp
+    REAL(bp)                              :: ech, esh, x, y, sigma, dm, ln, mu_
+    INTEGER                               :: n
+
+    ! Define mu parameter
+    mu_ = planetary_mu(central_body)
+
+    ! For small ds, equal initial guesses for elliptic and hyperbolic motion;
+    ! for large ds, separate initial guesses:
+    IF (ABS(dt/r0) <= 0.2_bp) THEN
+       IF (ABS(r0**3.0_bp) < 10*EPSILON(r0)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "r0**3 equal to zero.", 1)
+          RETURN
+       ELSE
+          s = dt/r0 - dt**2.0_bp * 0.5_bp*u/(r0**3.0_bp) ! r0 can be small !!!
+       END IF
+    ELSE
+       a = mu_/alpha
+       IF (ABS(a**3.0_bp) < 10**(-15)*EPSILON(tmp)) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "a**3 equal to zero.", 1)
+          RETURN
+       ELSE
+          ! If alpha < 0, then mu < 0, and vice versa:
+          en = SQRT(SIGN(mu_,alpha)/(a**3.0_bp))
+       END IF
+       IF (alpha > 0.0_bp) THEN ! alpha positive -> elliptic motion
+          ec = 1.0_bp - r0/a
+          tmp = en*a**2.0_bp
+          IF (ABS(tmp) < 10*EPSILON(tmp)) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / solveKeplerEquation", &
+                  "1-r0/a equal to zero (5).", 1)
+             RETURN
+          ELSE
+             es = u/tmp
+          END IF
+          e = SQRT(ec**2.0_bp + es**2.0_bp)
+          dt = dt - INT(en*dt/two_pi) * two_pi/en
+          y = en*dt - es
+          sigma = SIGN(1.0_bp,es*COS(y)+ec*SIN(y))
+          x = y + sigma*0.85_bp*e
+          s = x/SQRT(alpha)
+       ELSE ! alpha negative (or equal to zero) -> hyperbolic motion
+          ech = 1.0_bp - r0/a
+          tmp = SQRT(-a*mu_)
+          esh = u/tmp
+          tmp = ech**2.0_bp - esh**2.0_bp
+          IF (tmp < 0.0_bp) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / solveKeplerEquation", &
+                  "ech**2.0_bp - esh**2.0_bp negative.", 1)
+             RETURN
+          ELSE
+             e = SQRT(tmp)
+          END IF
+          dm = en*dt
+          IF (dm >= 0.0_bp) THEN
+             tmp = ech + esh
+             s = LOG((2.0_bp*dm + 1.8_bp*e)/tmp)/SQRT(-alpha)
+          ELSE
+             tmp = ech - esh
+             s = -LOG((-2.0_bp*dm + 1.8_bp*e)/tmp)/SQRT(-alpha)
+          END IF
+       END IF
+    END IF
+    s_ = s
+
+    ! Newton's method for solving s:
+    n  = 0
+    DO WHILE (n < nnew)
+       n             = n + 1
+       x             = s**2.0_bp * alpha
+       CALL getStumpffFunctions(x, stumpff_c)
+       IF (error) THEN
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "TRACE BACK 5", 1)
+          RETURN
+       END IF
+       stumpff_cs(0) = stumpff_c(0)
+       stumpff_cs(1) = stumpff_c(1) * s
+       stumpff_cs(2) = stumpff_c(2) * s**2.0_bp
+       stumpff_cs(3) = stumpff_c(3) * s**3.0_bp
+       ffs(0) = r0*stumpff_cs(1) + u*stumpff_cs(2) + mu_*stumpff_cs(3) - dt
+       ffs(1) = r0*stumpff_cs(0) + u*stumpff_cs(1) + mu_*stumpff_cs(2)
+       ffs(2) = (-r0*alpha+mu_)*stumpff_cs(1) + u*stumpff_cs(0)
+       ffs(3) = (-r0*alpha+mu_)*stumpff_cs(0) - u*alpha*stumpff_cs(1)
+       IF (ABS(ffs(1)) < 10*EPSILON(ffs(1))) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "Division by zero (40).", 1)
+          RETURN
+       ELSE
+          ds = -ffs(0) / ffs(1)
+       END IF
+       tmp = ffs(1) + 0.5_bp*ds*ffs(2)
+       IF (ABS(tmp) < 10*EPSILON(ffs(1))) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "Division by zero (45).", 1)
+          RETURN
+       ELSE
+          ds = -ffs(0) / tmp
+       END IF
+       tmp = ffs(1) + 0.5_bp*ds*ffs(2) + ds**2.0_bp*ffs(3)/6.0_bp
+       IF (ABS(tmp) < 10*EPSILON(ffs(1))) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "Division by zero (50).", 1)
+          RETURN
+       ELSE
+          ds = -ffs(0) / tmp
+       END IF
+       s = s + ds
+       ! Return if/when solution is found:
+       IF (ABS(ds) < tols) THEN
+          RETURN
+       END IF
+    END DO
+
+    ! Laguerre's method for solving s:
+    s  = s_
+    ln = 5.0_bp
+    n  = 0
+    DO WHILE (n < nlag)
+       n = n + 1
+       x = s**2.0_bp * alpha
+       CALL getStumpffFunctions(x, stumpff_c)
+       IF (error) THEN
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "TRACE BACK 10", 1)
+          RETURN
+       END IF
+       stumpff_cs(0) = stumpff_c(0)
+       stumpff_cs(1) = stumpff_c(1) * s
+       stumpff_cs(2) = stumpff_c(2) * s**2.0_bp
+       stumpff_cs(3) = stumpff_c(3) * s**3.0_bp
+       ffs(0)        = r0*stumpff_cs(1) + u*stumpff_cs(2) + mu_*stumpff_cs(3) - dt
+       ffs(1)        = r0*stumpff_cs(0) + u*stumpff_cs(1) + mu_*stumpff_cs(2)
+       ffs(2)        = (-r0*alpha+mu_)*stumpff_cs(1) + u*stumpff_cs(0)
+       tmp = ffs(1)+SIGN(1.0_bp,ffs(1))*SQRT(ABS((ln-1.0_bp)**2.0_bp*ffs(1)**2.0_bp - &
+            (ln-1.0_bp)*ln*ffs(0)*ffs(2)))
+       IF (ABS(tmp) < 10*EPSILON(ffs(1))) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / solveKeplerEquation", &
+               "Division by zero (55).", 1)
+          RETURN
+       ELSE
+          ds = -ln*ffs(0) / tmp
+       END IF
+       s = s + ds
+       ! Return if/when solution is found:
+       IF (ABS(ds) < tols) THEN
+          RETURN
+       END IF
+    END DO
+
+    ! Both Newton's and Laguerre's methods were unsuccesful. Report error:
+    error = .TRUE.
+    CALL errorMessage("Orbit / solveKeplerEquation", &
+         "Newton's and Laguerre's methods were unsuccessful.", 1)
+
+  END SUBROUTINE solveKeplerEquation_stumpff
+
+
+
+
+
+  SUBROUTINE toCartesian_Orb(this, frame)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)  :: this
+    CHARACTER(len=*), INTENT(in) :: frame
+    CHARACTER(len=FRAME_LEN)     :: frame_
+    REAL(bp), DIMENSION(6)       :: elements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / toCartesian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    frame_ = frame
+    CALL locase(frame_, error)
+    IF (error) THEN
+       CALL errorMessage("Orbit / toCartesian", &
+            "The frame string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    IF (frame_ /= "equatorial" .AND. &
+         frame_ /= "ecliptic") THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / toCartesian", &
+            "Frame " // TRIM(frame_) // " not recognized.", 1)
+    END IF
+
+    IF (info_verb >= 4) THEN
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "Orbit / toCartesian:", &
+            "Conversion to " // TRIM(frame_) // &
+            " Cartesian elements. Initial " // TRIM(this%frame) // &
+            " " // TRIM(this%element_type) // " elements:"
+       IF (this%element_type == "cartesian") THEN
+          WRITE(stdout,"(6(F22.15))") this%elements
+       ELSE IF (this%element_type == "cometary") THEN
+          WRITE(stdout,"(6(F22.15))") this%elements(1:2), &
+               this%elements(3:5)/rad_deg, this%elements(6)
+       ELSE IF (this%element_type == "keplerian") THEN
+          WRITE(stdout,"(6(F22.15))") this%elements(1:2), &
+               this%elements(3:6)/rad_deg
+       END IF
+    END IF
+
+    IF (this%element_type /= "cartesian") THEN
+       elements = getElements(this, "cartesian", frame_)
+       IF (error) THEN
+          CALL errorMessage("Orbit / toCartesian", &
+               "TRACE BACK (5).", 1)
+          RETURN
+       END IF
+       this%elements = elements
+       this%element_type = "cartesian"
+       this%frame = frame_
+    ELSE
+       IF (frame_ == "equatorial") THEN
+          CALL rotateToEquatorial(this)
+       ELSE
+          CALL rotateToEcliptic(this)
+       END IF
+    END IF
+
+    IF (info_verb >= 4) THEN
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "Orbit / toCartesian:", &
+            "Final " // TRIM(this%frame) // &
+            " " // TRIM(this%element_type) // " elements:"
+       WRITE(stdout,"(6(F22.15))") this%elements
+    END IF
+
+  END SUBROUTINE toCartesian_Orb
+
+
+
+
+
+  SUBROUTINE toCometary_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)  :: this
+    REAL(bp), DIMENSION(6)       :: elements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / toCometary", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this, "cometary")
+    IF (error) THEN
+       CALL errorMessage("Orbit / toCometary", &
+            "TRACE BACK (5).", 1)
+       RETURN
+    END IF
+    this%elements = elements
+    this%element_type = "cometary"
+    this%frame = "ecliptic"
+
+  END SUBROUTINE toCometary_Orb
+
+
+
+
+
+  SUBROUTINE toKeplerian_Orb(this)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(inout)  :: this
+    REAL(bp), DIMENSION(6)       :: elements
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / toKeplerian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    elements = getElements(this, "keplerian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / toKeplerian", &
+            "TRACE BACK (5).", 1)
+       RETURN
+    END IF
+    this%elements = elements
+    this%element_type = "keplerian"
+    this%frame = "ecliptic"
+
+  END SUBROUTINE toKeplerian_Orb
+
+
+
+
+
+END MODULE Orbit_cl
Index: trunk/mops/oorb/classes/PhysicalParameters_class.f90
===================================================================
--- trunk/mops/oorb/classes/PhysicalParameters_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/PhysicalParameters_class.f90	(revision 34646)
@@ -0,0 +1,951 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!
+!! Type and routines for various physical parameters such as absolute
+!! magnitude H and slope parameter G.
+!!
+!! @see StochasticOrbit_class 
+!!
+!! @author  MG
+!! @version 2011-01-26
+!!
+MODULE PhysicalParameters_cl
+
+  USE Base_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  USE CartesianCoordinates_cl
+  USE Observations_cl
+  USE StochasticOrbit_cl
+
+  USE utilities
+  USE planetary_data
+  USE linal
+  USE sort
+  use statistics
+
+  IMPLICIT NONE
+
+  PRIVATE :: new_PP
+  PRIVATE :: new_PP_storb
+  PRIVATE :: nullify_PP
+  PRIVATE :: copy_PP
+  PRIVATE :: exist_PP
+
+  TYPE PhysicalParameters
+
+     PRIVATE
+     REAL(bp), DIMENSION(:,:), POINTER :: H0_arr
+     REAL(bp)                          :: H0_nominal
+     REAL(bp)                          :: H0_unc
+     REAL(bp), DIMENSION(:,:), POINTER :: G_arr
+     REAL(bp)                          :: G_nominal
+     REAL(bp)                          :: G_unc
+     REAL(bp), DIMENSION(:,:), POINTER :: m_arr
+     REAL(bp)                          :: m_nominal
+     REAL(bp)                          :: m_unc     
+     TYPE (StochasticOrbit)            :: storb
+     LOGICAL                           :: is_initialized = .FALSE.
+
+  END TYPE PhysicalParameters
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_PP
+     MODULE PROCEDURE new_PP_storb
+  END INTERFACE
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_PP
+  END INTERFACE
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_PP
+  END INTERFACE
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_PP
+  END INTERFACE
+
+CONTAINS
+
+
+  !! *Description*:
+  !!
+  !! Initializes a PhysicalParameters object. 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_PP(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%H0_nominal = 99.9_bp
+    this%G_nominal = -9.9_bp
+    CALL NEW(this%storb)
+    this%is_initialized  = .TRUE.
+
+  END SUBROUTINE new_PP
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a PhysicalParameters object. 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_PP_storb(this, storb)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(inout) :: this
+    TYPE (StochasticOrbit), INTENT(in) :: storb
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%H0_nominal = 99.9_bp
+    this%G_nominal = -9.9_bp
+    this%storb = copy(storb)
+    this%is_initialized  = .TRUE.
+
+  END SUBROUTINE new_PP_storb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_PP(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(inout) :: this
+
+    INTEGER :: err
+
+    CALL NULLIFY(this%storb)
+    this%H0_nominal = 99.9_bp
+    this%H0_unc = 99.0_bp
+    this%G_nominal = -9.9_bp
+    IF (ASSOCIATED(this%H0_arr)) THEN
+       DEALLOCATE(this%H0_arr, stat=err)
+    END IF
+    IF (ASSOCIATED(this%G_arr)) THEN
+       DEALLOCATE(this%G_arr, stat=err)
+    END IF
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_PP
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION copy_PP(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this
+    TYPE (PhysicalParameters)             :: copy_PP
+
+    copy_PP%H0_nominal     = this%H0_nominal
+    copy_PP%G_nominal      = this%G_nominal
+    copy_PP%is_initialized = this%is_initialized
+
+  END FUNCTION copy_PP
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether it exists or not.
+  !!
+  LOGICAL FUNCTION exist_PP(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this
+
+    exist_PP = this%is_initialized
+
+  END FUNCTION exist_PP
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Compute crude estimate for H by calculating the exact value for
+  !! each orbit and observation, and averaging over observations. That
+  !! is, for single point estimates (e.g., from LSL) we calculate nobs
+  !! H values and assume their average represents the overall H. For a
+  !! sampled solution each orbit gets an H value which has been
+  !! averaged over observations.
+  !!
+  !! NB: different bands (AKA filters) are not yet properly treated!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE crudeHEstimate(this, obss, input_G)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(inout) :: this    
+    TYPE (Observations), INTENT(in) :: obss
+    REAL(bp), INTENT(in) :: input_G
+
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoord_arr 
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: ephemerides_arr  
+    TYPE (Orbit), DIMENSION(:,:), POINTER :: orb_lt_corr_arr 
+    TYPE (Orbit), DIMENSION(:), POINTER :: orb_arr 
+    CHARACTER(len=2), DIMENSION(:), POINTER :: filter_arr
+    CHARACTER(len=2), DIMENSION(:), ALLOCATABLE :: filter_arr_
+    REAL(bp), DIMENSION(:,:,:), POINTER :: cov_arr
+    REAL(bp), DIMENSION(:,:), POINTER :: pdfs_arr, phase_angle_arr
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: helio_dist_arr, topo_dist_arr
+    REAL(bp), DIMENSION(:), POINTER :: obs_mag_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: H_arr, &
+         obs_mag_arr_
+    REAL(bp), DIMENSION(6) :: coordinates
+    INTEGER :: err, i, j, nobs, norb, nmag
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(this%storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "Orbital information not available.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "Photometric information not available.", 1)
+       RETURN
+    END IF
+
+    ! Extract observational information
+    obsy_ccoord_arr => getObservatoryCCoords(obss)
+    nobs = SIZE(obsy_ccoord_arr)
+    obs_mag_arr => getMagnitudes(obss)
+    filter_arr => getFilters(obss)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Photometry extracted..."
+    END IF
+
+    ! Extract information of observations reporting brightness
+    DO i=1,nobs
+       IF (obs_mag_arr(i) > 90.0_bp) THEN
+          CALL NULLIFY(obsy_ccoord_arr(i))
+       END IF
+    END DO
+    obsy_ccoord_arr => reallocate(obsy_ccoord_arr)
+    nmag = SIZE(obsy_ccoord_arr)
+    ALLOCATE(obs_mag_arr_(nmag), filter_arr_(nmag), stat=err)
+    IF (err /= 0) THEN
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "Could not allocate memory (5).", 1)
+       RETURN
+    END IF
+    j = 0
+    DO i=1,nobs
+       IF (obs_mag_arr(i) < 90.0_bp) THEN
+          j = j + 1
+          obs_mag_arr_(j) = obs_mag_arr(i)
+          filter_arr_(j) = filter_arr(i)
+       END IF
+    END DO
+    DEALLOCATE(obs_mag_arr, filter_arr)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2(I0,A))") nmag, " observations out of ", nobs, &
+            " contain brightness information."
+    END IF
+
+    ! Compute heliocentric and topocentric distances, and phase angles
+    IF (containsSampledPDF(this%storb)) THEN
+       orb_arr => getSampleOrbits(this%storb)
+    ELSE
+       ALLOCATE(orb_arr(1), stat=err)
+       IF (err /= 0) THEN
+          CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+               "Could not allocate memory (10).", 1)
+          RETURN
+       END IF
+       orb_arr(1) = getNominalOrbit(this%storb)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "TRACE BACK (10).", 1)
+       RETURN
+    END IF
+    CALL getEphemerides(orb_arr, obsy_ccoord_arr, &
+         ephemerides_arr, this_lt_corr_arr=orb_lt_corr_arr)
+    IF (error) THEN
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "TRACE BACK (15).", 1)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Ephemerides computed..."
+    END IF
+    norb = SIZE(ephemerides_arr,dim=1)
+    ALLOCATE(helio_dist_arr(norb,nmag), topo_dist_arr(norb,nmag), &
+         H_arr(nmag), stat=err)
+    IF (err /= 0) THEN
+       CALL errorMessage("PhysicalParameters / crudeHEstimate", &
+            "Could not allocate memory (15).", 1)
+       RETURN
+    END IF
+    DO i=1,nmag
+       DO j=1,norb
+          coordinates = getElements(orb_lt_corr_arr(j,i), "cartesian", "ecliptic")
+          helio_dist_arr(j,i) = SQRT(SUM(coordinates(1:3)**2.0_bp))
+          coordinates = getCoordinates(ephemerides_arr(j,i))
+          topo_dist_arr(j,i) = coordinates(1)
+       END DO
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,*) coordinates(2:3)/rad_deg
+       END IF
+    END DO
+    CALL getPhaseAngles(this%storb, obsy_ccoord_arr, &
+         phase_angle_arr)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Phase angles and distances computed..."
+    END IF
+
+    ! Estimate H
+    IF (containsSampledPDF(this%storb)) THEN
+       ALLOCATE(this%H0_arr(norb,2), this%G_arr(norb,2))
+       this%G_arr(:,1) = input_G
+       this%G_arr(:,2) = 0.0_bp
+       DO i=1,norb
+          DO j=1,nmag
+             H_arr(j) = getExactH(obs_mag_arr_(j), helio_dist_arr(i,j), &
+                  topo_dist_arr(i,j), phase_angle_arr(i,j), &
+                  this%G_arr(i,1))
+          END DO
+          this%H0_arr(i,1) = SUM(H_arr)/nmag
+          this%H0_arr(i,2) = 0.0_bp
+       END DO
+       IF (info_verb >= 2) THEN
+          WRITE(*,*) "H0_min: ", MINVAL(this%H0_arr(:,1)-this%H0_arr(:,2)), &
+               "  H0_max: ", MAXVAL(this%H0_arr(:,1)+this%H0_arr(:,2))
+       END IF
+    ELSE
+       this%G_nominal = input_G
+       this%G_unc = 0.0_bp
+       DO j=1,nmag
+          H_arr(j) = getExactH(obs_mag_arr_(j), helio_dist_arr(1,j), &
+               topo_dist_arr(1,j), phase_angle_arr(1,j), &
+               this%G_nominal)
+          !WRITE(*,*) j, H_arr(j)
+       END DO
+       this%H0_nominal = SUM(H_arr)/nmag
+       this%H0_unc = 0.0_bp
+       IF (info_verb >= 2) THEN
+          WRITE(*,*) "H0: ", this%H0_nominal, "  dH0: ", this%H0_unc
+       END IF
+    END IF
+
+    ! Deallocate memory
+    DEALLOCATE(H_arr, stat=err)
+    DEALLOCATE(obsy_ccoord_arr, stat=err)
+    DEALLOCATE(obs_mag_arr_, stat=err)
+    DEALLOCATE(filter_arr_, stat=err)
+    DEALLOCATE(ephemerides_arr, stat=err)
+    DEALLOCATE(orb_lt_corr_arr, stat=err)
+    DEALLOCATE(orb_arr, stat=err)
+    IF (ASSOCIATED(cov_arr)) THEN
+       DEALLOCATE(cov_arr, stat=err)
+    END IF
+    IF (ASSOCIATED(pdfs_arr)) THEN
+       DEALLOCATE(pdfs_arr, stat=err)
+    END IF
+    DEALLOCATE(phase_angle_arr, stat=err)
+    DEALLOCATE(helio_dist_arr, stat=err)
+    DEALLOCATE(topo_dist_arr, stat=err)
+
+  END SUBROUTINE crudeHEstimate
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Compute estimates for H and G as specified in Bowell et al. 1989.
+  !!
+  SUBROUTINE estimateHAndG(this, obss, input_G, input_delta_G)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(inout) :: this    
+    TYPE (Observations), INTENT(in) :: obss
+    REAL(bp), INTENT(in), OPTIONAL :: input_G, input_delta_G
+
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoord_arr 
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: ephemerides_arr  
+    TYPE (Orbit), DIMENSION(:,:), POINTER :: orb_lt_corr_arr 
+    CHARACTER(len=2), DIMENSION(:), POINTER :: filter_arr
+    CHARACTER(len=2), DIMENSION(:), ALLOCATABLE :: filter_arr_
+    REAL(bp), DIMENSION(:,:,:), POINTER :: cov_arr
+    REAL(bp), DIMENSION(:,:), POINTER :: pdfs_arr, phase_angle_arr
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: helio_dist_arr, topo_dist_arr
+    REAL(bp), DIMENSION(:), POINTER :: obs_mag_arr, obs_mag_unc_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: obs_mag_arr_, &
+         obs_mag_unc_arr_
+    REAL(bp), DIMENSION(6) :: coordinates
+    INTEGER :: err, i, j, nmag, norb, nobs
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / estimateHAndG", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(this%storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / estimateHAndG", &
+            "Orbital information not available.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / estimateHAndG", &
+            "Photometric information not available.", 1)
+       RETURN
+    END IF
+
+    ! Extract observational information
+    obsy_ccoord_arr => getObservatoryCCoords(obss)
+    nobs = SIZE(obsy_ccoord_arr)
+    obs_mag_arr => getMagnitudes(obss)
+    obs_mag_unc_arr => getMagnitudeUncertainties(obss)
+    filter_arr => getFilters(obss)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Photometry extracted..."
+    END IF
+    IF (info_verb >= 3) THEN
+       WRITE(stdout,*) obs_mag_unc_arr(:)
+    END IF
+
+    ! Extract information of observations reporting brightness
+    DO i=1,nobs
+       IF (obs_mag_arr(i) > 90.0_bp) THEN
+          CALL NULLIFY(obsy_ccoord_arr(i))
+       END IF
+    END DO
+    obsy_ccoord_arr => reallocate(obsy_ccoord_arr)
+    nmag = SIZE(obsy_ccoord_arr)
+    ALLOCATE(obs_mag_arr_(nmag), filter_arr_(nmag), obs_mag_unc_arr_(nmag))
+    j = 0
+    DO i=1,nobs
+       IF (obs_mag_arr(i) < 90.0_bp) THEN
+          j = j + 1
+          obs_mag_arr_(j) = obs_mag_arr(i)
+          obs_mag_unc_arr_(j) = obs_mag_unc_arr(i)
+          filter_arr_(j) = filter_arr(i)
+       END IF
+    END DO
+    DEALLOCATE(obs_mag_arr, obs_mag_unc_arr, filter_arr)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2(I0,A))") nmag, " observations out of ", nobs, &
+            " contain brightness information."
+    END IF
+
+    ! Compute heliocentric and topocentric distances, and phase angles
+    IF (containsSampledPDF(this%storb)) THEN
+       CALL getEphemerides(this%storb, obsy_ccoord_arr, &
+            ephemerides_arr, pdfs_arr=pdfs_arr, this_lt_corr_arr=orb_lt_corr_arr)
+    ELSE
+       CALL getEphemerides(this%storb, obsy_ccoord_arr, &
+            ephemerides_arr, cov_arr=cov_arr, this_lt_corr_arr=orb_lt_corr_arr)       
+    END IF
+    IF (error) THEN
+       CALL errorMessage("PhysicalParameters / estimateHAndG", &
+            "TRACE BACK (10).", 1)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Ephemerides computed..."
+    END IF
+    norb = SIZE(ephemerides_arr,dim=1)
+    ALLOCATE(helio_dist_arr(norb,nmag), topo_dist_arr(norb,nmag))
+    DO i=1,nmag
+       DO j=1,norb
+          coordinates = getElements(orb_lt_corr_arr(j,i), "cartesian", "ecliptic")
+          helio_dist_arr(j,i) = SQRT(SUM(coordinates(1:3)**2.0_bp))
+          coordinates = getCoordinates(ephemerides_arr(j,i))
+          topo_dist_arr(j,i) = coordinates(1)
+       END DO
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,*) coordinates(2:3)/rad_deg
+       END IF
+    END DO
+    CALL getPhaseAngles(this%storb, obsy_ccoord_arr, &
+         phase_angle_arr)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "Phase angles and distances computed..."
+    END IF
+
+    ! Estimate H and G
+    IF (containsSampledPDF(this%storb)) THEN
+       ALLOCATE(this%H0_arr(norb,2), this%G_arr(norb,2))
+       DO i=1,norb
+          IF (PRESENT(input_G)) THEN
+             CALL HG(obs_mag_arr_, obs_mag_unc_arr_, helio_dist_arr(i,:), &
+                  topo_dist_arr(i,:), phase_angle_arr(i,:), &
+                  this%H0_arr(i,1), this%H0_arr(i,2), this%G_arr(i,1), &
+                  this%G_arr(i,2), input_G, input_delta_G)
+          ELSE
+             CALL HG(obs_mag_arr_, obs_mag_unc_arr_, helio_dist_arr(i,:), &
+                  topo_dist_arr(i,:), phase_angle_arr(i,:), &
+                  this%H0_arr(i,1), this%H0_arr(i,2), this%G_arr(i,1), &
+                  this%G_arr(i,2))
+          END IF
+       END DO
+       IF (info_verb >= 2) THEN
+          WRITE(*,*) "H0_min: ", MINVAL(this%H0_arr(:,1)-this%H0_arr(:,2)), &
+               "  H0_max: ", MAXVAL(this%H0_arr(:,1)+this%H0_arr(:,2))
+          WRITE(*,*) "G_min:  ", MINVAL(this%G_arr(:,1)-this%G_arr(:,2)), &
+               "  G_max:  ", MAXVAL(this%G_arr(:,1)+this%G_arr(:,2))
+       END IF
+    ELSE
+       IF (PRESENT(input_G)) THEN
+          CALL HG(obs_mag_arr_, obs_mag_unc_arr_, helio_dist_arr(1,:), &
+               topo_dist_arr(1,:), phase_angle_arr(1,:), &
+               this%H0_nominal, this%H0_unc, this%G_nominal, &
+               this%G_unc, input_G, input_delta_G)
+       ELSE
+          CALL HG(obs_mag_arr_, obs_mag_unc_arr_, helio_dist_arr(1,:), &
+               topo_dist_arr(1,:), phase_angle_arr(1,:), &
+               this%H0_nominal, this%H0_unc, this%G_nominal, &
+               this%G_unc)
+       END IF
+       IF (info_verb >= 2) THEN
+          WRITE(*,*) "H0: ", this%H0_nominal, "  dH0: ", this%H0_unc
+          WRITE(*,*) "G:  ", this%G_nominal,  "  dG:  ", this%G_unc
+       END IF
+    END IF
+
+    ! Deallocate memory
+    DEALLOCATE(obsy_ccoord_arr, stat=err)
+    DEALLOCATE(obs_mag_arr_, stat=err)
+    DEALLOCATE(obs_mag_unc_arr_, stat=err)
+    DEALLOCATE(filter_arr_, stat=err)
+    DEALLOCATE(ephemerides_arr, stat=err)
+    DEALLOCATE(orb_lt_corr_arr, stat=err)
+    IF (ASSOCIATED(cov_arr)) THEN
+       DEALLOCATE(cov_arr, stat=err)
+    END IF
+    IF (ASSOCIATED(pdfs_arr)) THEN
+       DEALLOCATE(pdfs_arr, stat=err)
+    END IF
+    DEALLOCATE(phase_angle_arr, stat=err)
+    DEALLOCATE(helio_dist_arr, stat=err)
+    DEALLOCATE(topo_dist_arr, stat=err)
+
+  END SUBROUTINE estimateHAndG
+
+
+
+
+
+  !! *Description*:*
+  !!
+  !! The apparent magnitude from the H,G magnitude system.
+  !!
+  REAL(bp) FUNCTION getApparentMagnitude(H, G, r, Delta, phase_angle)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: H, G, r, Delta, phase_angle
+
+    REAL(bp), DIMENSION(2) :: phi
+
+    phi = HGPhaseFunctions(phase_angle)
+    getApparentMagnitude = H - 2.5_bp*LOG10((1.0_bp - G)*phi(1) + &
+         G*phi(2)) + 5.0_bp*LOG10(r*Delta)
+
+  END FUNCTION getApparentMagnitude
+
+
+
+
+
+  !! *Description*:*
+  !!
+  !! Returns the slope parameter G and its uncertainty.
+  !!
+  FUNCTION getG(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this    
+    REAL(bp), DIMENSION(2) :: getG
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / getG", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getG = (/ this%G_nominal, this%G_unc /)
+
+  END FUNCTION getG
+
+
+
+
+
+  !! *Description*:*
+  !!
+  !! Returns a distribution of slope parameters G and their
+  !! uncertainties corresponding to an orbital-element distribution.
+  !!
+  FUNCTION getGDistribution(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this    
+    REAL(bp), DIMENSION(:,:), POINTER :: getGDistribution
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / getGDistribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getGDistribution(SIZE(this%G_arr,dim=1),2))
+    getGDistribution = this%G_arr
+
+  END FUNCTION getGDistribution
+
+
+
+
+
+  !! *Description*:*
+  !!
+  !! Returns the H(alpha=0) magnitude and its uncertainty.
+  !!
+  FUNCTION getH0(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this    
+    REAL(bp), DIMENSION(2) :: getH0
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / getH0", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getH0 = (/ this%H0_nominal, this%H0_unc /)
+
+  END FUNCTION getH0
+
+
+
+
+
+  !! *Description*:*
+  !!
+  !! Returns a distribution of H(alpha=0) magnitudes and their
+  !! uncertainties corresponding to an orbital-element distribution.
+  !!
+  FUNCTION getH0Distribution(this)
+
+    IMPLICIT NONE
+    TYPE (PhysicalParameters), INTENT(in) :: this    
+    REAL(bp), DIMENSION(:,:), POINTER :: getH0Distribution
+
+    IF (.NOT.this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / getH0Distribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%H0_arr)) THEN
+       error = .TRUE.
+       CALL errorMessage("PhysicalParameters / getH0Distribution", &
+            "Object does not contain H0 distribution.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getH0Distribution(SIZE(this%H0_arr,dim=1),2))
+    getH0Distribution = this%H0_arr
+
+  END FUNCTION getH0Distribution
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Compute estimates for H and G and their uncertainties as
+  !! specified in Bowell et al. 1989.
+  !!
+  SUBROUTINE HG(obs_mag_arr, obs_mag_unc_arr, helio_dist_arr, &
+       topo_dist_arr, phase_angle_arr, H0, delta_H0, G, delta_G, input_G, &
+       input_delta_G)
+
+    IMPLICIT NONE
+
+    REAL(bp), DIMENSION(:), INTENT(in) :: obs_mag_arr, &
+         obs_mag_unc_arr, helio_dist_arr, topo_dist_arr, phase_angle_arr
+    REAL(bp), INTENT(out) :: H0, G, delta_H0, delta_G
+    REAL(bp), INTENT(in), OPTIONAL :: input_G, input_delta_G
+
+    REAL(bp), DIMENSION(SIZE(obs_mag_arr),2) :: phi_arr
+    REAL(bp), DIMENSION(SIZE(obs_mag_arr)) :: reduced_mag_arr, &
+         mag_resid_arr, delta_malpha_arr
+    REAL(bp), DIMENSION(2,2) :: h
+    REAL(bp), DIMENSION(2) :: gg, a
+    REAL(bp) :: bigI, D, alpha0, sigma2_Halpha0, sigma2_beta, s2, &
+         delta_Halpha0, delta_beta
+    INTEGER :: i
+
+    ! Note that geo_dist has been changed to topo_dist:
+    reduced_mag_arr = obs_mag_arr - 5.0_bp*LOG10(helio_dist_arr*topo_dist_arr)
+
+    DO i=1,SIZE(reduced_mag_arr)
+       phi_arr(i,1:2) = HGPhaseFunctions(phase_angle_arr(i))
+       !phi_arr(i,1:2) = simplifiedHGPhaseFunctions(phase_angle_arr(i))
+    END DO
+
+    IF (PRESENT(input_G)) THEN
+
+       ! Compute nominal LS value for H(alpha=0) assuming fixed G
+
+       G = input_G       
+       delta_malpha_arr = -2.5_bp * LOG10((1.0_bp - G)*phi_arr(:,1) + G*phi_arr(:,2))
+       H0 = SUM((reduced_mag_arr - delta_malpha_arr)/obs_mag_unc_arr**2.0_bp) / &
+            SUM(1.0_bp/obs_mag_unc_arr**2.0_bp)
+
+    ELSE
+
+       ! Compute nominal LS values for both H(alpha=0) and G 
+
+       h = 0.0_bp
+       gg = 0.0_bp
+       DO i=1,SIZE(reduced_mag_arr)
+          bigI = 10**(-0.4_bp*reduced_mag_arr(i))
+          h(1,1) = h(1,1) + phi_arr(i,1)**2.0_bp/(obs_mag_unc_arr(i)**2.0_bp*bigI**2.0_bp)
+          h(2,2) = h(2,2) + phi_arr(i,2)**2.0_bp/(obs_mag_unc_arr(i)**2.0_bp*bigI**2.0_bp)
+          h(1,2) = h(1,2) + phi_arr(i,1)*phi_arr(i,2)/(obs_mag_unc_arr(i)**2.0_bp*bigI**2.0_bp)
+          gg = gg + phi_arr(i,1:2)/(obs_mag_unc_arr(i)**2.0_bp*bigI**2.0_bp)
+       END DO
+       D = h(1,1)*h(2,2) - h(1,2)**2.0_bp
+       a(1) = (h(2,2)*gg(1) - h(1,2)*gg(2))/D
+       a(2) = (h(1,1)*gg(2) - h(1,2)*gg(1))/D
+       H0 = -2.5_bp*LOG10(SUM(a))
+       ! Note that the definition of G is wrong in the AII chapter!
+       G = a(2)/SUM(a)
+
+    END IF
+
+
+    IF (PRESENT(input_G) .AND. PRESENT(input_delta_G)) THEN
+
+       ! Compute uncertainty for H(alpha=0) assuming fixed G and delta_G
+
+       mag_resid_arr = reduced_mag_arr - H0 + &
+            2.5_bp * LOG10((1.0_bp - G)*phi_arr(:,1) + G*phi_arr(:,2))
+       alpha0 = SUM(phase_angle_arr/obs_mag_unc_arr**2.0_bp) / &
+            SUM(1.0_bp/obs_mag_unc_arr**2.0_bp)
+       sigma2_Halpha0 = 1.0_bp/SUM(1.0_bp/obs_mag_unc_arr**2.0_bp)
+       s2 = 1.0_bp/(SIZE(obs_mag_arr) - 2.0_bp)*SUM((mag_resid_arr/obs_mag_unc_arr)**2.0_bp)
+       delta_Halpha0 = SQRT(s2*sigma2_Halpha0)
+       delta_G = input_delta_G
+       delta_beta = delta_G*(0.0673_bp - 0.1132_bp*G + 0.0615_bp*G**2.0_bp)
+       delta_H0 = SQRT(s2*sigma2_Halpha0 + (delta_beta*alpha0)**2.0_bp)       
+
+    ELSE IF (.NOT.PRESENT(input_G) .AND. .NOT.PRESENT(input_delta_G)) THEN
+
+       ! Compute uncertainties for H(alpha=0) and G
+
+       mag_resid_arr = reduced_mag_arr - H0 + &
+            2.5_bp * LOG10((1.0_bp - G)*phi_arr(:,1) + G*phi_arr(:,2))
+       alpha0 = SUM(phase_angle_arr/obs_mag_unc_arr**2.0_bp) / &
+            SUM(1.0_bp/obs_mag_unc_arr**2.0_bp)
+       sigma2_Halpha0 = 1.0_bp/SUM(1.0_bp/obs_mag_unc_arr**2.0_bp)
+       sigma2_beta = 1.0_bp / (SUM(phase_angle_arr**2.0_bp/obs_mag_unc_arr**2.0_bp) - &
+            alpha0**2.0_bp*SUM(1.0_bp/obs_mag_unc_arr**2.0_bp))
+       s2 = 1.0_bp/(SIZE(obs_mag_arr) - 2.0_bp)*SUM((mag_resid_arr/obs_mag_unc_arr)**2.0_bp)
+       delta_Halpha0 = SQRT(s2*sigma2_Halpha0)
+       delta_beta = SQRT(s2*sigma2_beta)
+       delta_G = delta_beta/(0.0673_bp - 0.1132_bp*G + 0.0615_bp*G**2.0_bp)
+       delta_H0 = SQRT(s2*sigma2_Halpha0 + s2*sigma2_beta*alpha0**2.0_bp)
+
+    ELSE
+
+       ! Uncertainties cannot be computed
+
+       delta_H0 = -1.0_bp
+       delta_G = -1.0_bp
+
+    END IF
+
+  END SUBROUTINE HG
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Compute the exact value for H corresponding to an observed magnitude,
+  !! a heliocentric distance, a topocentric distance, a phase angle, and
+  !! a slope parameter.
+  !!
+  REAL(bp) FUNCTION getExactH(obs_mag, helio_dist, &
+       topo_dist, phase_angle, G)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: obs_mag, &
+         helio_dist, &
+         topo_dist, &
+         phase_angle, &
+         G
+
+    REAL(bp), DIMENSION(2) :: phi
+    REAL(bp) :: reduced_mag, delta_malpha
+
+    ! Note that geo_dist has been changed to topo_dist:
+    reduced_mag = obs_mag - 5.0_bp*LOG10(helio_dist*topo_dist)
+    phi(1:2) = HGPhaseFunctions(phase_angle)
+
+    ! Compute nominal value for H(alpha=0) assuming fixed G
+    delta_malpha = -2.5_bp * LOG10((1.0_bp - G)*phi(1) + G*phi(2))
+    getExactH = reduced_mag - delta_malpha
+
+  END FUNCTION getExactH
+
+
+
+
+
+  FUNCTION HGPhaseFunctions(phase_angle)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(2) :: HGPhaseFunctions
+    REAL(bp), INTENT(in) :: phase_angle
+
+    REAL(bp), DIMENSION(2) :: a, b, c
+    REAL(bp) :: w, phis, phil
+    INTEGER :: i
+
+    a(1) = 3.332_bp
+    a(2) = 1.862_bp
+    b(1) = 0.631_bp
+    b(2) = 1.218_bp
+    c(1) = 0.986_bp
+    c(2) = 0.238_bp
+    w = EXP(-90.56_bp*TAN(0.5_bp*phase_angle)**2)
+
+    DO i=1,2
+       phis = 1.0_bp - C(i)*SIN(phase_angle) / &
+            (0.119_bp+1.341_bp*SIN(phase_angle)-0.754_bp*SIN(phase_angle)**2) 
+       phil = EXP(-a(i)*TAN(0.5_bp*phase_angle)**b(i))
+       HGPhaseFunctions(i) = w*phis + (1.0_bp-w)*phil
+    END DO
+
+  END FUNCTION HGPhaseFunctions
+
+
+
+
+
+  !! MCMC mass estimation algorithm
+  SUBROUTINE massEstimation_mcmc(this, perturber_arr, proposal_density_masses, estimated_masses)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (StochasticOrbit), DIMENSION(:), INTENT(in) :: perturber_arr
+    REAL(bp), DIMENSION(:), INTENT(in) :: proposal_density_masses
+    REAL(bp), DIMENSION(:,:), POINTER :: estimated_masses
+
+  END SUBROUTINE massEstimation_mcmc
+
+
+
+
+  FUNCTION simplifiedHGPhaseFunctions(phase_angle)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(2) :: simplifiedHGPhaseFunctions
+    REAL(bp), INTENT(in) :: phase_angle
+    REAL(bp), DIMENSION(2) :: a, b
+    INTEGER :: i
+
+    a(1) = 3.33_bp
+    a(2) = 1.87_bp
+    b(1) = 0.63_bp
+    b(2) = 1.22_bp
+
+    DO i=1,2
+       simplifiedHGPhaseFunctions(i) = EXP(-a(i)*TAN(0.5_bp*phase_angle)**b(i))
+    END DO
+
+  END FUNCTION simplifiedHGPhaseFunctions
+
+
+
+
+
+
+END MODULE PhysicalParameters_cl
Index: trunk/mops/oorb/classes/SphericalCoordinates_class.f90
===================================================================
--- trunk/mops/oorb/classes/SphericalCoordinates_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/SphericalCoordinates_class.f90	(revision 34646)
@@ -0,0 +1,1283 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Type and routines for spherical coordinates.
+!!
+!! @see Observations_class
+!! 
+!! @author  MG
+!! @version 2012-02-15
+!!
+MODULE SphericalCoordinates_cl
+
+  USE Base_cl
+  USE Time_cl
+
+  USE random
+  USE utilities
+  USE linal
+
+  IMPLICIT NONE
+
+  PRIVATE :: new_SC
+  PRIVATE :: new_SC_coordinates
+  PRIVATE :: new_SC_hour
+  PRIVATE :: new_SC_hourAndDistance
+  PRIVATE :: new_SC_rad
+  PRIVATE :: new_SC_radAndDistance
+  PRIVATE :: new_SC_posAndVel
+  PRIVATE :: nullify_SC
+  PRIVATE :: copy_SC
+  PRIVATE :: exist_SC
+  PRIVATE :: addMultinormalDeviate_SC
+  PRIVATE :: addUniformDeviate_SC
+  PRIVATE :: checkAngles
+  PRIVATE :: equal_SC
+  PRIVATE :: getPosition_SC
+  PRIVATE :: getVelocity_SC
+  PRIVATE :: getFrame_SC
+  PRIVATE :: getTime_SC
+  PRIVATE :: rotateToEquatorial_SC
+  PRIVATE :: rotateToEcliptic_SC
+
+  TYPE SphericalCoordinates
+     PRIVATE
+     REAL(bp), DIMENSION(3)   :: position ! distance   [AU]
+     !                                      longitude  [rad]
+     !                                      latitude   [rad]
+     REAL(bp), DIMENSION(3)   :: velocity ! ddistance  [AU/d]
+     !                                      dlongitude [rad/d]
+     !                                      dlatitude  [rad/d]
+     CHARACTER(len=FRAME_LEN) :: frame = "equatorial"
+     TYPE (Time)              :: t
+     LOGICAL                  :: is_initialized = .FALSE.
+  END TYPE SphericalCoordinates
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_SC
+     MODULE PROCEDURE new_SC_coordinates
+     MODULE PROCEDURE new_SC_hour
+     MODULE PROCEDURE new_SC_hourAndDistance
+     MODULE PROCEDURE new_SC_rad
+     MODULE PROCEDURE new_SC_radAndDistance
+     MODULE PROCEDURE new_SC_posAndVel
+  END INTERFACE NEW
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_SC
+  END INTERFACE NULLIFY
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_SC
+  END INTERFACE copy
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_SC
+  END INTERFACE exist
+
+  INTERFACE addMultinormalDeviate
+     MODULE PROCEDURE addMultinormalDeviate_SC
+  END INTERFACE addMultinormalDeviate
+
+  INTERFACE addUniformDeviate
+     MODULE PROCEDURE addUniformDeviate_SC
+  END INTERFACE addUniformDeviate
+
+  INTERFACE equal
+     MODULE PROCEDURE equal_SC
+  END INTERFACE equal
+
+  INTERFACE getCoordinates
+     MODULE PROCEDURE getCoordinates_SC
+  END INTERFACE getCoordinates
+
+  INTERFACE getPosition
+     MODULE PROCEDURE getPosition_SC
+  END INTERFACE getPosition
+
+  INTERFACE getVelocity
+     MODULE PROCEDURE getVelocity_SC
+  END INTERFACE getVelocity
+
+  INTERFACE getFrame
+     MODULE PROCEDURE getFrame_SC
+  END INTERFACE getFrame
+
+  INTERFACE getTime
+     MODULE PROCEDURE getTime_SC
+  END INTERFACE getTime
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_SC_1
+     MODULE PROCEDURE reallocate_SC_2
+  END INTERFACE reallocate
+
+  INTERFACE rotateToEquatorial
+     MODULE PROCEDURE rotateToEquatorial_SC
+  END INTERFACE rotateToEquatorial
+
+  INTERFACE rotateToEcliptic
+     MODULE PROCEDURE rotateToEcliptic_SC
+  END INTERFACE rotateToEcliptic
+
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using default values:
+  !!   - position and velocity vectors are zero
+  !!   - coordinate frame is equatorial
+  !!   - epoch is the default Time object 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position       = 0.0_bp
+    this%velocity       = 0.0_bp
+    this%frame          = "equatorial"
+    CALL NEW(this%t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as spherical coordinates
+  !! and their time derivatives, the coordinate frame, and the epoch.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_coordinates(this, coordinates, frame, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6), INTENT(in)         :: coordinates
+    CHARACTER(len=*), INTENT(in)               :: frame
+    TYPE (Time), INTENT(in)                    :: t
+    CHARACTER(len=FRAME_LEN)                   :: frame_
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position       = coordinates(1:3)
+    this%velocity       = coordinates(4:6)
+    frame_ = frame
+    CALL locase(frame_, error)
+    IF (error) THEN
+       CALL errorMessage("SphericalCoordinates / new", &
+            "The frame string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    this%frame          = TRIM(frame_)
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC_coordinates
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as the traditional
+  !! astrometric coordinates, and a Time object. Coordinate 
+  !! frame is equatorial, and the distance and the velocity 
+  !! vector are set to zero.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_hour(this, h, min, sec, deg, arcmin, arcsec, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                 :: sec, arcsec
+    INTEGER, INTENT(in)                  :: h, min, deg, arcmin
+    TYPE (Time), INTENT(in)              :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Distance:
+    this%position(1)    = 0.0_bp
+
+    ! Transform longitude:
+    ! Transform to hours:
+    this%position(2)    = h + min/60.0_bp + sec/3600.0_bp
+    ! Transform to radians:
+    this%position(2)    = this%position(2) * rad_hour
+
+    ! Transform latitude:
+    ! Transform to degrees:
+    IF (deg /= 0) THEN
+       this%position(3) = SIGN((ABS(deg) + arcmin/60.0_bp + arcsec/3600.0_bp), REAL(deg, bp))
+    ELSE IF (deg == 0 .AND. arcmin /= 0) THEN
+       this%position(3) = SIGN((ABS(arcmin)/60.0_bp + arcsec/3600.0_bp), REAL(arcmin, bp))
+    ELSE IF (deg == 0 .AND. arcmin == 0) THEN
+       this%position(3) = arcsec/3600.0_bp
+    END IF
+    ! Transform to radians:
+    this%position(3)    = this%position(3) * rad_deg
+
+    CALL checkAngles(this)
+
+    this%velocity       = 0.0_bp
+    this%frame          = "equatorial"
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC_hour
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as the traditional 
+  !! astrometric coordinates, the distance, and a Time object. 
+  !! Coordinate frame is equatorial, and the velocity vector 
+  !! is set to zero.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_hourAndDistance(this, &
+       distance, h, min, sec, deg, arcmin, arcsec, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                 :: distance, sec, arcsec
+    INTEGER, INTENT(in)                  :: h, min, deg, arcmin    
+    TYPE (Time), INTENT(in)              :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL NEW(this, h, min, sec, deg, arcmin, arcsec, t)
+    IF (error) THEN
+       CALL errorMessage("SphericalCoordinates / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    ! Distance:
+    IF (distance < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Negative distance is not allowed.", 1)
+       this%is_initialized = .FALSE.
+       RETURN
+    END IF
+    this%position(1)    = distance
+
+  END SUBROUTINE new_SC_hourAndDistance
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as the longitude,
+  !! latitude, and a Time object. Angles are given in radians.
+  !! Coordinate frame is equatorial, and the distance and the 
+  !! velocity vector are set to zero.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_rad(this, longitude, latitude, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                 :: longitude, latitude
+    TYPE (Time), INTENT(in)              :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%position(1)    = 0.0_bp
+    this%position(2)    = longitude
+    this%position(3)    = latitude
+    this%velocity       = 0.0_bp
+    CALL checkAngles(this)
+    this%frame          = "equatorial"
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC_rad
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as the distance [AU], 
+  !! longitude, latitude, and a Time object. Angles are given in 
+  !! radians. Coordinate frame is equatorial, and the 
+  !! velocity vector is set to zero.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_radAndDistance(this, distance, longitude, &
+       latitude, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                 :: distance, longitude, latitude
+    TYPE (Time), INTENT(in)              :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (distance < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Negative distance is not allowed.", 1)
+       RETURN
+    END IF
+    this%position(1)    = distance
+    this%position(2)    = longitude
+    this%position(3)    = latitude
+    this%velocity       = 0.0_bp
+    CALL checkAngles(this)
+    this%frame          = "equatorial"
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC_radAndDistance
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes object using values given as the position and 
+  !! velocity vectors, the coordinate frame, and a Time object
+  !! for the epoch. 
+  !!
+  !! The vectors contain:
+  !!    - position(1): distance   [AU]
+  !!    - position(2): longitude  [rad]
+  !!    - position(3): latitude   [rad]
+  !!    - velocity(1): ddistance  [AU/d]
+  !!    - velocity(2): dlongitude [rad/d]
+  !!    - velocity(3): dlatitude  [rad/d]
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SC_posAndVel(this, position, velocity, frame, t)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(3), INTENT(in)   :: position, velocity
+    CHARACTER(len=*), INTENT(in)         :: frame
+    TYPE (Time), INTENT(in)              :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (position(1) < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / new", &
+            "Negative distance is not allowed.", 1)
+       RETURN
+    END IF
+    this%position       = position
+    this%velocity       = velocity
+    CALL checkAngles(this)
+    this%frame          = TRIM(frame)
+    this%t              = copy(t)
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_SC_posAndVel
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+
+    this%position       = 0.0_bp
+    this%velocity       = 0.0_bp
+    this%frame          = ""
+    CALL NULLIFY(this%t)
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    TYPE (SphericalCoordinates)             :: copy_SC
+
+    copy_SC%position       = this%position
+    copy_SC%velocity       = this%velocity
+    copy_SC%frame          = this%frame
+    copy_SC%t              = copy(this%t)
+    IF (error) THEN
+       CALL errorMessage("SphericalCoordinates / copy", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    copy_SC%is_initialized = this%is_initialized
+
+  END FUNCTION copy_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of this object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+
+    exist_SC = this%is_initialized
+
+  END FUNCTION exist_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds Gaussian deviates to the coordinates. The new center
+  !! relative to the original coordinates and the standard deviations
+  !! should be given in radians for the angular space coordinates, AUs
+  !! for distance, radians per day for angular velocities and AU per
+  !! day for line-of-sight velocity. Outputs the final values for
+  !! center (which should not change) and deviates.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addMultinormalDeviate_SC(this, mean, covariance)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6), INTENT(in)         :: mean
+    REAL(bp), DIMENSION(6,6), INTENT(in)       :: covariance
+
+    REAL(bp), DIMENSION(6,6)                   :: A, covariance_
+    REAL(bp), DIMENSION(6)                     :: norm, p, deviates
+    REAL(bp)                                   :: cosdelta
+    INTEGER                                    :: i
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / addMultinormalDeviate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Definitions:
+    !
+    ! x      :: multivariate deviate vector
+    ! v      :: normally distributed (0,1) random variables
+    ! SIGMA  :: covariance matrix
+
+    ! sigma RA is larger for a higher declination:
+    covariance_ = covariance
+    cosdelta = COS(this%position(3))
+    IF (ABS(cosdelta) < 10.0_bp*EPSILON(cosdelta)) THEN
+       cosdelta = 10.0_bp*EPSILON(cosdelta)
+    END IF
+    covariance_(2,:) = covariance_(2,:)/cosdelta
+    covariance_(:,2) = covariance_(:,2)/cosdelta
+    DO i=1,6
+       IF (covariance_(i,i) == 0.0_bp) THEN
+          covariance_(i,i) = 1.0_bp
+       END IF
+    END DO
+
+    A = 0.0_bp
+    DO i=1,6
+       A(i,i:6) = covariance_(i,i:6)
+    END DO
+    CALL cholesky_decomposition(A, p, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / addMultinormalDeviate:", &
+            "Cholesky decomposition unsuccessful:", 1)
+       WRITE(stderr,"(A)") TRIM(errstr)
+       RETURN
+    END IF
+    DO i=1,6
+       A(i,i) = p(i)
+    END DO
+
+    ! dx = A v + mean:
+    CALL randomGaussian(norm)
+    deviates = MATMUL(A,norm) + mean
+
+    ! x_new = x_old + dx:
+    this%position = this%position + deviates(1:3)
+    this%velocity = this%velocity + deviates(4:6)
+
+    CALL checkAngles(this)
+
+  END SUBROUTINE addMultinormalDeviate_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Adds uniform deviates to the coordinates. The center relative to
+  !! the original coordinates and the absolute values of the boundary
+  !! values ((i,1)=center, (i,2)=abs(boundary), position i=1:3 and
+  !! velocity i=4:6) should be given in radians for the angular space
+  !! coordinates, AUs for distance, radians per day for angular 
+  !! velocities and AUs per day for line-of-sight velocity.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE addUniformDeviate_SC(this, center_and_absbound)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6,2), INTENT(in)       :: center_and_absbound
+    REAL(bp), DIMENSION(6,2) :: center_and_absbound_
+    REAL(bp), DIMENSION(6) :: ran
+    REAL(bp) :: tmp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / addUniformDeviate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    center_and_absbound_ = center_and_absbound
+
+    ! Error value in RA is larger for a higher declination:
+    tmp = COS(this%position(3))
+    IF (ABS(tmp) < 10.0_bp*EPSILON(tmp)) THEN
+       tmp = 10.0_bp*EPSILON(tmp)
+    END IF
+    center_and_absbound_(2,2) = center_and_absbound_(2,2)/tmp
+
+    ! Multiply the random numbers with the given limits to get the
+    ! final deviates:
+    CALL randomNumber(ran)
+    center_and_absbound_(1:6,2) = &
+         (2.0_bp*ran - 1.0_bp)*center_and_absbound_(1:6,2)
+
+    ! New coordinates = old coordinates + center relative to old
+    ! coordinates + deviates:
+    this%position = this%position + center_and_absbound_(1:3,1) + &
+         center_and_absbound_(1:3,2)
+    this%velocity = this%velocity + center_and_absbound_(4:6,1) + &
+         center_and_absbound_(4:6,2)
+
+    CALL checkAngles(this)
+
+  END SUBROUTINE addUniformDeviate_SC
+
+
+
+
+
+  ! Description:
+  !
+  ! Checks that longitude and latitude are within [0,2pi] and 
+  ! [-pi/2,pi/2], respectively.
+  !
+  SUBROUTINE checkAngles(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+
+    ! 0 <= angle < 2pi :
+    this%position(2)    = MODULO(this%position(2), two_pi)
+
+    ! -pi/2 <= angle <= pi/2 :
+    this%position(3)    = ASIN(SIN(this%position(3)))
+
+  END SUBROUTINE checkAngles
+
+
+
+
+
+  LOGICAL FUNCTION equal_SC(this, that)
+
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    TYPE (SphericalCoordinates), INTENT(in) :: that
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / equal", &
+            "1st object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. that%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / equal", &
+            "2nd object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Designation:
+    IF (.NOT.(this%frame == that%frame)) THEN
+       equal_SC = .FALSE.
+       RETURN
+    END IF
+
+    ! Position:
+    IF (ANY(ABS(this%position - that%position) > EPSILON(this%position(1)))) THEN
+       equal_SC = .FALSE.
+       RETURN
+    END IF
+
+    ! Velocity:
+    IF (ANY(ABS(this%velocity - that%velocity) > EPSILON(this%velocity(1)))) THEN
+       equal_SC = .FALSE.
+       RETURN
+    END IF
+
+    ! Epoch
+    IF (.NOT.equal(this%t,that%t)) THEN
+       equal_SC = .FALSE.
+       RETURN
+    END IF
+
+    ! Assuming that all of the above comparisons are true,
+    ! it can be concluded that the two objects are the same:
+    equal_SC = .TRUE.    
+
+  END FUNCTION equal_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the position vector as [AU,rad,rad,AU/day,rad/day,rad/day].
+  !!
+  !! Returns error if not initialized.
+  !!
+  FUNCTION getCoordinates_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)                  :: getCoordinates_SC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getCoordinates", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getCoordinates_SC(1:3) = this%position
+    getCoordinates_SC(4:6) = this%velocity
+
+  END FUNCTION getCoordinates_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the position vector as [AU,rad,rad].
+  !!
+  !! Returns error if not initialized.
+  !!
+  FUNCTION getPosition_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)            :: getPosition_SC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getPosition", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getPosition_SC = this%position
+
+  END FUNCTION getPosition_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the velocity vector as [AU/day,rad/day,rad/day].
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getVelocity_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    REAL(bp), DIMENSION(3)            :: getVelocity_SC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getVelocity", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getVelocity_SC = this%velocity
+
+  END FUNCTION getVelocity_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns coordinate frame.
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=FRAME_LEN) FUNCTION getFrame_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getFrame", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getFrame_SC = TRIM(this%frame)
+
+  END FUNCTION getFrame_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the epoch as a Time object.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTime_SC(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+    TYPE (Time)                       :: getTime_SC
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getTime_SC = copy(this%t)
+
+  END FUNCTION getTime_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns distance.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getDistance(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getDistance", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getDistance = this%position(1)
+
+  END FUNCTION getDistance
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns longitude (or Right Ascension).
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getLongitude(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getLongitude", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getLongitude = this%position(2)
+
+  END FUNCTION getLongitude
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns latitude (or Declination).
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getLatitude(this)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / getLatitude", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getLatitude = this%position(3)
+
+  END FUNCTION getLatitude
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of SphericalCoordinates-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myscoords => reallocate(myscoords,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_SC_1(array,n)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: reallocate_SC_1, array
+    INTEGER, INTENT(in)                   :: n
+    INTEGER                               :: i, nold, err
+
+    ALLOCATE(reallocate_SC_1(n), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_SC_1 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    DO i=1, MIN(n,nold)
+       reallocate_SC_1(i) = copy(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_SC_1
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of SphericalCoordinates-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! myscoords => reallocate(myscoords,4,2)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_SC_2(array,n,m)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: reallocate_SC_2, array
+    INTEGER, INTENT(in)                   :: n, m
+    INTEGER                               :: i, j, nold, mold, err
+
+    ALLOCATE(reallocate_SC_2(n,m), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_SC_2 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    mold = SIZE(array,dim=2)
+    DO i=1, MIN(n,nold)
+       DO j=1, MIN(m,mold)
+          reallocate_SC_2(i,j) = copy(array(i,j))
+       END DO
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_SC_2
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Rotates position coordinates to equatorial coordinates.
+  !! Optionally, returns partial derivatives between final and initial
+  !! coordinates. An identity matrix is returned if the coordinates
+  !! are not changed, otherwise:
+  !! 
+  !! dr_eq/dr_ec    dr_eq/dlon_ec    dr_eq/dlat_ec    dr_eq/ddr_ec    dr_eq/ddlon_ec    dr_eq/ddlat_ec  
+  !!
+  !! dlon_eq/dr_ec  dlon_eq/dlon_ec  dlon_eq/dlat_ec  dlon_eq/ddr_ec  dlon_eq/ddlon_ec  dlon_eq/ddlat_ec  
+  !!
+  !! dlat_eq/dr_ec  dlat_eq/dlon_ec  dlat_eq/dlat_ec  dlat_eq/ddr_ec  dlat_eq/ddlon_ec  dlat_eq/ddlat_ec  
+  !!
+  !! ddr_eq/dr_ec   ddr_eq/dlon_ec   ddr_eq/dlat_ec   ddr_eq/ddr_ec   ddr_eq/ddlon_ec   ddr_eq/ddlat_ec  
+  !!
+  !! ddlon_eq/dr_ec ddlon_eq/dlon_ec ddlon_eq/dlat_ec ddlon_eq/ddr_ec ddlon_eq/ddlon_ec ddlon_eq/ddlat_ec  
+  !!
+  !! ddlat_eq/dr_ec ddlat_eq/dlon_ec ddlat_eq/dlat_ec ddlat_eq/ddr_ec ddlat_eq/ddlon_ec ddlat_eq/ddlat_ec  
+  !!
+  SUBROUTINE rotateToEquatorial_SC(this, partials)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: partials
+    REAL(bp) :: lon_ec, lat_ec, sin_lon_ec, cos_lon_ec, sin_lat_ec, &
+         cos_lat_ec, sin_lat_eq, cos_lat_eq, sin_lon_eq, cos_lon_eq, &
+         dlon_ec, dlat_ec, sin_eps, cos_eps
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / rotateToEquatorial", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%frame /= "equatorial") THEN
+
+       ! Position
+       lon_ec = this%position(2)
+       lat_ec  = this%position(3)
+       sin_lon_ec = SIN(lon_ec)
+       cos_lon_ec = COS(lon_ec)
+       sin_lat_ec = SIN(lat_ec)
+       cos_lat_ec = COS(lat_ec)
+       sin_eps = SIN(eps)
+       cos_eps = COS(eps)
+       sin_lat_eq = sin_lat_ec*cos_eps + &
+            cos_lat_ec*sin_eps*sin_lon_ec
+       IF (ABS(sin_lat_eq) > 1.0_bp) THEN
+          sin_lat_eq = SIGN(1.0_bp, sin_lat_eq)
+       END IF
+       this%position(3) = ASIN(sin_lat_eq)
+       cos_lat_eq = COS(this%position(3))
+       sin_lon_eq = (-sin_lat_ec*sin_eps + &
+            cos_lat_ec*cos_eps*sin_lon_ec) / &
+            cos_lat_eq
+       cos_lon_eq = cos_lat_ec*cos_lon_ec / &
+            cos_lat_eq
+       this%position(2) = angle(cos_lon_eq, sin_lon_eq)
+
+       ! Velocity
+       dlon_ec = this%velocity(2)
+       dlat_ec  = this%velocity(3)
+       this%velocity(3) = (dlat_ec*cos_lat_ec*cos_eps - &
+            dlat_ec*sin_lat_ec*sin_eps*sin_lon_ec + &
+            dlon_ec*cos_lat_ec*sin_eps*cos_lon_ec) / &
+            cos_lat_eq
+       this%velocity(2) = (dlat_ec*sin_lat_ec*cos_lon_ec + &
+            dlon_ec*cos_lat_ec*sin_lon_ec - &
+            this%velocity(3)*cos_lon_eq*sin_lat_eq) / &
+            (sin_lon_eq*cos_lat_eq)
+
+       CALL checkAngles(this)
+       this%frame = "equatorial"
+
+       IF (PRESENT(partials)) THEN
+          partials(1,:) = (/ 1.0_bp, 0.0_bp, 0.0_bp, 0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(2,:) = (/ 0.0_bp, &
+               cos_lat_ec*sin_lon_ec/(SQRT(1.0_bp-cos_lon_eq**2)*cos_lat_eq), &
+               sin_lat_ec*cos_lon_ec/(SQRT(1.0_bp-cos_lon_eq**2)*cos_lat_eq), &
+               0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(3,:) = (/ 0.0_bp, &
+               cos_lat_ec*sin_eps*cos_lon_ec/SQRT(1.0_bp-sin_lat_eq**2), &
+               (cos_lat_ec*cos_eps-sin_lat_ec*sin_eps*sin_lon_ec)/SQRT(1.0_bp-sin_lat_eq**2), &
+               0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(4,:) = (/ 0.0_bp, 0.0_bp, 0.0_bp, 1.0_bp, 0.0_bp, 0.0_bp /)
+          partials(5,:) = (/ 0.0_bp, &
+               (-dlat_ec*sin_lat_ec*sin_lon_ec+dlon_ec*cos_lat_ec*cos_lon_ec)/(sin_lon_eq*cos_lat_eq), &
+               (dlat_ec*cos_lat_ec*cos_lon_ec-dlon_ec*sin_lat_ec*sin_lon_ec)/(sin_lon_eq*cos_lat_eq), &
+               0.0_bp, &
+               (cos_lat_ec*sin_lon_ec)/(sin_lon_eq*cos_lat_eq), &
+               (sin_lat_ec*cos_lon_ec)/(sin_lon_eq*cos_lat_eq) /)
+          partials(6,:) = (/ 0.0_bp, &
+               (-dlat_ec*sin_lat_ec*sin_eps*cos_lon_ec-dlon_ec*cos_lat_ec*sin_eps*sin_lon_ec)/cos_lat_eq, &
+               (-dlat_ec*sin_lat_ec*cos_eps - &
+               dlat_ec*cos_lat_ec*sin_eps*sin_lon_ec - &
+               dlon_ec*sin_lat_ec*sin_eps*cos_lon_ec)/cos_lat_eq, &
+               0.0_bp, &
+               (cos_lat_ec*sin_eps*cos_lon_ec)/cos_lat_eq, &
+               (cos_lat_ec*cos_eps-sin_lat_ec*sin_eps*sin_lon_ec)/cos_lat_eq /)
+       END IF
+
+    ELSE
+
+       IF (PRESENT(partials)) THEN
+          partials = identity_matrix(6)
+       END IF
+
+    END IF
+
+  END SUBROUTINE rotateToEquatorial_SC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Rotates position coordinates to ecliptic coordinates.
+  !! Optionally, returns partial derivatives between final and initial
+  !! coordinates. An identity matrix is returned if the coordinates
+  !! are not changed, otherwise:
+  !! 
+  !! dr_ec/dr_eq    dr_ec/dlon_eq    dr_ec/dlat_eq    dr_ec/ddr_eq    dr_ec/ddlon_eq    dr_ec/ddlat_eq  
+  !!
+  !! dlon_ec/dr_eq  dlon_ec/dlon_eq  dlon_ec/dlat_eq  dlon_ec/ddr_eq  dlon_ec/ddlon_eq  dlon_ec/ddlat_eq  
+  !!
+  !! dlat_ec/dr_eq  dlat_ec/dlon_eq  dlat_ec/dlat_eq  dlat_ec/ddr_eq  dlat_ec/ddlon_eq  dlat_ec/ddlat_eq  
+  !!
+  !! ddr_ec/dr_eq   ddr_ec/dlon_eq   ddr_ec/dlat_eq   ddr_ec/ddr_eq   ddr_ec/ddlon_eq   ddr_ec/ddlat_eq  
+  !!
+  !! ddlon_ec/dr_eq ddlon_ec/dlon_eq ddlon_ec/dlat_eq ddlon_ec/ddr_eq ddlon_ec/ddlon_eq ddlon_ec/ddlat_eq  
+  !!
+  !! ddlat_ec/dr_eq ddlat_ec/dlon_eq ddlat_ec/dlat_eq ddlat_ec/ddr_eq ddlat_ec/ddlon_eq ddlat_ec/ddlat_eq  
+  !!
+  SUBROUTINE rotateToEcliptic_SC(this, partials)
+
+    IMPLICIT NONE
+    TYPE (SphericalCoordinates), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL :: partials
+    REAL(bp) :: lon_eq, lat_eq, sin_lon_eq, cos_lon_eq, sin_lat_eq, &
+         cos_lat_eq, sin_lat_ec, cos_lat_ec, sin_lon_ec, cos_lon_ec, &
+         dlon_eq, dlat_eq, sin_eps, cos_eps
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("SphericalCoordinates / rotateToEcliptic", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%frame /= "ecliptic") THEN
+
+       ! Position
+       lon_eq = this%position(2)
+       lat_eq  = this%position(3)
+       sin_lon_eq = SIN(lon_eq)
+       cos_lon_eq = COS(lon_eq)
+       sin_lat_eq = SIN(lat_eq)
+       cos_lat_eq = COS(lat_eq)
+       sin_eps = SIN(eps)
+       cos_eps = COS(eps)
+       sin_lat_ec = sin_lat_eq*cos_eps - &
+            cos_lat_eq*sin_eps*sin_lon_eq
+       IF (ABS(sin_lat_ec) > 1.0_bp) THEN
+          sin_lat_ec = SIGN(1.0_bp, sin_lat_ec)
+       END IF
+       this%position(3) = ASIN(sin_lat_ec)
+       cos_lat_ec = COS(this%position(3))
+       sin_lon_ec = (sin_lat_eq*sin_eps + &
+            cos_lat_eq*cos_eps*sin_lon_eq) / &
+            cos_lat_ec
+       cos_lon_ec = cos_lat_eq*cos_lon_eq / &
+            cos_lat_ec
+       this%position(2) = angle(cos_lon_ec, sin_lon_ec)
+
+       ! Velocity
+       dlon_eq = this%velocity(2)
+       dlat_eq  = this%velocity(3)
+       this%velocity(3) = (dlat_eq*cos_lat_eq*cos_eps + &
+            dlat_eq*sin_lat_eq*sin_eps*sin_lon_eq - &
+            dlon_eq*cos_lat_eq*sin_eps*cos_lon_eq) / &
+            cos_lat_ec
+       this%velocity(2) = (dlat_eq*sin_lat_eq*cos_lon_eq + &
+            dlon_eq*cos_lat_eq*sin_lon_eq - &
+            this%velocity(3)*cos_lon_ec*sin_lat_ec) / &
+            (sin_lon_ec*cos_lat_ec)
+
+       CALL checkAngles(this)
+       this%frame = "ecliptic"
+
+       IF (PRESENT(partials)) THEN
+          partials(1,:) = (/ 1.0_bp, 0.0_bp, 0.0_bp, 0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(2,:) = (/ 0.0_bp, &
+               cos_lat_eq*sin_lon_eq/(SQRT(1.0_bp-cos_lon_ec**2)*cos_lat_ec), &
+               sin_lat_eq*cos_lon_eq/(SQRT(1.0_bp-cos_lon_ec**2)*cos_lat_ec), &
+               0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(3,:) = (/ 0.0_bp, &
+               -cos_lat_eq*sin_eps*cos_lon_eq/SQRT(1.0_bp-sin_lat_ec**2), &
+               (cos_lat_eq*cos_eps+sin_lat_eq*sin_eps*sin_lon_eq)/SQRT(1.0_bp-sin_lat_ec**2), &
+               0.0_bp, 0.0_bp, 0.0_bp /)
+          partials(4,:) = (/ 0.0_bp, 0.0_bp, 0.0_bp, 1.0_bp, 0.0_bp, 0.0_bp /)
+          partials(5,:) = (/ 0.0_bp, &
+               (-dlat_eq*sin_lat_eq*sin_lon_eq+dlon_eq*cos_lat_eq*cos_lon_eq)/(sin_lon_ec*cos_lat_ec), &
+               (dlat_eq*cos_lat_eq*cos_lon_eq-dlon_eq*sin_lat_eq*sin_lon_eq)/(sin_lon_ec*cos_lat_ec), &
+               0.0_bp, &
+               (cos_lat_eq*sin_lon_eq)/(sin_lon_ec*cos_lat_ec), &
+               (sin_lat_eq*cos_lon_eq)/(sin_lon_ec*cos_lat_ec) /)
+          partials(6,:) = (/ 0.0_bp, &
+               (dlat_eq*sin_lat_eq*sin_eps*cos_lon_eq+dlon_eq*cos_lat_eq*sin_eps*sin_lon_eq)/cos_lat_ec, &
+               (-dlat_eq*sin_lat_eq*cos_eps + &
+               dlat_eq*cos_lat_eq*sin_eps*sin_lon_eq + &
+               dlon_eq*sin_lat_eq*sin_eps*cos_lon_eq)/cos_lat_ec, &
+               0.0_bp, &
+               (-cos_lat_eq*sin_eps*cos_lon_eq)/cos_lat_ec, &
+               (cos_lat_eq*cos_eps+sin_lat_eq*sin_eps*sin_lon_eq)/cos_lat_ec /)
+       END IF
+
+    ELSE
+
+       IF (PRESENT(partials)) THEN
+          partials = identity_matrix(6)
+       END IF
+
+    END IF
+
+  END SUBROUTINE rotateToEcliptic_SC
+
+
+
+
+END MODULE SphericalCoordinates_cl
Index: trunk/mops/oorb/classes/StochasticOrbit_class.f90
===================================================================
--- trunk/mops/oorb/classes/StochasticOrbit_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/StochasticOrbit_class.f90	(revision 34646)
@@ -0,0 +1,17859 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012   !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*: 
+!!  
+!! Type and routines for stochastic orbits (that is, orbital elements
+!! with their uncertainties). Contains the algorithms for the
+!! [statistical orbital] ranging method and the least-squares method.
+!!
+!! @author MG, JV, KM, DO 
+!! @version 2012-04-03
+!!  
+MODULE StochasticOrbit_cl
+
+  USE Base_cl
+  USE Orbit_cl
+  USE Observations_cl
+  USE SphericalCoordinates_cl
+  USE CartesianCoordinates_cl
+  USE Time_cl
+
+  USE planetary_data
+  USE linal
+  USE estimators
+  USE statistics
+
+  IMPLICIT NONE
+  !! Default bound for equivalent chi2-difference. Change it through
+  !! setParameters!
+  !! E.g., 50.0 corresponds to probability mass (1 - 4.7e-9).  
+  !! E.g., 30.0 corresponds to probability mass (1 - ?).
+  !! E.g., 20.1 corresponds to probability mass 0.9973 which
+  !!  corresponds to the 1D 3-sigma confidence limits
+  REAL(bp), PARAMETER, PRIVATE :: dchi2       = 20.1_bp    
+  !! Maximum end value for histogram.
+  REAL(bp), PARAMETER, PRIVATE :: histo_end   = 0.3_bp     
+  !! Maximum number of orbits to be processed simultaneously.
+  INTEGER, PARAMETER, PRIVATE  :: norb_simult_max = 5000
+
+  PRIVATE :: new_SO
+  PRIVATE :: new_SO_observations
+  PRIVATE :: new_SO_orb_arr
+  PRIVATE :: nullify_SO
+  PRIVATE :: copy_SO
+  PRIVATE :: exist_SO
+  PRIVATE :: getApoapsisDistance_SO
+  PRIVATE :: getEphemerides_SO
+  PRIVATE :: getEphemeris_SO
+  PRIVATE :: getID_SO
+  PRIVATE :: getCovarianceMatrix_SO
+  PRIVATE :: getParameters_SO
+  PRIVATE :: getPeriapsisDistance_SO
+  PRIVATE :: getPhaseAngle_SO_pdf
+  PRIVATE :: getPhaseAngle_SO_point
+  PRIVATE :: getPhaseAngles_SO
+  PRIVATE :: getObservationMasks_SO
+  PRIVATE :: getRangeBounds_SO
+  PRIVATE :: getResiduals_SO_obss
+  PRIVATE :: getResiduals_SO_orb
+  PRIVATE :: getResults_SO
+  PRIVATE :: getSampleOrbit_SO
+  PRIVATE :: getStandardDeviations_SO
+  PRIVATE :: propagate_SO
+  PRIVATE :: setObservationMask_one
+  PRIVATE :: setObservationMask_all
+  PRIVATE :: setObservationMask_all_notes
+  PRIVATE :: setObservationPair_default
+  PRIVATE :: setObservationPair_pair
+  PRIVATE :: setParameters_SO
+  PRIVATE :: toCartesian_SO
+  PRIVATE :: toKeplerian_SO
+
+  TYPE StochasticOrbit
+     PRIVATE
+     TYPE (Time)                         :: t_inv_prm
+     TYPE (Orbit), DIMENSION(:), POINTER :: orb_arr_cmp            => NULL()
+     TYPE (Orbit)                        :: orb_ml_cmp
+     TYPE (Observations)                 :: obss
+     CHARACTER(len=DESIGNATION_LEN)      :: id_prm                 = " "
+     CHARACTER(len=ELEMENT_TYPE_LEN)     :: cov_type_prm           = " "
+     CHARACTER(len=ELEMENT_TYPE_LEN)     :: element_type_prm       = "cartesian"
+     REAL(bp), DIMENSION(:,:,:), POINTER :: res_arr_cmp            => NULL()
+     REAL(bp), DIMENSION(:,:), POINTER   :: cov_ml_cmp             => NULL()
+     REAL(bp), DIMENSION(:,:), POINTER   :: rms_arr_cmp            => NULL()
+     REAL(bp), DIMENSION(:,:), POINTER   :: res_accept_prm         => NULL()
+     REAL(bp), DIMENSION(:,:), POINTER   :: jac_arr_cmp            => NULL()
+     REAL(bp), DIMENSION(:), POINTER     :: rchi2_arr_cmp          => NULL()
+     REAL(bp), DIMENSION(:), POINTER     :: pdf_arr_cmp            => NULL()
+     REAL(bp), DIMENSION(:), POINTER     :: reg_apr_arr_cmp        => NULL()
+     REAL(bp)                            :: chi2_min_init_prm      = -1.0_bp
+     REAL(bp)                            :: dchi2_prm              = dchi2
+     REAL(bp)                            :: chi2_min_prm           = -1.0_bp
+     REAL(bp)                            :: chi2_min_cmp           = -1.0_bp
+     REAL(bp)                            :: accept_multiplier_prm  = -1.0_bp
+     REAL(bp)                            :: outlier_multiplier_prm = -1.0_bp
+     INTEGER, DIMENSION(:), POINTER      :: repetition_arr_cmp     => NULL()
+     LOGICAL, DIMENSION(:,:), POINTER    :: obs_masks_prm          => NULL()
+     LOGICAL                             :: outlier_rejection_prm  = .FALSE.
+     LOGICAL                             :: regularization_prm     = .TRUE.
+     LOGICAL                             :: jacobians_prm          = .TRUE.
+     LOGICAL                             :: multiple_obj_prm       = .FALSE.
+     LOGICAL                             :: is_initialized_prm     = .FALSE.
+     LOGICAL                             :: dchi2_rejection_prm        = .TRUE.
+     LOGICAL                             :: mh_acceptance_prm        = .FALSE.
+     LOGICAL                             :: generat_gaussian_deviates_prm = .TRUE.
+     REAL(bp)                            :: generat_multiplier_prm = -1.0_bp
+
+     ! Bayesian informative apriori assumptions
+     REAL(bp)                            :: apriori_a_max_prm             = 500.0
+     REAL(bp)                            :: apriori_a_min_prm             = planetary_radii(11)
+     REAL(bp)                            :: apriori_periapsis_max_prm     = -1.0_bp
+     REAL(bp)                            :: apriori_periapsis_min_prm     = -1.0_bp
+     REAL(bp)                            :: apriori_apoapsis_max_prm      = -1.0_bp
+     REAL(bp)                            :: apriori_apoapsis_min_prm      = -1.0_bp
+     REAL(bp)                            :: apriori_rho_max_prm           = 200.0_bp
+     REAL(bp)                            :: apriori_rho_min_prm           = 0.0_bp
+     REAL(bp)                            :: apriori_hcentric_dist_max_prm = 200.0_bp
+     REAL(bp)                            :: apriori_hcentric_dist_min_prm = planetary_radii(11)
+     REAL(bp)                            :: apriori_velocity_max_prm      = 0.12_bp
+     LOGICAL                             :: informative_apriori_prm       = .TRUE.
+
+     ! Parameters for propagation:
+     CHARACTER(len=DYN_MODEL_LEN)        :: dyn_model_prm        = "2-body"
+     CHARACTER(len=INTEGRATOR_LEN)       :: integrator_prm       = "gauss-radau"
+     REAL(bp), DIMENSION(:), POINTER     :: finite_diff_prm      => NULL()
+     REAL(bp)                            :: integration_step_prm = 1.0_bp
+     LOGICAL, DIMENSION(10)              :: perturbers_prm       = .FALSE.
+
+     ! Parameters for statistical ranging:
+     CHARACTER(len=64)                   :: sor_2point_method_prm      = "continued fraction"
+     CHARACTER(len=64)                   :: sor_2point_method_sw_prm   = "continued fraction"
+     REAL(bp), DIMENSION(:,:,:), POINTER :: sor_deviates_prm           => NULL()
+     REAL(bp), DIMENSION(:,:), POINTER   :: sor_rho_arr_cmp            => NULL()
+     REAL(bp), DIMENSION(:), POINTER     :: sor_pair_histo_prm         => NULL()
+     REAL(bp), DIMENSION(2,2)            :: sor_rho_prm                = -1.0_bp
+     REAL(bp), DIMENSION(2,2)            :: sor_rho_cmp                = -1.0_bp
+     INTEGER, DIMENSION(:,:), POINTER    :: sor_pair_arr_prm           => NULL()
+     INTEGER                             :: sor_ntrial_prm             = -1
+     INTEGER                             :: sor_ntrial_cmp             = -1
+     INTEGER                             :: sor_norb_prm               = -1
+     INTEGER                             :: sor_norb_cmp               = -1
+     INTEGER                             :: sor_ntrial_sw_prm          = -1
+     INTEGER                             :: sor_ntrial_sw_cmp          = -1
+     INTEGER                             :: sor_norb_sw_prm            = -1
+     INTEGER                             :: sor_norb_sw_cmp            = -1
+     INTEGER                             :: sor_niter_cmp              = -1
+     INTEGER                             :: sor_niter_prm              = -1
+     INTEGER                             :: sor_rho_histo_cmp          = 1
+     LOGICAL, DIMENSION(4)               :: sor_iterate_bounds_prm     = .TRUE.
+     LOGICAL                             :: sor_random_obs_prm         = .FALSE.
+     ! Allow generation of rho from Gaussian p.d.f.
+     ! NOTE: only applicable to first statisticalRanging in autoSR!
+     LOGICAL                             :: sor_gaussian_pdf_prm       = .FALSE.
+
+     ! Parameters for VoV:
+     REAL(bp), DIMENSION(:,:), POINTER   :: vov_map_cmp           => NULL()
+     REAL(bp), DIMENSION(6,2)            :: vov_scaling_prm       = -1.0_bp
+     REAL(bp), DIMENSION(6,2)            :: vov_scaling_cmp       = -1.0_bp
+     INTEGER                             :: vov_norb_prm          = -1
+     INTEGER                             :: vov_norb_iter_prm     = -1
+     INTEGER                             :: vov_norb_cmp          = -1
+     INTEGER                             :: vov_ntrial_prm        = -1
+     INTEGER                             :: vov_ntrial_iter_prm   = -1
+     INTEGER                             :: vov_ntrial_cmp        = -1
+     INTEGER                             :: vov_niter_prm         = -1
+     INTEGER                             :: vov_niter_cmp         = -1
+     INTEGER                             :: vov_nmap_prm          = -1
+     LOGICAL, DIMENSION(6)               :: vov_mapping_mask_prm  = &
+          (/ .TRUE., .FALSE., .FALSE., .FALSE., .FALSE., .FALSE. /)
+     LOGICAL, DIMENSION(6,2)             :: vov_scaling_ready_cmp = &
+          .FALSE.
+
+     ! Parameters for VOMCMC:
+     REAL(bp), DIMENSION(:,:), POINTER   :: vomcmc_map_cmp           => NULL()
+     REAL(bp), DIMENSION(6,2)            :: vomcmc_scaling_prm       = -1.0_bp
+     REAL(bp), DIMENSION(6,2)            :: vomcmc_scaling_cmp       = -1.0_bp
+     INTEGER                             :: vomcmc_norb_prm          = -1
+     INTEGER                             :: vomcmc_norb_iter_prm     = -1
+     INTEGER                             :: vomcmc_norb_cmp          = -1
+     INTEGER                             :: vomcmc_ntrial_prm        = -1
+     INTEGER                             :: vomcmc_ntrial_iter_prm   = -1
+     INTEGER                             :: vomcmc_ntrial_cmp        = -1
+     INTEGER                             :: vomcmc_niter_prm         = -1
+     INTEGER                             :: vomcmc_niter_cmp         = -1
+     INTEGER                             :: vomcmc_nmap_prm          = -1
+     LOGICAL, DIMENSION(6)               :: vomcmc_mapping_mask_prm  = &
+          (/ .TRUE., .FALSE., .FALSE., .FALSE., .FALSE., .FALSE. /)
+     LOGICAL, DIMENSION(6,2)             :: vomcmc_scaling_ready_cmp = &
+          .FALSE.
+
+     ! Parameters for the least-squares fitting:
+     REAL(bp)                            :: ls_corr_fac_prm         = 1.0_bp
+     REAL(bp)                            :: ls_rchi2_diff_tresh_prm = 0.00001_bp
+     REAL(bp)                            :: ls_rchi2_acceptable_prm = 1.5_bp
+     INTEGER                             :: ls_niter_major_max_prm  = 10
+     INTEGER                             :: ls_niter_major_min_prm  = 2
+     INTEGER                             :: ls_niter_minor_prm      = 20
+     LOGICAL, DIMENSION(6)               :: ls_elem_mask_prm        = .TRUE.
+
+     ! Parameters for the covariance sampling:
+     REAL(bp)                            :: cos_nsigma_prm   = 7.5_bp
+     INTEGER                             :: cos_norb_prm     = 100
+     INTEGER                             :: cos_ntrial_prm   = 100000
+     LOGICAL                             :: cos_gaussian_prm = .FALSE.
+
+     ! Parameters for simplex optimization:
+     REAL(bp)                            :: smplx_tol_prm  = 1.05_bp
+     REAL(bp)                            :: smplx_similarity_tol_prm = 0.0001
+     INTEGER                             :: smplx_niter_prm = 1000
+     INTEGER                             :: smplx_niter_cmp
+     LOGICAL                             :: smplx_force_prm = .FALSE.
+
+     ! Parameters for MCMC observation sampling:
+     INTEGER                             :: os_norb_prm = 500
+     INTEGER                             :: os_ntrial_prm = 5000
+     INTEGER                             :: os_sampling_type_prm = 1
+
+  END TYPE StochasticOrbit
+
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_SO
+     MODULE PROCEDURE new_SO_observations
+     MODULE PROCEDURE new_SO_orb_cov
+     MODULE PROCEDURE new_SO_orb_arr
+  END INTERFACE NEW
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_SO
+  END INTERFACE NULLIFY
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_SO
+  END INTERFACE copy
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_SO
+  END INTERFACE exist
+
+  INTERFACE getApoapsisDistance
+     MODULE PROCEDURE getApoapsisDistance_SO
+  END INTERFACE getApoapsisDistance
+
+  INTERFACE getChi2
+     MODULE PROCEDURE getChi2_matrix
+     MODULE PROCEDURE getChi2_this_orb
+  END INTERFACE getChi2
+
+  INTERFACE getCovarianceMatrix
+     MODULE PROCEDURE getCovarianceMatrix_SO
+  END INTERFACE getCovarianceMatrix
+
+  INTERFACE getEphemerides
+     MODULE PROCEDURE getEphemerides_SO
+  END INTERFACE getEphemerides
+
+  INTERFACE getEphemeris
+     MODULE PROCEDURE getEphemeris_SO
+  END INTERFACE getEphemeris
+
+  INTERFACE getID
+     MODULE PROCEDURE getID_SO
+  END INTERFACE getID
+
+  INTERFACE getParameters
+     MODULE PROCEDURE getParameters_SO
+  END INTERFACE getParameters
+
+  INTERFACE getPeriapsisDistance
+     MODULE PROCEDURE getPeriapsisDistance_SO
+  END INTERFACE getPeriapsisDistance
+
+  INTERFACE getPhaseAngle
+     MODULE PROCEDURE getPhaseAngle_SO_pdf
+     MODULE PROCEDURE getPhaseAngle_SO_point
+  END INTERFACE getPhaseAngle
+
+  INTERFACE getPhaseAngles
+     MODULE PROCEDURE getPhaseAngles_SO
+  END INTERFACE getPhaseAngles
+
+  INTERFACE getObservationMasks
+     MODULE PROCEDURE getObservationMasks_SO
+  END INTERFACE getObservationMasks
+
+  INTERFACE getRangeBounds
+     MODULE PROCEDURE getRangeBounds_SO
+  END INTERFACE getRangeBounds
+
+  INTERFACE getResiduals
+     MODULE PROCEDURE getResiduals_SO_obss
+     MODULE PROCEDURE getResiduals_SO_orb
+  END INTERFACE getResiduals
+
+  INTERFACE getResults
+     MODULE PROCEDURE getResults_SO
+  END INTERFACE getResults
+
+  INTERFACE getRMS
+     MODULE PROCEDURE getRMS_single
+  END INTERFACE getRMS
+
+  INTERFACE getSampleOrbit
+     MODULE PROCEDURE getSampleOrbit_SO
+  END INTERFACE getSampleOrbit
+
+  INTERFACE getStandardDeviations
+     MODULE PROCEDURE getStandardDeviations_SO
+  END INTERFACE getStandardDeviations
+
+  INTERFACE leastSquares
+     MODULE PROCEDURE leastSquares_SO
+  END INTERFACE leastSquares
+
+  INTERFACE levenbergMarquardt
+     MODULE PROCEDURE levenbergMarquardt_SO
+  END INTERFACE levenbergMarquardt
+
+  INTERFACE getTime
+     MODULE PROCEDURE getTime_SO
+  END INTERFACE getTime
+
+  INTERFACE propagate
+     MODULE PROCEDURE propagate_SO
+  END INTERFACE propagate
+
+  INTERFACE setAcceptanceWindow
+     MODULE PROCEDURE setAcceptanceWindow_sigma
+  END INTERFACE setAcceptanceWindow
+
+  INTERFACE setObservationMask
+     MODULE PROCEDURE setObservationMask_one
+     MODULE PROCEDURE setObservationMask_all
+     MODULE PROCEDURE setObservationMask_all_notes
+  END INTERFACE setObservationMask
+
+  INTERFACE setObservationPair
+     MODULE PROCEDURE setObservationPair_default
+     MODULE PROCEDURE setObservationPair_pair
+  END INTERFACE setObservationPair
+
+  INTERFACE setParameters
+     MODULE PROCEDURE setParameters_SO
+  END INTERFACE setParameters
+
+  INTERFACE setRangeBounds
+     MODULE PROCEDURE setRangeBounds_3sigma
+     MODULE PROCEDURE setRangeBounds_values
+  END INTERFACE setRangeBounds
+
+  INTERFACE toCartesian
+     MODULE PROCEDURE toCartesian_SO
+  END INTERFACE toCartesian
+
+  INTERFACE toCometary
+     MODULE PROCEDURE toCometary_SO
+  END INTERFACE toCometary
+
+  INTERFACE toKeplerian
+     MODULE PROCEDURE toKeplerian_SO
+  END INTERFACE toKeplerian
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+
+    IF (this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%is_initialized_prm = .TRUE.
+
+  END SUBROUTINE new_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SO_observations(this, obss)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Observations), INTENT(in)       :: obss
+
+    IF (this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF(.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Observations not intialized.", 1)
+       RETURN
+    END IF
+
+    this%obss = copy(obss)
+    this%obs_masks_prm => getObservationMasks(this%obss)
+
+    ! Initialize other variables needed in the computation
+    this%is_initialized_prm = .TRUE.
+    CALL setObservationPair(this)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE new_SO_observations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_SO_orb_cov(this, orb, cov, cov_type, &
+       element_type, obss, id)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)     :: this
+    TYPE (Orbit), INTENT(in)                  :: orb
+    CHARACTER(len=*), INTENT(in)              :: cov_type
+    REAL(bp), DIMENSION(6,6), INTENT(in)      :: cov
+    CHARACTER(len=*), INTENT(in), OPTIONAL    :: element_type
+    TYPE (Observations), INTENT(in), OPTIONAL :: obss
+    CHARACTER(len=*), INTENT(in), OPTIONAL    :: id
+    INTEGER                                   :: err
+
+    IF (this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(obss)) THEN
+       IF(.NOT. exist(obss)) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / new", &
+               "Observations not intialized.", 1)
+          RETURN
+       END IF
+       this%obss = copy(obss)
+       this%obs_masks_prm => getObservationMasks(this%obss)
+    END IF
+    ALLOCATE(this%cov_ml_cmp(6,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    ! Initialize other variables needed in the computation
+    this%orb_ml_cmp = copy(orb)
+    this%cov_ml_cmp = cov
+    this%cov_type_prm = cov_type
+    IF (PRESENT(element_type)) THEN
+       this%element_type_prm = element_type
+    ELSE
+       this%element_type_prm = "cartesian"
+    END IF
+    this%is_initialized_prm = .TRUE.
+    IF (PRESENT(obss)) THEN
+       CALL setObservationPair(this)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit /  new", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(id)) THEN
+       this%id_prm = id 
+    END IF
+
+  END SUBROUTINE new_SO_orb_cov
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+
+  SUBROUTINE new_SO_orb_arr(this, orb_arr, pdf_arr, element_type, &
+       jac_arr, reg_apr_arr, rchi2_arr, repetition_arr)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)          :: this
+    TYPE (Orbit), DIMENSION(:), INTENT(in)         :: orb_arr
+    CHARACTER(len=*), INTENT(in)                   :: element_type
+    REAL(bp), DIMENSION(:), INTENT(in)             :: pdf_arr
+    REAL(bp), DIMENSION(:,:), INTENT(in), OPTIONAL :: jac_arr
+    REAL(bp), DIMENSION(:), INTENT(in), OPTIONAL   :: reg_apr_arr
+    REAL(bp), DIMENSION(:), INTENT(in), OPTIONAL   :: rchi2_arr
+    INTEGER, DIMENSION(:), INTENT(in), OPTIONAL    :: repetition_arr
+
+    INTEGER :: i, err
+
+    IF (this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    this%sor_norb_cmp = SIZE(orb_arr, dim=1)
+    ALLOCATE(this%orb_arr_cmp(this%sor_norb_cmp), &
+         this%pdf_arr_cmp(this%sor_norb_cmp), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / new", &
+            "Could not allocate pointer (5).", 1)
+       RETURN
+    END IF
+    DO i=1,this%sor_norb_cmp
+       this%orb_arr_cmp(i) = copy(orb_arr(i))
+       this%pdf_arr_cmp(i) = pdf_arr(i)
+    END DO
+    IF (PRESENT(jac_arr)) THEN
+       ALLOCATE(this%jac_arr_cmp(this%sor_norb_cmp,3), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / new", &
+               "Could not allocate pointer (10).", 1)
+          RETURN
+       END IF
+       DO i=1,this%sor_norb_cmp
+          this%jac_arr_cmp(i,1) = jac_arr(i,1)
+          this%jac_arr_cmp(i,2) = jac_arr(i,2)
+          this%jac_arr_cmp(i,3) = jac_arr(i,3)
+       END DO
+    END IF
+    IF (PRESENT(rchi2_arr)) THEN
+       ALLOCATE(this%rchi2_arr_cmp(this%sor_norb_cmp), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / new", &
+               "Could not allocate pointer (15).", 1)
+          RETURN
+       END IF
+       this%rchi2_arr_cmp = rchi2_arr
+    END IF
+    IF (PRESENT(reg_apr_arr)) THEN
+       ALLOCATE(this%reg_apr_arr_cmp(this%sor_norb_cmp), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / new", &
+               "Could not allocate pointer (20).", 1)
+          RETURN
+       END IF
+       this%reg_apr_arr_cmp = reg_apr_arr
+    END IF
+    IF (PRESENT(repetition_arr)) THEN
+       ALLOCATE(this%repetition_arr_cmp(this%sor_norb_cmp), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / new", &
+               "Could not allocate pointer (25).", 1)
+          RETURN
+       END IF
+       this%repetition_arr_cmp = repetition_arr
+    END IF
+    this%element_type_prm = element_type
+    this%is_initialized_prm = .TRUE.
+
+  END SUBROUTINE new_SO_orb_arr
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  SUBROUTINE nullify_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    INTEGER :: i, err
+
+    CALL NULLIFY(this%t_inv_prm)
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+    END IF
+    CALL NULLIFY(this%orb_ml_cmp)
+    CALL NULLIFY(this%obss)
+    this%element_type_prm = "cartesian"
+    this%cov_type_prm = " "
+    IF (ASSOCIATED(this%res_arr_cmp)) THEN
+       DEALLOCATE(this%res_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%res_accept_prm)) THEN
+       DEALLOCATE(this%res_accept_prm, stat=err)
+    END IF
+    IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+       DEALLOCATE(this%cov_ml_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%rms_arr_cmp)) THEN
+       DEALLOCATE(this%rms_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%reg_apr_arr_cmp)) THEN
+       DEALLOCATE(this%reg_apr_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%jac_arr_cmp)) THEN
+       DEALLOCATE(this%jac_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%repetition_arr_cmp)) THEN
+       DEALLOCATE(this%repetition_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%obs_masks_prm)) THEN
+       DEALLOCATE(this%obs_masks_prm, stat=err)
+    END IF
+    this%chi2_min_init_prm = -1.0_bp
+    this%chi2_min_prm = -1.0_bp
+    this%dchi2_prm = dchi2
+    this%accept_multiplier_prm = -1.0_bp
+    this%outlier_rejection_prm = .FALSE.
+    this%regularization_prm = .TRUE.
+    this%jacobians_prm = .TRUE.
+    this%multiple_obj_prm = .FALSE.
+
+    ! Bayesian apriori parameters
+    this%apriori_a_max_prm = 500.0
+    this%apriori_a_min_prm = planetary_radii(11)
+    this%apriori_periapsis_max_prm = -1.0_bp
+    this%apriori_periapsis_min_prm = -1.0_bp
+    this%apriori_apoapsis_max_prm = -1.0_bp
+    this%apriori_apoapsis_min_prm = -1.0_bp
+    this%apriori_rho_max_prm = 200.0_bp
+    this%apriori_rho_min_prm = 0.0_bp
+    this%informative_apriori_prm = .TRUE.
+
+    ! Propagation parameters
+    this%dyn_model_prm = "2-body"
+    this%integrator_prm = "gauss-radau"
+    IF (ASSOCIATED(this%finite_diff_prm)) THEN
+       DEALLOCATE(this%finite_diff_prm, stat=err)
+    END IF
+    this%integration_step_prm = 1.0_bp 
+    this%perturbers_prm = .FALSE.
+
+    ! Ranging variables
+    this%sor_2point_method_prm = "continued fraction"
+    this%sor_2point_method_sw_prm = "continued fraction"
+    IF (ASSOCIATED(this%sor_deviates_prm)) THEN
+       DEALLOCATE(this%sor_deviates_prm, stat=err)
+    END IF
+    IF (ASSOCIATED(this%sor_rho_arr_cmp)) THEN
+       DEALLOCATE(this%sor_rho_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%sor_pair_histo_prm)) THEN
+       DEALLOCATE(this%sor_pair_histo_prm, stat=err)
+    END IF
+    this%sor_rho_prm = -1.0_bp
+    this%sor_rho_cmp = -1.0_bp
+    this%generat_multiplier_prm = -1.0_bp
+    IF (ASSOCIATED(this%sor_pair_arr_prm)) THEN
+       DEALLOCATE(this%sor_pair_arr_prm, stat=err)
+    END IF
+    this%sor_ntrial_prm = -1
+    this%sor_ntrial_cmp = -1
+    this%sor_norb_prm = -1
+    this%sor_norb_cmp = -1
+    this%sor_niter_cmp = -1
+    this%sor_niter_prm = -1
+    this%sor_rho_histo_cmp = 1
+    this%sor_random_obs_prm = .FALSE.
+    this%sor_gaussian_pdf_prm = .FALSE.
+    this%dchi2_rejection_prm = .TRUE.
+
+    ! Parameters for VoV:
+    IF (ASSOCIATED(this%vov_map_cmp)) THEN
+       DEALLOCATE(this%vov_map_cmp, stat=err)
+    END IF
+    this%vov_scaling_prm = -1.0_bp
+    this%vov_scaling_cmp = -1.0_bp
+    this%vov_norb_prm = -1
+    this%vov_norb_cmp = -1
+    this%vov_ntrial_prm = -1
+    this%vov_ntrial_cmp = -1
+    this%vov_niter_prm = -1
+    this%vov_niter_cmp = -1
+    this%vov_nmap_prm = -1
+    this%vov_mapping_mask_prm = &
+         (/ .TRUE., .FALSE., .FALSE., .FALSE., .FALSE., .FALSE. /)
+    this%vov_scaling_ready_cmp = .FALSE.
+
+    ! Parameters for VOMCMC:
+    IF (ASSOCIATED(this%vomcmc_map_cmp)) THEN
+       DEALLOCATE(this%vomcmc_map_cmp, stat=err)
+    END IF
+    this%vomcmc_scaling_prm = -1.0_bp
+    this%vomcmc_scaling_cmp = -1.0_bp
+    this%vomcmc_norb_prm = -1
+    this%vomcmc_norb_cmp = -1
+    this%vomcmc_ntrial_prm = -1
+    this%vomcmc_ntrial_cmp = -1
+    this%vomcmc_niter_prm = -1
+    this%vomcmc_niter_cmp = -1
+    this%vomcmc_nmap_prm = -1
+    this%vomcmc_mapping_mask_prm = &
+         (/ .TRUE., .FALSE., .FALSE., .FALSE., .FALSE., .FALSE. /)
+    this%vomcmc_scaling_ready_cmp = .FALSE.
+
+    ! Parameters for the least-squares fit:
+    this%ls_corr_fac_prm = 1.0_bp
+    this%ls_niter_major_max_prm = 10
+    this%ls_niter_major_min_prm = 2
+    this%ls_niter_minor_prm = 20
+    this%ls_elem_mask_prm = .TRUE.
+
+    this%is_initialized_prm = .FALSE.
+
+  END SUBROUTINE nullify_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error if allocation fails.
+  !!
+  FUNCTION copy_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit) :: this
+    TYPE (StochasticOrbit) :: copy_SO
+    INTEGER :: i, err, nobs, norb
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / copy", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    copy_SO%t_inv_prm = copy(this%t_inv_prm) 
+    IF (exist(this%obss)) THEN
+       copy_SO%obss = copy(this%obss)
+       nobs = getNrOfObservations(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / copy", &
+               "TRACE BACK (5).", 1)
+          RETURN
+       END IF
+    END IF
+    norb = SIZE(this%orb_arr_cmp)
+    IF (ASSOCIATED(copy_SO%orb_arr_cmp)) THEN
+       DO i=1,SIZE(copy_SO%orb_arr_cmp)
+          CALL NULLIFY(copy_SO%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(copy_SO%orb_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       ALLOCATE(copy_SO%orb_arr_cmp(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (5).", 1)
+          RETURN
+       END IF
+       DO i=1,norb
+          copy_SO%orb_arr_cmp(i) = copy(this%orb_arr_cmp(i))       
+       END DO
+    END IF
+    copy_SO%orb_ml_cmp = copy(this%orb_ml_cmp)
+    copy_SO%cov_type_prm = this%cov_type_prm
+    IF (ASSOCIATED(this%res_arr_cmp)) THEN
+       ALLOCATE(copy_SO%res_arr_cmp(norb,nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (10).", 1)
+          RETURN
+       END IF
+       copy_SO%res_arr_cmp = this%res_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%res_accept_prm)) THEN
+       ALLOCATE(copy_SO%res_accept_prm(nobs,6))
+       copy_SO%res_accept_prm = this%res_accept_prm
+    END IF
+    IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+       ALLOCATE(copy_SO%cov_ml_cmp(6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (15).", 1)
+          RETURN
+       END IF
+       copy_SO%cov_ml_cmp = this%cov_ml_cmp
+    END IF
+    IF (ASSOCIATED(this%rms_arr_cmp)) THEN
+       ALLOCATE(copy_SO%rms_arr_cmp(norb,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (25).", 1)
+          RETURN
+       END IF
+       copy_SO%rms_arr_cmp = this%rms_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       ALLOCATE(copy_SO%rchi2_arr_cmp(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (30).", 1)
+          RETURN
+       END IF
+       copy_SO%rchi2_arr_cmp = this%rchi2_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       ALLOCATE(copy_SO%pdf_arr_cmp(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (35).", 1)
+          RETURN
+       END IF
+       copy_SO%pdf_arr_cmp = this%pdf_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%reg_apr_arr_cmp)) THEN
+       ALLOCATE(copy_SO%reg_apr_arr_cmp(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (40).", 1)
+          RETURN
+       END IF
+       copy_SO%reg_apr_arr_cmp = this%reg_apr_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%jac_arr_cmp)) THEN
+       ALLOCATE(copy_SO%jac_arr_cmp(norb,3), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (45).", 1)
+          RETURN
+       END IF
+       copy_SO%jac_arr_cmp = this%jac_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%repetition_arr_cmp)) THEN
+       ALLOCATE(copy_SO%repetition_arr_cmp(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (46).", 1)
+          RETURN
+       END IF
+       copy_SO%repetition_arr_cmp = this%repetition_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%obs_masks_prm)) THEN
+       ALLOCATE(copy_SO%obs_masks_prm(nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (20).", 1)
+          RETURN
+       END IF
+       copy_SO%obs_masks_prm = this%obs_masks_prm
+    END IF
+    copy_SO%chi2_min_init_prm = this%chi2_min_init_prm
+    copy_SO%chi2_min_prm = this%chi2_min_prm
+    copy_SO%dchi2_prm = this%dchi2_prm
+    copy_SO%accept_multiplier_prm = this%accept_multiplier_prm
+    copy_SO%outlier_rejection_prm = this%outlier_rejection_prm
+    copy_SO%regularization_prm = this%regularization_prm
+    copy_SO%jacobians_prm = this%jacobians_prm
+    copy_SO%multiple_obj_prm = this%multiple_obj_prm
+    copy_SO%generat_multiplier_prm = this%generat_multiplier_prm
+    copy_SO%generat_gaussian_deviates_prm = this%generat_gaussian_deviates_prm
+
+    ! Bayesian apriori parameters
+    copy_SO%apriori_a_max_prm = this%apriori_a_max_prm
+    copy_SO%apriori_a_min_prm = this%apriori_a_min_prm
+    copy_SO%apriori_periapsis_max_prm = this%apriori_periapsis_max_prm
+    copy_SO%apriori_periapsis_min_prm = this%apriori_periapsis_min_prm
+    copy_SO%apriori_apoapsis_max_prm = this%apriori_apoapsis_max_prm
+    copy_SO%apriori_apoapsis_min_prm = this%apriori_apoapsis_min_prm
+    copy_SO%apriori_rho_min_prm = this%apriori_rho_min_prm
+    copy_SO%informative_apriori_prm = this%informative_apriori_prm
+
+    ! Propagation parameters
+    copy_SO%dyn_model_prm = this%dyn_model_prm
+    copy_SO%integrator_prm = this%integrator_prm
+    IF (ASSOCIATED(this%finite_diff_prm)) THEN
+       ALLOCATE(copy_SO%finite_diff_prm(6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (50).", 1)
+          RETURN
+       END IF
+       copy_SO%finite_diff_prm = this%finite_diff_prm
+    END IF
+    copy_SO%integration_step_prm = this%integration_step_prm
+    copy_SO%perturbers_prm = this%perturbers_prm
+
+    ! Ranging parameters
+    copy_SO%element_type_prm = this%element_type_prm
+    copy_SO%sor_2point_method_prm = this%sor_2point_method_prm
+    copy_SO%sor_2point_method_sw_prm = this%sor_2point_method_sw_prm
+    IF (ASSOCIATED(this%sor_deviates_prm)) THEN
+       ALLOCATE(copy_SO%sor_deviates_prm(nobs,6,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (55).", 1)
+          RETURN
+       END IF
+       copy_SO%sor_deviates_prm = this%sor_deviates_prm
+    END IF
+    IF (ASSOCIATED(this%sor_rho_arr_cmp)) THEN
+       ALLOCATE(copy_SO%sor_rho_arr_cmp(SIZE(this%sor_rho_arr_cmp,dim=1),2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (60).", 1)
+          RETURN
+       END IF
+       copy_SO%sor_rho_arr_cmp = this%sor_rho_arr_cmp
+    END IF
+    IF (ASSOCIATED(this%sor_pair_histo_prm)) THEN
+       ALLOCATE(copy_SO%sor_pair_histo_prm(SIZE(this%sor_pair_histo_prm)), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (65).", 1)
+          RETURN
+       END IF
+       copy_SO%sor_pair_histo_prm = this%sor_pair_histo_prm
+    END IF
+    copy_SO%sor_rho_prm = this%sor_rho_prm
+    copy_SO%sor_rho_cmp = this%sor_rho_cmp
+    IF (ASSOCIATED(this%sor_pair_arr_prm)) THEN
+       ALLOCATE(copy_SO%sor_pair_arr_prm(SIZE(this%sor_pair_arr_prm,dim=1), &
+            SIZE(this%sor_pair_arr_prm,dim=2)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (70).", 1)
+          RETURN
+       END IF
+       copy_SO%sor_pair_arr_prm = this%sor_pair_arr_prm
+    END IF
+    copy_SO%sor_ntrial_prm = this%sor_ntrial_prm
+    copy_SO%sor_ntrial_cmp = this%sor_ntrial_cmp
+    copy_SO%sor_norb_prm = this%sor_norb_prm
+    copy_SO%sor_norb_cmp = this%sor_norb_cmp
+    copy_SO%sor_niter_cmp = this%sor_niter_cmp
+    copy_SO%sor_niter_prm = this%sor_niter_prm
+    copy_SO%sor_rho_histo_cmp = this%sor_rho_histo_cmp
+    copy_SO%sor_random_obs_prm = this%sor_random_obs_prm
+    copy_SO%sor_gaussian_pdf_prm = this%sor_gaussian_pdf_prm
+    copy_SO%dchi2_rejection_prm = this%dchi2_rejection_prm
+
+    ! VoV parameters
+    IF (ASSOCIATED(this%vov_map_cmp)) THEN
+       ALLOCATE(copy_SO%vov_map_cmp(SIZE(this%vov_map_cmp,dim=1), &
+            SIZE(this%vov_map_cmp,dim=2)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (75).", 1)
+          RETURN
+       END IF
+       copy_SO%vov_map_cmp = this%vov_map_cmp
+    END IF
+    copy_SO%vov_scaling_prm = this%vov_scaling_prm
+    copy_SO%vov_scaling_cmp = this%vov_scaling_cmp
+    copy_SO%vov_norb_prm = this%vov_norb_prm
+    copy_SO%vov_norb_cmp = this%vov_norb_cmp
+    copy_SO%vov_ntrial_prm = this%vov_ntrial_prm
+    copy_SO%vov_ntrial_cmp = this%vov_ntrial_cmp
+    copy_SO%vov_niter_prm = this%vov_niter_prm
+    copy_SO%vov_niter_cmp = this%vov_niter_cmp
+    copy_SO%vov_nmap_prm = this%vov_nmap_prm
+    copy_SO%vov_mapping_mask_prm = this%vov_mapping_mask_prm
+    copy_SO%vov_scaling_ready_cmp = this%vov_scaling_ready_cmp
+
+    ! VOMCMC parameters
+    IF (ASSOCIATED(this%vomcmc_map_cmp)) THEN
+       ALLOCATE(copy_SO%vomcmc_map_cmp(SIZE(this%vomcmc_map_cmp,dim=1), &
+            SIZE(this%vomcmc_map_cmp,dim=2)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / copy", &
+               "Could not allocate pointer (75).", 1)
+          RETURN
+       END IF
+       copy_SO%vomcmc_map_cmp = this%vomcmc_map_cmp
+    END IF
+    copy_SO%vomcmc_scaling_prm = this%vomcmc_scaling_prm
+    copy_SO%vomcmc_scaling_cmp = this%vomcmc_scaling_cmp
+    copy_SO%vomcmc_norb_prm = this%vomcmc_norb_prm
+    copy_SO%vomcmc_norb_cmp = this%vomcmc_norb_cmp
+    copy_SO%vomcmc_ntrial_prm = this%vomcmc_ntrial_prm
+    copy_SO%vomcmc_ntrial_cmp = this%vomcmc_ntrial_cmp
+    copy_SO%vomcmc_niter_prm = this%vomcmc_niter_prm
+    copy_SO%vomcmc_niter_cmp = this%vomcmc_niter_cmp
+    copy_SO%vomcmc_nmap_prm = this%vomcmc_nmap_prm
+    copy_SO%vomcmc_mapping_mask_prm = this%vomcmc_mapping_mask_prm
+    copy_SO%vomcmc_scaling_ready_cmp = this%vomcmc_scaling_ready_cmp
+
+    ! Least-squares parameters
+    copy_SO%ls_corr_fac_prm = this%ls_corr_fac_prm
+    copy_SO%ls_niter_major_max_prm = this%ls_niter_major_max_prm
+    copy_SO%ls_niter_major_min_prm = this%ls_niter_major_min_prm
+    copy_SO%ls_niter_minor_prm = this%ls_niter_minor_prm
+    copy_SO%ls_elem_mask_prm = this%ls_elem_mask_prm
+
+    ! Simplex parameters
+    copy_SO%smplx_tol_prm = this%smplx_tol_prm
+    copy_SO%smplx_niter_prm = this%smplx_niter_prm
+    copy_SO%smplx_niter_cmp = this%smplx_niter_cmp
+    copy_SO%smplx_force_prm = this%smplx_force_prm
+    copy_SO%smplx_similarity_tol_prm = this%smplx_similarity_tol_prm
+
+    ! Observation sampling parameters
+    copy_SO%os_norb_prm = this%os_norb_prm
+    copy_SO%os_ntrial_prm = this%os_ntrial_prm
+    copy_SO%os_sampling_type_prm = this%os_sampling_type_prm
+
+    copy_SO%is_initialized_prm = this%is_initialized_prm
+
+  END FUNCTION copy_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  LOGICAL FUNCTION exist_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+
+    exist_SO = this%is_initialized_prm
+
+  END FUNCTION exist_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Automated statistical orbital ranging. By gradually increasing
+  !! the number of sample orbits (10->200->norb_init), the topocentric
+  !! range intervals are iterated until they correspond to an unbiased 
+  !! phase space region of possible orbits.
+  !!
+  !! Returns error.
+  !!
+  !! @author  JV, MG
+  !! @version 2011-08-22
+  !!
+  SUBROUTINE autoStatisticalRanging(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+
+    REAL(bp), DIMENSION(2,2) :: rho_bounds_
+    REAL(bp) :: dchi2, & 
+         ddchi2, & ! difference to the given dchi2 limit
+         chi2_min_final, chi2_min_
+    INTEGER :: niter_, norb_prm 
+    LOGICAL :: dchi2_rejection_prm
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / autoStatisticalRanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%sor_niter_cmp = 0
+    norb_prm = this%sor_norb_prm
+    dchi2_rejection_prm = this%dchi2_rejection_prm    
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "***************"
+       WRITE(stdout,"(2X,A)") "FIRST ITERATION"
+       WRITE(stdout,"(2X,A)") "***************"
+    END IF
+
+    ! Force 10 orbits and uniform pdf in the first step
+    this%sor_norb_prm = 10
+    this%dchi2_rejection_prm = .FALSE.
+    CALL statisticalRanging(this)
+    IF (error .OR. this%sor_norb_cmp <= 1) THEN
+       CALL errorMessage("StochasticOrbit / autoStatisticalRanging", &
+            "First iteration failed.", 1)
+       RETURN
+    END IF
+    this%sor_niter_cmp = 1
+    CALL updateRanging(this, automatic=.TRUE.)
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(1X)")
+       WRITE(stdout,"(2X,A)") "*****************"
+       WRITE(stdout,"(2X,A)") "SECOND ITERATION "
+       WRITE(stdout,"(2X,A)") "*****************"
+    END IF
+
+    ! Force 200 orbits and uniform pdf in the second step
+    this%sor_norb_prm = 200
+    ! Draw rho from uniform p.d.f. regardless of initial choice
+    this%sor_gaussian_pdf_prm = .FALSE.
+    CALL statisticalRanging(this)
+    IF (error .OR. this%sor_norb_cmp <= 1) THEN
+       CALL errorMessage("StochasticOrbit / autoStatisticalRanging", &
+            "Second iteration failed.", 1)
+       RETURN
+    END IF
+    this%sor_niter_cmp = 2
+    CALL updateRanging(this, automatic=.TRUE.)
+
+    ! Return to user-defined pdf mode 
+    this%dchi2_rejection_prm = dchi2_rejection_prm
+
+    ! Additional iteration, if requested nr of orbits very large
+    IF (norb_prm/this%sor_norb_prm >= 50) THEN
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(1X)")
+          WRITE(stdout,"(2X,A)") "********************"
+          WRITE(stdout,"(2X,A)") "ADDITIONAL ITERATION"
+          WRITE(stdout,"(2X,A)") "********************"
+       END IF
+       this%sor_norb_prm = 2000
+       CALL statisticalRanging(this)
+       IF (error .OR. this%sor_norb_cmp <= 1) THEN
+          CALL errorMessage("StochasticOrbit / autoStatisticalRanging", &
+               "Additional iteration failed.", 1)
+          RETURN
+       END IF
+
+       this%sor_niter_cmp = 3
+       CALL updateRanging(this, automatic=.TRUE.)
+    END IF
+
+    ! Final iteration with requested nr of orbits, subsequent iterations if necessary
+    IF (info_verb >= 2) THEN 
+       WRITE(stdout,"(1X)")
+       WRITE(stdout,"(2X,A)") "****************"
+       WRITE(stdout,"(2X,A)") "FINAL ITERATIONS"
+       WRITE(stdout,"(2X,A)") "****************"
+    END IF
+
+    niter_ = this%sor_niter_cmp
+    this%sor_norb_prm  = norb_prm
+    this%sor_rho_histo_cmp = 1
+    ddchi2             = 10.0_bp
+    DO WHILE (this%sor_rho_histo_cmp > 0 .OR. (this%dchi2_rejection_prm .AND. ddchi2 > 2.0_bp))
+
+       IF (this%sor_niter_cmp >= (this%sor_niter_prm + niter_)) THEN
+          EXIT
+       END IF
+
+       CALL statisticalRanging(this)
+       IF (error .OR. this%sor_norb_cmp <= 1) THEN
+          CALL errorMessage("StochasticOrbit / autoStatisticalRanging", &
+               "Subsequent iteration failed.", 1)
+          RETURN
+       END IF
+       dchi2 = MAXVAL(this%rchi2_arr_cmp) - MINVAL(this%rchi2_arr_cmp)
+       ddchi2 = ABS(dchi2 - this%dchi2_prm)
+
+       this%sor_niter_cmp = this%sor_niter_cmp + 1
+       IF (this%sor_norb_cmp < this%sor_norb_prm .AND. err_verb >= 2) THEN
+          WRITE(stderr,"(A,I0)") " Warning by autoStatisticalRanging:" // &
+               " Number of sample orbits too small: ", this%sor_norb_cmp
+          WRITE(stderr,"(1X)")
+       END IF
+
+       chi2_min_ = this%chi2_min_prm
+       rho_bounds_ = this%sor_rho_prm
+       CALL updateRanging(this, automatic = .TRUE.)
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,I0,2(A,F10.5))") "Rho histogram flag = ", &
+               this%sor_rho_histo_cmp,", dchi2 = ", dchi2, &
+               ", d(dchi2) = ", ddchi2
+          WRITE(stdout,"(1X)")
+       END IF
+
+    END DO
+    ! Save the last _used_ rho bounds
+    this%sor_rho_prm = rho_bounds_
+    this%chi2_min_prm = chi2_min_
+
+  END SUBROUTINE autoStatisticalRanging
+
+
+
+
+
+  SUBROUTINE comparePropagationParameters(this, orb, parameters_agree)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Orbit), INTENT(in) :: orb
+    LOGICAL, INTENT(out) :: parameters_agree
+    CHARACTER(len=DYN_MODEL_LEN) :: storb_dyn_model, orb_dyn_model
+    CHARACTER(len=INTEGRATOR_LEN) :: storb_integrator, orb_integrator
+    REAL(bp), DIMENSION(6) :: storb_finite_diff, orb_finite_diff
+    REAL(bp) :: storb_integration_step, orb_integration_step
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / comparePropagationParameters", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    parameters_agree = .TRUE.
+    CALL getParameters(this, &
+         dyn_model=storb_dyn_model, &
+         integration_step=storb_integration_step, &
+         integrator=storb_integrator, &
+         finite_diff=storb_finite_diff)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / comparePropagationParameters", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    CALL getParameters(orb, &
+         dyn_model=orb_dyn_model, &
+         integration_step=orb_integration_step, &
+         integrator=orb_integrator, &
+         finite_diff=orb_finite_diff)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / comparePropagationParameters", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    IF (storb_dyn_model == "n-body" .AND. &
+         orb_dyn_model == "n-body") THEN
+       IF (storb_integrator /= orb_integrator .OR. &
+            storb_integration_step /= orb_integration_step) THEN
+          parameters_agree = .FALSE.
+          CALL infoMessage("StochasticOrbit / comparePropagationParameters", &
+               "Integrators or step-sizes disagree.", stdout, 2)
+       END IF
+       IF (ANY(ABS(storb_finite_diff-orb_finite_diff) > &
+            EPSILON(storb_finite_diff))) THEN
+          parameters_agree = .FALSE.
+          CALL infoMessage("StochasticOrbit / comparePropagationParameters", &
+               "Finite difference values disagree.", stdout, 2)
+       END IF
+    ELSE IF (storb_dyn_model /= orb_dyn_model) THEN
+       parameters_agree = .FALSE.
+       CALL infoMessage("StochasticOrbit / comparePropagationParameters", &
+            "Propagation models disagree.", stdout, 2)
+    END IF
+
+  END SUBROUTINE comparePropagationParameters
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns .TRUE. if this StochasticOrbit instance contains an
+  !! orbital-element pdf in the form of sample orbits and their
+  !! weights. Otherwise returns .FALSE.
+  !!
+  LOGICAL FUNCTION containsSampledPDF(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+
+    ! The default result is .FALSE.:
+    containsSampledPDF = .FALSE.
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       RETURN
+    END IF
+
+    IF (ASSOCIATED(this%orb_arr_cmp) .AND. &
+         ASSOCIATED(this%pdf_arr_cmp)) THEN
+       containsSampledPDF = .TRUE.
+    END IF
+
+  END FUNCTION containsSampledPDF
+
+
+
+
+
+  SUBROUTINE covarianceSampling(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+
+    TYPE (Time) :: t0
+    TYPE (Orbit), DIMENSION(:), ALLOCATABLE :: &
+         orb_arr
+    TYPE (Orbit) :: &
+         orb_nominal, &
+         orb
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: &
+         comp_scoords, obs_scoords
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: &
+         obsy_ccoords
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=12) :: str1, str2
+    CHARACTER(len=64) :: &
+         frmt = "(F20.15,1X)", &
+         efrmt = "(E11.4,1X)"
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         residuals3, &
+         partials_arr, &
+         information_matrix_obs
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         stdev_arr_measur
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+         jacobian_arr, &
+         obs_coords, &
+         residuals2
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         reg_apriori_arr, &
+         pdf_arr, &
+         rchi2_arr, &
+         cosdec0
+    REAL(bp), DIMENSION(6,6) :: &
+         A, &
+         cov, &
+         eigenvectors, &
+         information_matrix_elem, &
+         jacobian_matrix, &
+         sqrt_eigenvalues
+    REAL(bp), DIMENSION(6) :: &
+         elements_nominal, &
+         ran, &
+         deviates, &
+         mean, &
+         eigenvalues, &
+         elements, &
+         comp_coord, &
+         p, &
+         stdev
+    REAL(bp) :: &
+         sma, &
+         apriori, &
+         chi2_min_global_ls, &
+         chi2, &
+         dchi2, &
+         pdf_val, &
+         obs_, &
+         q, &
+         comp_
+    INTEGER, DIMENSION(:), ALLOCATABLE :: &
+         failed_flag
+    INTEGER, DIMENSION(6) :: &
+         n0
+    INTEGER :: &
+         i, j, &
+         itrial, &
+         iorb, &
+         err, &
+         nobs, &
+         nfailed, &
+         nrotation
+    LOGICAL, DIMENSION(:,:), POINTER :: &
+         mask_arr, &
+         mask_measur
+
+    iorb = 0
+    itrial = 0
+    mean = 0.0_bp
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,6
+       n0(i) = COUNT(this%obs_masks_prm(:,i))
+    END DO
+    orb_nominal = getNominalOrbit(this)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    frame = getFrame(orb_nominal)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    elements_nominal = getElements(orb_nominal, this%element_type_prm, frame)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    cov = getCovarianceMatrix(this, this%element_type_prm, frame)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+    DO i=1,6
+       stdev(i) = SQRT(cov(i,i))
+    END DO
+    t0 = getTime(orb_nominal)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+
+    ! Observations
+    information_matrix_obs => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (30)", 1)
+       RETURN
+    END IF
+    stdev_arr_measur => getStandardDeviations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (31)", 1)
+       RETURN
+    END IF
+    obs_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (35)", 1)
+       RETURN
+    END IF
+    nobs = SIZE(obs_scoords,dim=1)
+    ALLOCATE(orb_arr(this%cos_norb_prm), cosdec0(nobs), &
+         residuals2(nobs,6), residuals3(this%cos_norb_prm,nobs,6), &
+         failed_flag(11), reg_apriori_arr(this%cos_norb_prm), &
+         pdf_arr(this%cos_norb_prm), rchi2_arr(this%cos_norb_prm), &
+         jacobian_arr(this%cos_norb_prm,3), obs_coords(nobs,6), &
+         mask_arr(nobs,6), mask_measur(nobs,6), stat=err)
+    DO i=1,nobs
+       obs_coords(i,:) = getCoordinates(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (40)",1)
+          RETURN
+       END IF
+       cosdec0(i) = COS(obs_coords(i,3))
+    END DO
+    obsy_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (45)",1)
+       RETURN
+    END IF
+    failed_flag = 0
+
+    ! ML PDF value
+    CALL getEphemerides(orb_nominal, obsy_ccoords, comp_scoords, &
+         partials_arr=partials_arr)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (50)",1)
+       RETURN
+    END IF
+    ! Multiply RA partials with cosine of observed declination:
+    DO i=1,nobs
+       partials_arr(2,:,i) = partials_arr(2,:,i)*cosdec0(i)
+    END DO
+    ! Residuals for the input orbit:
+    DO i=1,nobs
+       comp_coord = getCoordinates(comp_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (55)",1)
+          RETURN
+       END IF
+       residuals2(i,1:6) = obs_coords(i,1:6) - comp_coord(1:6)
+       residuals2(i,2) = residuals2(i,2) * cosdec0(i)
+       IF (ABS(residuals2(i,2)) > pi) THEN
+          obs_ = obs_coords(i,2)
+          comp_ = comp_coord(2)
+          IF (obs_ < comp_) THEN
+             obs_ = obs_ + two_pi
+          ELSE
+             comp_ = comp_ + two_pi
+          END IF
+          residuals2(i,2) = (obs_ - comp_) * cosdec0(i)
+       END IF
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,A,3"//TRIM(frmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "observed pos.", obs_coords(i,1:3)
+          WRITE(stdout,"(2X,A,1X,A,3"//TRIM(frmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "computed pos.", comp_coord(1:3)
+       END IF
+    END DO
+
+    ! Observation mask
+    mask_measur = this%obs_masks_prm
+    ! Outlier rejection
+    IF (this%outlier_rejection_prm) THEN
+       DO i=1,nobs
+          IF (ANY(ABS(residuals2(i,2:3)) > &
+               this%outlier_multiplier_prm*stdev_arr_measur(i,2:3))) THEN
+             mask_measur(i,:) = .FALSE.
+          END IF
+       END DO
+    END IF
+
+    ! Reference chi2 from the input orbit which is assumed to be the
+    ! maximum-likelihood orbit:
+    chi2 = chi_square(residuals2, information_matrix_obs, mask_measur, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "TRACE BACK (60)" // TRIM(errstr),1)
+       RETURN
+    END IF
+    DEALLOCATE(residuals2)
+    IF (chi2 < 0.0_bp) THEN
+       WRITE(stdout,"(2X,A,1X,A,F10.5,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Negative chi2 (", chi2, ") for ML solution."
+    END IF
+    ! Jeffrey's apriori:
+    IF (this%regularization_prm) THEN
+       ! Sigma_elements^(-1) = A^T Sigma_obs^(-1) A, where A is the
+       ! partial derivatives matrix of ephemerides wrt elements:
+       information_matrix_elem(:,:) = 0.0_bp
+       DO i=1,nobs
+          information_matrix_elem = information_matrix_elem + &
+               MATMUL(MATMUL(TRANSPOSE(partials_arr(1:6,1:6,i)), &
+               information_matrix_obs(i,1:6,1:6)), &
+               partials_arr(1:6,1:6,i))
+       END DO
+       ! Jeffrey's apriori:
+       apriori = SQRT(ABS(determinant(information_matrix_elem, errstr)))
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (65)", 1)
+          DO i=1,nobs
+             CALL matrix_print(partials_arr(1:6,1:6,i),stderr,errstr)
+             WRITE(stderr,*)
+             CALL matrix_print(information_matrix_obs(i,1:6,1:6),stderr,errstr)
+             WRITE(stderr,*)
+          END DO
+          CALL matrix_print(information_matrix_elem,stderr,errstr)
+          RETURN
+       END IF
+    ELSE
+       apriori = 1.0_bp
+    END IF
+    chi2_min_global_ls = chi2
+    ! If initial estimate for chi2 corresponding to maximum likelihood
+    ! solution remains undetermined (indicated by a negative value),
+    ! set it equal to the chi2 computed for the global least squares:
+    IF (this%chi2_min_prm < 0.0_bp) THEN
+       this%chi2_min_prm = chi2_min_global_ls
+    END IF
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Orbital-elemnt covariance matrix:"
+       CALL matrix_print(cov,stdout,errstr)
+       WRITE(stdout,"(2X,2(A,1X),E12.4)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Condition number for orbital-element covariance matrix:", cond_nr(cov, errstr)
+    END IF
+
+    A = 0.0_bp
+    DO i=1,6
+       A(i,i:6) = cov(i,i:6)
+    END DO
+    CALL cholesky_decomposition(A, p, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / covarianceSampling:", &
+            "Cholesky decomposition unsuccessful:", 1)
+       WRITE(stderr,"(A)") TRIM(errstr)
+       RETURN
+    END IF
+    DO i=1,6
+       A(i,i) = p(i)
+    END DO
+
+!!$    cov = cov*1.0e10_bp
+!!$    ! Solve U and LAMBDA from SIGMA = U LAMBDA transpose(U)
+!!$    CALL eigen_decomposition_jacobi(cov, eigenvalues, &
+!!$         eigenvectors, nrotation, errstr)
+!!$    IF (LEN_TRIM(errstr) /= 0) THEN
+!!$       error = .TRUE.
+!!$       CALL errorMessage("StochasticOrbit / covarianceSampling:", &
+!!$            "Eigen decomposition unsuccessful:", 1)
+!!$       write(stderr,"(A)") trim(errstr)
+!!$       RETURN
+!!$    END IF
+!!$    IF (info_verb >= 2) THEN
+!!$       WRITE(stdout,"(2X,A,1X,A)") &
+!!$            "StochasticOrbit / covarianceSampling:", &
+!!$            "Eigenvectors:"
+!!$       CALL matrix_print(eigenvectors,stdout,errstr)
+!!$       WRITE(stdout,"(2X,A,1X,A)") &
+!!$            "StochasticOrbit / covarianceSampling:", &
+!!$            "Eigenvalues:"
+!!$       CALL vector_print(eigenvalues,stdout,.false.,errstr)
+!!$    end IF
+!!$    sqrt_eigenvalues = 0.0_bp
+!!$    ! sqrt(LAMBDA) is needed:
+!!$    DO i=1,6
+!!$       sqrt_eigenvalues(i,i) = SQRT(eigenvalues(i))
+!!$    END DO
+!!$    ! A = U sqrt(LAMBDA)
+!!$    A = MATMUL(eigenvectors, sqrt_eigenvalues)/1.0e10_bp
+
+!!$    ! From Devroye: "Non-Uniform Random Variate Generation", 1986,
+!!$    ! chapter 11
+!!$    A = 0.0_bp
+!!$    DO i=1,6
+!!$       DO j=1,i
+!!$          IF (j == 1) THEN
+!!$             A(i,1) = cov(i,1)/SQRT(cov(1,1))
+!!$          ELSE IF (i == j) THEN
+!!$             IF (cov(i,i) - SUM(A(i,1:i-1)**2) < -1E-7_bp) THEN
+!!$                CALL toString(i, str1, error)
+!!$                CALL toString(cov(i,i) - SUM(A(i,1:i-1)**2), str2, error, frmt=efrmt)
+!!$                error = .TRUE.
+!!$                CALL errorMessage("StochasticOrbit / covarianceSampling", &
+!!$                     "Square of element (" // TRIM(str1) // "," // TRIM(str1) // &
+!!$                     ") of Devroye's matrix A is negative (" // TRIM(str2) // ").", 1)
+!!$                RETURN
+!!$             END IF
+!!$             A(i,i) = SQRT(ABS(cov(i,i) - SUM(A(i,1:i-1)**2)))
+!!$          ELSE IF (j < i) THEN
+!!$             A(i,j) = (cov(i,j) - SUM(A(i,1:j-1)*A(j,1:j-1)))/A(j,j)
+!!$          END IF
+!!$       END DO
+!!$    END DO
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "A matrix:"
+       CALL matrix_print(A,stdout,errstr)
+       IF (this%element_type_prm == "keplerian") THEN
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Element uncertainty:", stdev(1:2), stdev(3:6)/rad_deg
+       ELSE
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Element uncertainty:", stdev(1:6)
+       END IF
+       DO i=1,6
+          ran = 0.0_bp
+          ran(i) = -1.0_bp
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") "StochasticOrbit / covarianceSampling:", &
+               "1-sigma deviates", this%cos_nsigma_prm*MATMUL(A,ran) + mean
+          ran(i) = 1.0_bp
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") "StochasticOrbit / covarianceSampling:", &
+               "1-sigma deviates", this%cos_nsigma_prm*MATMUL(A,ran) + mean
+       END DO
+       IF (this%element_type_prm == "keplerian") THEN
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Nominal elements:", elements_nominal(1:2), elements_nominal(3:6)/rad_deg
+       ELSE
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Nominal elements:", elements_nominal(1:6)
+       END IF
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Starting sampling."
+    END IF
+
+    DO WHILE (iorb < this%cos_norb_prm .AND. itrial < this%cos_ntrial_prm)
+
+       itrial = itrial + 1
+
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,1X,A,I0)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Trial orbit #", itrial
+          WRITE(stdout,"(2X,A,1X,A,I0)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Accepted orbits so far: ", iorb
+          WRITE(stdout,"(2X,A,1X,2A)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Element type: ", TRIM(this%element_type_prm)
+          IF (this%element_type_prm == "keplerian") THEN
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Nominal elements:", elements_nominal(1:2), elements_nominal(3:6)/rad_deg
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Element uncertainty:", stdev(1:2), stdev(3:6)/rad_deg
+          ELSE
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Nominal elements:", elements_nominal(1:6)
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Element uncertainty:", stdev(1:6)
+          END IF
+       END IF
+
+       IF (itrial == 1) THEN
+          ! Use the nominal orbit as first trial orbit.
+          IF (info_verb >= 2) THEN
+             deviates = 0.0_bp
+             elements = elements_nominal
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Deviates:", deviates
+          END IF
+          CALL NULLIFY(orb)
+          orb = copy(orb_nominal)
+       ELSE
+          IF (this%cos_gaussian_prm) THEN
+             CALL randomGaussian(ran)
+          ELSE
+             CALL randomNumber(ran)
+             ran = 2.0_bp*ran - 1.0_bp
+          END IF
+          WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Random numbers:", ran
+          deviates = this%cos_nsigma_prm*MATMUL(A,ran) + mean
+          ! New coordinates = old coordinates + deviates:
+          elements = elements_nominal + deviates
+          IF (this%element_type_prm == "keplerian") THEN
+             ! 0 <= angle < 2pi :
+             elements(4:6) = MODULO(elements(4:6), two_pi)
+          END IF
+          IF (info_verb >= 2) THEN
+             IF (this%element_type_prm == "keplerian") THEN
+                WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                     "StochasticOrbit / covarianceSampling:", &
+                     "Deviates:", deviates(1:2), deviates(3:6)/rad_deg
+             ELSE
+                WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                     "StochasticOrbit / covarianceSampling:", &
+                     "Deviates:", deviates(1:6)          
+             END IF
+          END IF
+          CALL NULLIFY(orb)
+          CALL NEW(orb, elements, this%element_type_prm, frame, t0)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "TRACE BACK (70)", 1)
+             RETURN
+          END IF
+       END IF
+       IF (info_verb >= 2) THEN
+          IF (this%element_type_prm == "keplerian") THEN
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Generated elements:", elements(1:2), elements(3:6)/rad_deg
+          ELSE
+             WRITE(stdout,"(2X,A,1X,A19,6(1X,F15.10))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Generated elements:", elements(1:6)          
+          END IF
+       END IF
+
+       ! Check whether there are a priori requirements on the orbits
+       IF (this%informative_apriori_prm) THEN
+          elements = getElements(orb,"cometary")
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "TRACE BACK (71)", 1)
+             RETURN
+          END IF
+          ! Semimajor axis:
+          IF (this%apriori_a_min_prm >= 0.0_bp .OR. &
+               this%apriori_a_max_prm >= 0.0_bp) THEN
+             sma = elements(1)/(1.0_bp-elements(2))
+             IF (this%apriori_a_min_prm >= 0.0_bp .AND. &
+                  sma < this%apriori_a_min_prm) THEN
+                ! Semimajor axis too small
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F13.7,A)") &
+                        "Failed (semimajor axis too small: ", sma, " AU)"
+                END IF
+                failed_flag(1) = failed_flag(1) + 1
+                CYCLE
+             END IF
+             IF (this%apriori_a_max_prm >= 0.0_bp .AND. &
+                  sma > this%apriori_a_max_prm) THEN
+                ! Semimajor axis too large
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F10.7,A)") &
+                        "Failed (semimajor axis too large: ", sma, " AU)"
+                END IF
+                failed_flag(2) = failed_flag(2) + 1
+                CYCLE
+             END IF
+          END IF
+          ! Eccentricity:
+          IF (elements(2) < 0.0_bp) THEN
+             ! Eccentricity too small.
+             failed_flag(3) = failed_flag(3) + 1
+             CYCLE
+          END IF
+          IF (elements(2) > 1.0_bp) THEN
+             ! Eccentricity too large (or should non-elliptic orbits be accepted?).
+             failed_flag(4) = failed_flag(4) + 1
+             CYCLE
+          END IF
+          ! Inclination:
+          IF (elements(3) < 0.0_bp) THEN
+             ! Inclination not defined.
+             failed_flag(5) = failed_flag(5) + 1
+             CYCLE
+          END IF
+          IF (elements(3) > pi) THEN
+             ! Inclination not defined.
+             failed_flag(6) = failed_flag(6) + 1
+             CYCLE
+          END IF
+          ! Periapsis distance:
+          IF (this%apriori_periapsis_min_prm >= 0.0_bp .OR. &
+               this%apriori_periapsis_max_prm >= 0.0_bp) THEN
+             ! Periapsis distance too small:
+             IF (this%apriori_periapsis_min_prm >= 0.0_bp .AND. &
+                  elements(1) < this%apriori_periapsis_min_prm) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F13.7,A)") &
+                        "Failed (periapsis distance too small: ", q, " AU)"
+                END IF
+                failed_flag(7) = failed_flag(7) + 1
+                CYCLE
+             END IF
+             ! Periapsis distance too large:
+             IF (this%apriori_periapsis_max_prm >= 0.0_bp .AND. &
+                  elements(1) > this%apriori_periapsis_max_prm) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F10.7,A)") &
+                        "Failed (periapsis distance too large: ", q, " AU)"
+                END IF
+                failed_flag(8) = failed_flag(8) + 1
+                CYCLE
+             END IF
+          END IF
+          ! Apoapsis distance:
+          IF (this%apriori_apoapsis_min_prm >= 0.0_bp .OR. &
+               this%apriori_apoapsis_max_prm >= 0.0_bp) THEN
+             Q = sma*(1.0_bp+elements(2))
+             ! Apoapsis distance too small:
+             IF (this%apriori_apoapsis_min_prm >= 0.0_bp .AND. &
+                  Q < this%apriori_apoapsis_min_prm) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F13.7,A)") &
+                        "Failed (apoapsis distance too small: ", Q, " AU)"
+                END IF
+                failed_flag(9) = failed_flag(9) + 1
+                CYCLE
+             END IF
+             ! Apoapsis distance too large:
+             IF (this%apriori_apoapsis_max_prm >= 0.0_bp .AND. &
+                  Q > this%apriori_apoapsis_max_prm) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F10.7,A)") &
+                        "Failed (apoapsis distance too large: ", Q, " AU)"
+                END IF
+                failed_flag(10) = failed_flag(10) + 1
+                CYCLE
+             END IF
+          END IF
+       END IF
+
+       CALL setParameters(orb, dyn_model=this%dyn_model_prm, &
+            integrator=this%integrator_prm, &
+            integration_step=this%integration_step_prm, &
+            perturbers=this%perturbers_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (75)",1)
+          RETURN
+       END IF
+
+       !!
+       !! 5) ACCEPTANCE / REJECTION OF GENERATED ORBIT
+       !!
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,A)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Start computing ephemerides..."
+       END IF
+       CALL getEphemerides(orb, obsy_ccoords, comp_scoords, &
+            partials_arr=partials_arr)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (80)",1)
+          RETURN
+       END IF
+       IF (info_verb >= 4) THEN
+          WRITE(stdout,"(2X,A,1X,A)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Ephemerides ready..."
+       END IF
+       ! Multiply RA partials with cosine of observed declination:
+       DO i=1,nobs
+          partials_arr(2,:,i) = partials_arr(2,:,i)*cosdec0(i)
+       END DO
+
+       ! Sky-plane residuals and chi-squares:
+       DO i=1,nobs
+          comp_coord = getCoordinates(comp_scoords(i))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "TRACE BACK (85)",1)
+             RETURN
+          END IF
+          residuals3(iorb+1,i,1:6) = obs_coords(i,1:6) - comp_coord(1:6)
+          residuals3(iorb+1,i,2) = residuals3(iorb+1,i,2) * cosdec0(i)
+          IF (ABS(residuals3(iorb+1,i,2)) > pi) THEN
+             obs_ = obs_coords(i,2)
+             comp_ = comp_coord(2)
+             IF (obs_ < comp_) THEN
+                obs_ = obs_ + two_pi
+             ELSE
+                comp_ = comp_ + two_pi
+             END IF
+             residuals3(iorb+1,i,2) = (obs_ - comp_) * cosdec0(i)
+          END IF
+          IF (info_verb >= 4) THEN
+             WRITE(stdout,"(2X,A,1X,A21,3"//TRIM(frmt)//")") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "observed pos.", obs_coords(i,1:3)
+             WRITE(stdout,"(2X,A,1X,A21,3"//TRIM(frmt)//")") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "computed pos.", comp_coord(1:3)
+             WRITE(stdout,"(2X,A,1X,A21,3"//TRIM(frmt)//")") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "residuals [AU,arcsec]", residuals3(iorb+1,i,1), &
+                  residuals3(iorb+1,i,2:3)/rad_asec
+          END IF
+       END DO
+
+!!$       mask_arr = .FALSE.
+!!$       WHERE (this%obs_masks_prm .AND. ABS(residuals3(iorb+1,:,:)) > this%res_accept_prm)
+!!$          mask_arr = .TRUE.
+!!$       END WHERE
+!!$       IF (info_verb >= 4) THEN
+!!$          DO i=1,nobs
+!!$             WRITE(stdout,"(2X,A,1X,A,2"//TRIM(frmt)//")") "O-C residuals (RA, Dec):", &
+!!$                  residuals3(iorb+1,i,2:3)/rad_asec
+!!$          END DO
+!!$          WRITE(stdout,"(2X,A,1X,A,I0,A,I0)") &
+!!$               "No of omitted obs/included obs: ", &
+!!$               COUNT(mask_arr),"/",n0(2)
+!!$       END IF
+!!$       IF (COUNT(mask_arr) > 0) THEN
+!!$          ! Residuals are too large for at least one observation.
+!!$          failed_flag(3) = failed_flag(3) + 1
+!!$          IF (info_verb >= 5) THEN
+!!$             WRITE(stdout,"(2X,A,1X,A)") &
+!!$                  "Failed (residuals are too large)"
+!!$          END IF
+!!$          CALL NULLIFY(orb)
+!!$          DEALLOCATE(comp_scoords, partials_arr, stat=err)
+!!$          IF (err /= 0) THEN
+!!$             error = .TRUE.
+!!$             DEALLOCATE(comp_scoords, stat=err)
+!!$             DEALLOCATE(partials_arr, stat=err)
+!!$             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+!!$                  "Could not deallocate memory (5)", 1)
+!!$             RETURN
+!!$          END IF
+!!$          CYCLE
+!!$       END IF
+
+       ! Compute chi2:
+       chi2 = chi_square(residuals3(iorb+1,:,:), information_matrix_obs, mask_measur, errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "TRACE BACK (90)" // TRIM(errstr),1)
+          RETURN
+       END IF
+       IF (chi2 < 0.0_bp) THEN
+          WRITE(stdout,"(2X,A,1X,A,F10.5,A,I0)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Negative chi2 (", chi2, ") at trial ", itrial
+       END IF
+       dchi2 = chi2 - this%chi2_min_prm
+       IF (this%dchi2_rejection_prm .AND. &
+            dchi2 > this%dchi2_prm) THEN
+          ! chi2 filtering is used and dchi2 is too large.
+          failed_flag(11) = failed_flag(11) + 1
+          IF (info_verb >= 5) THEN
+             WRITE(stdout,"(2X,A,1X,A,1X,E10.5)") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Failed (dchi2 too large)", dchi2
+          END IF
+          CALL NULLIFY(orb)
+          DEALLOCATE(comp_scoords, partials_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             DEALLOCATE(comp_scoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "Could not deallocate memory (5)", 1)
+             RETURN
+          END IF
+          CYCLE
+       END IF
+
+
+       ! Jeffrey's apriori:
+       ! Monitor the matrix inversion?
+       IF (this%regularization_prm) THEN
+          ! Sigma_elements^(-1) = A^T Sigma_obs^(-1) A, where A is the
+          ! partial derivatives matrix of ephemerides wrt elements:
+          information_matrix_elem(:,:) = 0.0_bp
+          DO i=1,nobs
+             information_matrix_elem = information_matrix_elem + &
+                  MATMUL(MATMUL(TRANSPOSE(partials_arr(1:6,1:6,i)), &
+                  information_matrix_obs(i,1:6,1:6)), &
+                  partials_arr(1:6,1:6,i))
+          END DO
+          ! Jeffrey's apriori:
+          apriori = SQRT(ABS(determinant(information_matrix_elem, errstr)))
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "TRACE BACK (95)", 1)
+             DO i=1,nobs
+                CALL matrix_print(partials_arr(1:6,1:6,i),stderr,errstr)
+                WRITE(stderr,*)
+                CALL matrix_print(information_matrix_obs(i,1:6,1:6),stderr,errstr)
+                WRITE(stderr,*)
+             END DO
+             CALL matrix_print(information_matrix_elem,stderr,errstr)
+             RETURN
+          END IF
+       ELSE
+          apriori = 1.0_bp
+       END IF
+
+       ! This trial orbit fulfills all criteria so add it to the pile
+       ! of (accepted) sample orbits
+       iorb = iorb + 1
+       orb_arr(iorb) = copy(orb)
+       reg_apriori_arr(iorb) = apriori
+       pdf_arr(iorb) = apriori*EXP(-0.5_bp*(chi2 - COUNT(mask_measur)))
+       rchi2_arr(iorb) = chi2 - SUM(n0(1:6))
+       IF (this%jacobians_prm) THEN
+          ! Determinant of Jacobian between topocentric spherical
+          ! coordinates of the first and the last observation and
+          ! orbital parameters required for output ("Topocentric Wrt
+          ! Cartesian/Keplerian"):
+          jacobian_matrix(1:3,:) = partials_arr(1:3,:,1) / &
+               cosdec0(1)
+          jacobian_matrix(4:6,:) = partials_arr(1:3,:,nobs) / &
+               cosdec0(nobs)
+          jacobian_arr(iorb,1) = ABS(determinant(jacobian_matrix, errstr))
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "Unsuccessful computation of determinant of orbital element " // &
+                  "jacobian matrix " // TRIM(errstr), 1)
+             errstr = ""
+             IF (err_verb >= 1) THEN
+                CALL matrix_print(jacobian_matrix, stderr, errstr)
+             END IF
+             errstr = ""
+             CYCLE
+          END IF
+
+          ! Determinant of Jacobian between Cartesian and Keplerian
+          ! orbital elements ("Cartesian Wrt Keplerian"):
+          CALL partialsCartesianWrtKeplerian(orb, &
+               jacobian_matrix, "equatorial")
+          jacobian_arr(iorb,2) = ABS(determinant(jacobian_matrix, errstr)) 
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             CALL errorMessage("StochasticOrbit / covarianceSampling", &
+                  "Unsuccessful computation of " // &
+                  "jacobian matrix " // TRIM(errstr), 1)
+             errstr = ""
+             IF (err_verb >= 1) THEN
+                CALL matrix_print(jacobian_matrix, stderr, errstr)
+             END IF
+             errstr = ""
+             CALL NULLIFY(orb)
+             RETURN
+          END IF
+
+          ! Determinant of Jacobian between equinoctial and
+          ! Keplerian orbital elements ("Equinoctial Wrt
+          ! Keplerian"):
+          elements = getElements(orb, "keplerian")
+          jacobian_arr(iorb,3) = 0.5_bp*elements(2) * &
+               SIN(0.5_bp*elements(3)) / COS(0.5_bp*elements(3))**3
+          IF (info_verb >= 5) THEN
+             WRITE(stdout,"(2X,A,1X,A,F15.12)") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "Chi2 new: ", chi2
+             WRITE(stdout,"(2X,A,1X,A,3(1X,F10.5))") &
+                  "StochasticOrbit / covarianceSampling:", &
+                  "dchi2:", chi2 - this%chi2_min_prm
+          END IF
+       ELSE
+          jacobian_arr(iorb,:) = -1.0_bp
+       END IF
+
+       CALL NULLIFY(orb)
+       DEALLOCATE(comp_scoords, partials_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(comp_scoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "Could not deallocate memory (15).", 1)
+          RETURN
+       END IF
+
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,1X,A,I0,1X,A)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Orbit #", iorb, "accepted."
+          WRITE(stdout,"(2X,A,1X,A)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Sample information matrix:"
+          CALL matrix_print(information_matrix_elem,stdout,errstr)
+          WRITE(stdout,"(2X,A,1X,A,1X,2"//TRIM(efrmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Sample chi2, rchi2:", chi2, chi2-SUM(n0(1:6))
+          WRITE(stdout,"(2X,A,1X,A,1X,1"//TRIM(efrmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Sample apriori:", apriori
+          WRITE(stdout,"(2X,A,1X,A,1X,1"//TRIM(efrmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "Sample pdf:", pdf_arr(iorb)
+          WRITE(stdout,"(2X,A,1X,A,1X,1"//TRIM(efrmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               "dchi2:", dchi2
+          WRITE(stdout,"(2X,A,1X,A,L1)") &
+               "StochasticOrbit / covarianceSampling:", &
+               "dchi2 filtering: ", this%dchi2_rejection_prm 
+       END IF
+
+    END DO
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Final number of orbits and the required trials:"
+       WRITE(stdout,"(2X,A,1X,2(I0,2X))") &
+            "StochasticOrbit / covarianceSampling:", &
+            iorb, itrial
+       WRITE(stdout,"(2X,A,1X,A)") &
+            "StochasticOrbit / covarianceSampling:", &
+            "Total failure percentage (1), and failure due to " // &
+            "(2) min a, " // &
+            "(3) max a, " // &
+            "(4) min e, " // &
+            "(5) max e, " // &
+            "(6) min i, " // &
+            "(7) max i, " // &
+            "(8) min q, " // &
+            "(9) max q, " // &
+            "(10) min Q, " // &
+            "(11) max Q, " // &
+            "(12) pdf:"
+       nfailed = SUM(failed_flag)
+       nfailed = MAX(1,nfailed)
+       WRITE(stdout,"(2X,A,1X,1"//TRIM(frmt)//")") &
+            "StochasticOrbit / covarianceSampling:", &
+            100.0_bp*REAL(SUM(failed_flag),bp)/itrial
+       DO i=1,SIZE(failed_flag)
+          WRITE(stdout,"(2X,A,1X,1"//TRIM(frmt)//")") &
+               "StochasticOrbit / covarianceSampling:", &
+               100.0_bp*REAL(failed_flag(i),bp)/nfailed
+       END DO
+    END IF
+
+    ALLOCATE(this%reg_apr_arr_cmp(iorb), this%res_arr_cmp(iorb,nobs,6))
+
+
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "Could not deallocate memory (20).", 1)
+          RETURN
+       END IF
+    END IF
+    ALLOCATE(this%orb_arr_cmp(iorb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Could not allocate memory (5).", 1)
+       RETURN
+    END IF
+    DO i=1,iorb
+       this%orb_arr_cmp(i) = copy(orb_arr(i))
+    END DO
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "Could not deallocate memory (25).", 1)
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(this%pdf_arr_cmp(iorb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Could not allocate memory (10).", 1)
+       RETURN
+    END IF
+    this%pdf_arr_cmp = pdf_arr
+    IF (ASSOCIATED(this%jac_arr_cmp)) THEN
+       DEALLOCATE(this%jac_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "Could not deallocate memory (25).", 1)
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(this%jac_arr_cmp(iorb,3), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Could not allocate memory (10).", 1)
+       RETURN
+    END IF
+    this%jac_arr_cmp = jacobian_arr
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL errorMessage("StochasticOrbit / covarianceSampling", &
+               "Could not deallocate memory (25).", 1)
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(this%rchi2_arr_cmp(iorb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Could not allocate memory (10).", 1)
+       RETURN
+    END IF
+    this%rchi2_arr_cmp = rchi2_arr
+    DO i=1,SIZE(orb_arr)
+       CALL NULLIFY(orb_arr(i))
+    END DO
+    this%reg_apr_arr_cmp = reg_apriori_arr
+    this%res_arr_cmp = residuals3
+
+    CALL NULLIFY(orb_nominal)
+
+    DEALLOCATE(orb_arr, failed_flag, pdf_arr, &
+         information_matrix_obs, jacobian_arr, residuals3, &
+         stdev_arr_measur, mask_measur, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(jacobian_arr, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(stdev_arr_measur, stat=err)
+       DEALLOCATE(mask_measur, stat=err)
+       CALL errorMessage("StochasticOrbit / covarianceSampling", &
+            "Could not deallocate memory (30).", 1)
+       RETURN       
+    END IF
+
+  END SUBROUTINE covarianceSampling
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a discrete sampling of the apoapsis distance
+  !! probability-density function for this orbit.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getApoapsisDistance_SO(this, Q)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), DIMENSION(:,:), POINTER     :: Q
+
+    TYPE (Orbit) :: orb
+    REAL(bp), DIMENSION(6,6) :: partials, covariance1, covariance2
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    REAL(bp) :: jac
+    INTEGER :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getApoapsisDistance", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (containsSampledPDF(this)) THEN
+
+       pdf_arr => getPDFValues(this, "keplerian")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+
+       ALLOCATE(Q(SIZE(this%orb_arr_cmp,dim=1),2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "Could not allocate memory (5).", 1)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       partials = identity_matrix(6)
+       DO i=1,SIZE(this%orb_arr_cmp,dim=1)
+          CALL getApoapsisDistance(this%orb_arr_cmp(i), &
+               Q(i,1), partials=partials(1,1:6))
+          IF (error) THEN
+             CALL errorMessage("Orbit / getApoapsisDistance", &
+                  "TRACE BACK (5)", 1)
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          jac = ABS(determinant(partials, errstr))
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getApoapsisDistance", &
+                  "Could not compute determinant for Jacobian. " // &
+                  TRIM(errstr), 1)
+             errstr = ""
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          Q(i,2) = pdf_arr(i)*jac
+       END DO
+
+       DEALLOCATE(pdf_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getApoapsisDistance", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+
+    ELSE
+
+       ALLOCATE(Q(1,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+       orb = copy(this%orb_ml_cmp)
+       CALL toKeplerian(orb)
+       partials = identity_matrix(6)
+       CALL getApoapsisDistance(orb, &
+            Q(1,1), &
+            partials=partials(1,1:6))
+       IF (error) THEN
+          CALL errorMessage("Orbit / getApoapsisDistance", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(orb)
+
+       covariance1 = getCovarianceMatrix(this, "keplerian")
+       covariance2 = MATMUL(MATMUL(partials,covariance1),TRANSPOSE(partials))
+       Q(1,2) = SQRT(covariance2(1,1))
+
+    END IF
+
+  END SUBROUTINE getApoapsisDistance_SO
+
+
+
+
+
+  SUBROUTINE getAPrioriWeights(this, apriori, apriori_pdf)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)   :: this
+    REAL(bp), DIMENSION(:,:), INTENT(in) :: apriori
+    REAL(bp), DIMENSION(:), POINTER      :: apriori_pdf
+    REAL(bp), DIMENSION(6)               :: elements
+    INTEGER                              :: i, j, norb, nbin, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getAPrioriWeights", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nbin = SIZE(apriori,dim=1)
+    IF (.NOT. ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getAPrioriWeights", &
+            "No sample orbits available.", 1)
+       RETURN
+    END IF
+    norb = SIZE(this%orb_arr_cmp,dim=1)
+    ALLOCATE(apriori_pdf(norb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getAPrioriWeights", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    apriori_pdf = 0.0_bp
+
+    DO i=1,norb
+       elements = getElements(this%orb_arr_cmp(i), "keplerian")
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getAPrioriWeights", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       elements(3) = elements(3)/rad_deg
+       DO j=1,nbin
+          IF (elements(1) >= apriori(j,1) .AND. elements(1) < apriori(j,2) .AND. &
+               elements(2) >= apriori(j,3) .AND. elements(2) < apriori(j,4) .AND. &
+               elements(3) >= apriori(j,5) .AND. elements(3) < apriori(j,6)) THEN
+             apriori_pdf(i) = apriori(j,7)
+             EXIT
+          END IF
+       END DO
+    END DO
+
+  END SUBROUTINE getAPrioriWeights
+
+
+
+
+
+  !! Description:
+  !!
+  !! Returns the sample orbit with the highest PDF value. Optionally,
+  !! the PDF of all sample orbits is multiplied with a given priori
+  !! distribution before choosing the highest value.
+  !!
+  FUNCTION getBestFittingSampleOrbit(this, apriori)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)  :: this
+    REAL(bp), DIMENSION(:,:), OPTIONAL  :: apriori
+    TYPE (Orbit)                        :: getBestFittingSampleOrbit
+    REAL(bp), DIMENSION(:), POINTER     :: apriori_pdf
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: pdf
+    INTEGER                             :: norb, err, indx 
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    norb = SIZE(this%orb_arr_cmp,dim=1)
+    ALLOCATE(pdf(norb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    pdf = this%pdf_arr_cmp
+    pdf = pdf / SUM(pdf)
+    IF (PRESENT(apriori)) THEN
+       CALL getAPrioriWeights(this, apriori, apriori_pdf)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "TRACE BACK (5).", 1)
+          DEALLOCATE(pdf, stat=err)
+          IF (err /= 0) CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       ELSE IF (SIZE(apriori_pdf,dim=1) /= norb) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Size of a priori array not consistent with number of orbits.", 1)
+          DEALLOCATE(pdf, apriori_pdf, stat=err)
+          IF (err /= 0) CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+       pdf(1:norb) = pdf(1:norb)*apriori_pdf(1:norb)
+       IF (SUM(pdf) < EPSILON(pdf(1))) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Use of priori results in zero probability.", 1)
+          DEALLOCATE(pdf, apriori_pdf, stat=err)
+          IF (err /= 0) CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       ELSE
+          pdf = pdf / SUM(pdf)
+       END IF
+       DEALLOCATE(apriori_pdf, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+               "Could not deallocate memory (15).", 1)
+          RETURN
+       END IF
+    END IF
+    indx = MAXLOC(pdf,dim=1)
+    DEALLOCATE(pdf, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getBestFittingSampleOrbit", &
+            "Could not deallocate memory (20).", 1)
+       RETURN
+    END IF
+    getBestFittingSampleOrbit = copy(this%orb_arr_cmp(indx))
+
+  END FUNCTION getBestFittingSampleOrbit
+
+
+
+
+
+  REAL(bp) FUNCTION getChi2_this_orb(this, orb, obs_masks)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Orbit), INTENT(in) :: orb
+    LOGICAL, DIMENSION(:,:), INTENT(in), OPTIONAL :: obs_masks
+
+    REAL(bp), DIMENSION(:,:,:), POINTER :: information_matrix
+    REAL(bp), DIMENSION(:,:), POINTER :: residuals
+    INTEGER :: err, i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+    IF (.NOT.exist(orb)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "Orbit has not been initialized.", 1)
+       RETURN
+    END IF
+    residuals => getResiduals(this, orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(residuals, stat=err)
+       RETURN
+    END IF
+    information_matrix => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(information_matrix, stat=err)
+       RETURN
+    END IF
+    IF (PRESENT(obs_masks)) THEN
+       getChi2_this_orb = chi_square(residuals, information_matrix, obs_masks, errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getChi2", &
+               "TRACE BACK (15) " // TRIM(errstr), 1)
+          errstr = ""
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(information_matrix, stat=err)
+          RETURN
+       END IF
+    ELSE
+       getChi2_this_orb = chi_square(residuals, information_matrix, this%obs_masks_prm, errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getChi2", &
+               "TRACE BACK (25) " // TRIM(errstr), 1)
+          errstr = ""
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(information_matrix, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    DEALLOCATE(residuals, information_matrix, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "Could not deallocate memory (10).", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(information_matrix, stat=err)
+       RETURN
+    END IF
+
+  END FUNCTION getChi2_this_orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns chi2 based on residuals and information matrix. Has been tested.
+  !!
+  !! @author MG, JV
+  !! @version 22.5.2006
+  !!
+  REAL(bp) FUNCTION getChi2_matrix(residuals, information_matrix, mask)
+
+    IMPLICIT NONE
+    REAL(bp), DIMENSION(:,:), INTENT(in)          :: residuals ! (1:nobs,1:nmulti)
+    REAL(bp), DIMENSION(:,:), INTENT(in)          :: information_matrix ! (1:nobs*nmulti,1:nobs*nmulti)
+    LOGICAL, DIMENSION(:,:), INTENT(in), OPTIONAL :: mask ! (1:nobs,1:nmulti)
+
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: residuals_
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: residual_vector, tmp
+    INTEGER :: i, j, nobs, nmulti,err
+
+    ! chi2 = residuals*information_matrix*transpose(residuals), where
+    ! "residuals" is (nmulti*nobs x 1) and "information_matrix" is
+    ! (nmulti*nobs x nmulti*nobs):
+
+    nobs = SIZE(residuals,dim=1)
+    nmulti = SIZE(residuals,dim=2)
+    ALLOCATE(residuals_(nobs,nmulti), residual_vector(nobs*nmulti), &
+         tmp(nobs*nmulti), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    residuals_ = residuals
+    IF (PRESENT(mask)) THEN
+       WHERE (.NOT. mask)
+          residuals_ = 0.0_bp
+       END WHERE
+    END IF
+
+    DO i=1,nobs
+       j = (i-1)*nmulti
+       residual_vector(j+1:j+nmulti) = residuals_(i,:)
+    END DO
+    DO i=1,nobs*nmulti
+       tmp(i) = DOT_PRODUCT(residual_vector(:), information_matrix(:,i))
+    END DO
+    getChi2_matrix = DOT_PRODUCT(tmp(:), residual_vector(:))
+
+    DEALLOCATE(residuals_, residual_vector, tmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getChi2", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getChi2_matrix
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns orbital element covariance matrix for a given orbital
+  !! element type (Keplerian/Cartesian).
+  !!
+  !! Tested:
+  !!
+  !! cov_type="keplerian" has been tested using Keplerian ls and
+  !! Cartesian ls + partials, where partials are partials
+  !! Keplerian wrt Cartesian. Relative errors of sqrt(diagonal
+  !! elements) are  ~10^-8 sigma.
+  !!
+  !! cov_type="cartesian" has been tested using Keplerian ls +
+  !! inv(partials) and Cartesian ls, where partials are partials
+  !! Keplerian wrt Cartesian. Relative errors of sqrt(diagonal
+  !! elements) are ~10^-7 sigma.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getCovarianceMatrix_SO(this, cov_type, frame)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)     :: this
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: cov_type
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frame
+    REAL(bp), DIMENSION(6,6)               :: getCovarianceMatrix_SO
+
+    CHARACTER(len=ELEMENT_TYPE_LEN)        :: cov_type_
+    CHARACTER(len=FRAME_LEN)               :: frame_
+    REAL(bp), DIMENSION(6,6)               :: partials
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. ASSOCIATED(this%cov_ml_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+            "Covariances are not available.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(cov_type)) THEN
+       cov_type_ = cov_type
+    ELSE
+       cov_type_ = this%cov_type_prm
+    END IF
+    CALL locase(cov_type_, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+            "The element type string contains forbidden characters.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(frame)) THEN
+       frame_ = frame
+    ELSE IF (cov_type_ == "keplerian" .OR. cov_type_ == "cometary") THEN
+       frame_ = "ecliptic"
+    ELSE IF (.NOT.PRESENT(frame) .AND. .NOT.PRESENT(cov_type)) THEN
+       frame_ = getFrame(this%orb_ml_cmp)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+            "Frame must be given for non-Keplerian elements.", 1)       
+       RETURN
+    END IF
+
+    IF (cov_type_ == this%cov_type_prm) THEN
+       getCovarianceMatrix_SO = this%cov_ml_cmp
+       RETURN
+    ELSE IF (this%cov_type_prm == "cartesian" .AND. &
+         cov_type_ == "cometary") THEN
+       CALL partialsCometaryWrtCartesian(this%orb_ml_cmp, partials)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    ELSE IF (this%cov_type_prm == "cartesian" .AND. &
+         cov_type_ == "keplerian") THEN
+       CALL partialsKeplerianWrtCartesian(this%orb_ml_cmp, partials)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    ELSE IF (this%cov_type_prm == "cometary" .AND. &
+         cov_type_ == "cartesian") THEN
+       CALL partialsCartesianWrtCometary(this%orb_ml_cmp, partials, frame_)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    ELSE IF (this%cov_type_prm == "cometary" .AND. &
+         cov_type_ == "keplerian") THEN
+       CALL partialsKeplerianWrtCometary(this%orb_ml_cmp, partials)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+    ELSE IF (this%cov_type_prm == "keplerian" .AND. &
+         cov_type_ == "cartesian") THEN
+       CALL partialsCartesianWrtKeplerian(this%orb_ml_cmp, partials, frame_)
+    ELSE IF (this%cov_type_prm == "keplerian" .AND. &
+         cov_type_ == "cometary") THEN
+       CALL partialsCometaryWrtKeplerian(this%orb_ml_cmp, partials)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getCovarianceMatrix", &
+            "No such option: " // TRIM(this%cov_type_prm) // &
+            " in and " // TRIM(cov_type_) // " out.", 1)
+       RETURN
+    END IF
+    getCovarianceMatrix_SO = MATMUL(MATMUL(partials, this%cov_ml_cmp), TRANSPOSE(partials))
+
+  END FUNCTION getCovarianceMatrix_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemerides_SO(this, observers, ephemerides_arr, &
+       lt_corr, cov_arr, pdfs_arr, this_lt_corr_arr)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)                 :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: observers
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER  :: ephemerides_arr
+    LOGICAL, INTENT(in), OPTIONAL                         :: lt_corr
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL         :: cov_arr
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL           :: pdfs_arr
+    TYPE (Orbit), DIMENSION(:,:), POINTER, OPTIONAL       :: this_lt_corr_arr
+
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemerides_arr_
+    TYPE (Orbit), DIMENSION(:), POINTER                :: this_lt_corr_arr_
+    REAL(bp), DIMENSION(:,:,:,:), POINTER              :: partials_arr4 
+    REAL(bp), DIMENSION(:,:,:), POINTER                :: partials_arr3
+    REAL(bp), DIMENSION(6,6)                           :: cov_elm
+    REAL(bp)                                           :: det
+    INTEGER                                            :: i, j, err, norb, nobs
+    LOGICAL                                            :: lt_corr_
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getEphemeris", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = SIZE(observers,dim=1)
+    DO i=1,nobs
+       IF (.NOT. exist(observers(i))) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "One or more of the observers has not been initialized.", 1)
+          RETURN
+       END IF
+    END DO
+
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+
+    IF (ASSOCIATED(this%orb_arr_cmp) .AND. PRESENT(pdfs_arr)) THEN
+       ! Sampled p.d.f.:
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          CALL getEphemerides(this%orb_arr_cmp, observers, &
+               ephemerides_arr, lt_corr=lt_corr_, &
+               partials_arr=partials_arr4, &
+               this_lt_corr_arr=this_lt_corr_arr)
+       ELSE
+          CALL getEphemerides(this%orb_arr_cmp, observers, &
+               ephemerides_arr, lt_corr=lt_corr_, &
+               partials_arr=partials_arr4)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(partials_arr4, stat=err)
+          RETURN
+       END IF
+       norb = SIZE(this%orb_arr_cmp, dim=1)
+       ALLOCATE(pdfs_arr(norb,nobs), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Could not allocate memory (5).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(partials_arr4, stat=err)
+          DEALLOCATE(pdfs_arr, stat=err)
+          RETURN
+       END IF
+       DO i=1,norb
+          DO j=1,nobs
+             det = determinant(partials_arr4(i,:,:,j), errstr)
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / getEphemerides", &
+                     "Computation of determinant of partials between " // &
+                     "ephemeris and orbital elements failed. " // &
+                     TRIM(errstr), 1)
+                errstr = ""
+                IF (err_verb >= 1) THEN
+                   CALL matrix_print(partials_arr4(i,:,:,j),stderr, errstr)
+                END IF
+                errstr = ""
+                DEALLOCATE(ephemerides_arr, stat=err)
+                DEALLOCATE(partials_arr4, stat=err)
+                DEALLOCATE(pdfs_arr, stat=err)
+                RETURN
+             END IF
+             ! Changed 2008-12-14
+             !pdfs_arr(i,j) = this%pdf_arr_cmp(i)/ABS(det)
+             pdfs_arr(i,j) = this%pdf_arr_cmp(i) * ABS(det)
+          END DO
+       END DO
+       DEALLOCATE(partials_arr4, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Could not deallocate memory (5).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(pdfs_arr, stat=err)
+          RETURN
+       END IF
+    ELSE IF (exist(this%orb_ml_cmp) .AND. PRESENT(cov_arr)) THEN
+       ! Least squares solution + covariance matrix:
+       IF (getElementType(this%orb_ml_cmp) /= &
+            this%element_type_prm) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Element types for ML Orbit and StochasticOrbit are not compatible.", 1)
+          RETURN
+       END IF
+       IF (getElementType(this%orb_ml_cmp) /= &
+            this%cov_type_prm) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Element types for ML orbit and covariance are not compatible.", 1)
+          RETURN
+       END IF
+       IF (PRESENT(this_lt_corr_arr)) THEN
+          CALL getEphemerides(this%orb_ml_cmp, observers, &
+               ephemerides_arr_, lt_corr=lt_corr_, &
+               partials_arr=partials_arr3, &
+               this_lt_corr_arr=this_lt_corr_arr_)
+          ALLOCATE(this_lt_corr_arr(1,nobs))
+          DO i=1,nobs
+             this_lt_corr_arr(1,i) = copy(this_lt_corr_arr_(i))
+          END DO
+          DEALLOCATE(this_lt_corr_arr_)
+       ELSE
+          CALL getEphemerides(this%orb_ml_cmp, observers, ephemerides_arr_, &
+               lt_corr=lt_corr_, partials_arr=partials_arr3)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "TRACE BACK (10)", 1)
+          DEALLOCATE(ephemerides_arr_, stat=err)
+          DEALLOCATE(partials_arr3, stat=err)
+          RETURN
+       END IF
+       cov_elm = getCovarianceMatrix(this, &
+            getElementType(this%orb_ml_cmp), &
+            getFrame(this%orb_ml_cmp))
+       ALLOCATE(ephemerides_arr(1,nobs), cov_arr(6,6,nobs), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(ephemerides_arr_, stat=err)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(cov_arr, stat=err)
+          DEALLOCATE(partials_arr3, stat=err)
+          RETURN
+       END IF
+       DO i=1,nobs
+          ephemerides_arr(1,i) = copy(ephemerides_arr_(i))
+          CALL NULLIFY(ephemerides_arr_(i))
+          cov_arr(:,:,i) = MATMUL(MATMUL(partials_arr3(:,:,i), cov_elm), &
+               TRANSPOSE(partials_arr3(:,:,i)))
+       END DO
+       DEALLOCATE(partials_arr3, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Could not deallocate memory (10).", 1)
+          DEALLOCATE(ephemerides_arr_, stat=err)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(cov_arr, stat=err)
+          RETURN
+       END IF
+       DEALLOCATE(ephemerides_arr_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemerides", &
+               "Could not deallocate memory (15).", 1)
+          DEALLOCATE(ephemerides_arr, stat=err)
+          DEALLOCATE(cov_arr, stat=err)
+          RETURN
+       END IF
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getEphemerides", &
+            "pdfs_arr or cov_arr must be specified.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE getEphemerides_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getEphemeris_SO(this, observer, ephemeris_arr, &
+       lt_corr, cov, pdf_arr, this_lt_corr_arr, &
+       cov_lt_corr, pdf_lt_corr_arr)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)              :: this
+    TYPE (CartesianCoordinates), INTENT(in)            :: observer
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemeris_arr
+    LOGICAL, INTENT(in), OPTIONAL                      :: lt_corr
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL    :: cov
+    REAL(bp), DIMENSION(:), POINTER, OPTIONAL          :: pdf_arr
+    TYPE (Orbit), DIMENSION(:), POINTER, OPTIONAL      :: this_lt_corr_arr
+    REAL(bp), DIMENSION(6,6), INTENT(out), OPTIONAL    :: cov_lt_corr
+    REAL(bp), DIMENSION(:), POINTER, OPTIONAL          :: pdf_lt_corr_arr
+
+    REAL(bp), DIMENSION(:,:,:), POINTER :: partials_arr, &
+         jacobian_lt_corr_arr, jacobian_prop_arr
+    REAL(bp), DIMENSION(6,6)            :: cov_elm, partials, &
+         jacobian_lt_corr, jacobian_prop, jacobian
+    REAL(bp)                            :: det
+    INTEGER                             :: i, err, norb
+    LOGICAL                             :: lt_corr_
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getEphemeris", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getEphemeris", &
+            "'observer' has not been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Light-time correction is applied by default:
+    IF (PRESENT(lt_corr)) THEN
+       lt_corr_ = lt_corr
+    ELSE
+       lt_corr_ = .TRUE.
+    END IF
+
+    IF (ASSOCIATED(this%orb_arr_cmp) .AND. PRESENT(pdf_arr)) THEN
+       ! Sampled p.d.f.:
+       IF (PRESENT(this_lt_corr_arr) .AND. PRESENT(pdf_lt_corr_arr)) THEN
+          CALL getEphemeris(this%orb_arr_cmp, observer, ephemeris_arr, &
+               lt_corr=lt_corr_, partials_arr=partials_arr, &
+               this_lt_corr_arr=this_lt_corr_arr, &
+               jacobian_lt_corr_arr=jacobian_lt_corr_arr, &
+               jacobian_prop_arr=jacobian_prop_arr)
+       ELSE IF (.NOT.(PRESENT(this_lt_corr_arr) .OR. PRESENT(pdf_lt_corr_arr))) THEN
+          CALL getEphemeris(this%orb_arr_cmp, observer, ephemeris_arr, &
+               lt_corr=lt_corr_, partials_arr=partials_arr)
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "Are you sure you want to do this?", 1)
+          RETURN          
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "TRACE BACK", 1)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          RETURN
+       END IF
+       norb = SIZE(this%orb_arr_cmp, dim=1)
+       ALLOCATE(pdf_arr(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "Could not allocate memory.", 1)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       DO i=1,norb
+          det = determinant(partials_arr(i,:,:), errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getEphemeris", &
+                  "Computation of determinant of partials between " // &
+                  "ephemeris and orbital elements failed. " // &
+                  TRIM(errstr), 1)
+             errstr = ""
+             DEALLOCATE(ephemeris_arr, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             IF (PRESENT(this_lt_corr_arr)) THEN
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+             END IF
+             DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          ! Changed 2008-12-14
+          !pdf_arr(i) = this%pdf_arr_cmp(i)/ABS(det)
+          pdf_arr(i) = this%pdf_arr_cmp(i) * ABS(det)
+       END DO
+       DEALLOCATE(partials_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "Could not deallocate memory.", 1)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+          DEALLOCATE(jacobian_prop_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       IF (PRESENT(this_lt_corr_arr) .AND. PRESENT(pdf_lt_corr_arr)) THEN
+          ALLOCATE(pdf_lt_corr_arr(norb), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getEphemeris", &
+                  "Could not allocate memory.", 1)
+             DEALLOCATE(ephemeris_arr, stat=err)
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+             DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          DO i=1,norb
+             det = determinant(MATMUL(jacobian_lt_corr_arr(i,:,:), &
+                  jacobian_prop_arr(i,:,:)), errstr)
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / getEphemeris", &
+                     "Computation of determinant of partials between " // &
+                     "orbital elements at different epochs failed. " // &
+                     TRIM(errstr), 1)
+                errstr = ""
+                DEALLOCATE(ephemeris_arr, stat=err)
+                DEALLOCATE(this_lt_corr_arr, stat=err)
+                DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+                DEALLOCATE(jacobian_prop_arr, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                RETURN
+             END IF
+             ! Changed 2008-12-14
+             !pdf_lt_corr_arr(i) = this%pdf_arr_cmp(i)/ABS(det)
+             pdf_lt_corr_arr(i) = this%pdf_arr_cmp(i) * ABS(det)
+          END DO
+          DEALLOCATE(jacobian_lt_corr_arr, jacobian_prop_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getEphemeris", &
+                  "Could not deallocate memory.", 1)
+             DEALLOCATE(ephemeris_arr, stat=err)
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+             DEALLOCATE(jacobian_lt_corr_arr, stat=err)
+             DEALLOCATE(jacobian_prop_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+       END IF
+    ELSE IF (exist(this%orb_ml_cmp) .AND. PRESENT(cov)) THEN
+       ! Least squares solution + covariance matrix:
+       ALLOCATE(ephemeris_arr(1), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "Could not allocate memory.", 1)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          RETURN
+       END IF
+       cov_elm = getCovarianceMatrix(this, &
+            getElementType(this%orb_ml_cmp), &
+            getFrame(this%orb_ml_cmp))
+       IF (PRESENT(this_lt_corr_arr) .AND. PRESENT(cov_lt_corr)) THEN
+          ALLOCATE(this_lt_corr_arr(1), stat=err)
+          CALL getEphemeris(this%orb_ml_cmp, observer, ephemeris_arr(1), &
+               lt_corr=lt_corr_, partials=partials, &
+               this_lt_corr=this_lt_corr_arr(1), &
+               jacobian_lt_corr=jacobian_lt_corr, &
+               jacobian_prop=jacobian_prop)
+          jacobian = MATMUL(jacobian_lt_corr,jacobian_prop)
+          cov_lt_corr = MATMUL(MATMUL(jacobian, cov_elm), &
+               TRANSPOSE(jacobian))
+       ELSE IF (.NOT.(PRESENT(this_lt_corr_arr) .OR. PRESENT(pdf_lt_corr_arr))) THEN
+          CALL getEphemeris(this%orb_ml_cmp, observer, ephemeris_arr(1), &
+               lt_corr=lt_corr_, partials=partials)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getEphemeris", &
+               "TRACE BACK", 1)
+          DEALLOCATE(ephemeris_arr, stat=err)
+          IF (PRESENT(this_lt_corr_arr)) THEN
+             DEALLOCATE(this_lt_corr_arr, stat=err)
+          END IF
+          RETURN
+       END IF
+       cov = MATMUL(MATMUL(partials, cov_elm), &
+            TRANSPOSE(partials))
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getEphemeris", &
+            "Ephemeris cannot be requested without proper uncertainty estimate.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE getEphemeris_SO
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getGroupWeights(this, weights, groups, apriori_pdf)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)           :: this
+    REAL(bp), DIMENSION(:), POINTER              :: weights
+    CHARACTER(len=*), DIMENSION(:), POINTER      :: groups
+    REAL(bp), DIMENSION(:), INTENT(in), OPTIONAL :: apriori_pdf
+
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: elements
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: periapsis, apoapsis, pdf
+    LOGICAL, DIMENSION(:), POINTER :: mask_array, mask_array_tot
+    INTEGER :: norb, err, i, ngroup
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getGroupWeights", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ngroup = 17
+    IF (.NOT. ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getGroupWeights", &
+            "No sample orbits available.", 1)
+       RETURN
+    END IF
+    norb = SIZE(this%orb_arr_cmp,dim=1)
+    ALLOCATE(weights(ngroup), groups(ngroup), elements(norb,6), &
+         apoapsis(norb), periapsis(norb), mask_array(norb), &
+         mask_array_tot(norb), pdf(norb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getGroupWeights", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    mask_array_tot = .TRUE. ! which are left?
+    pdf = this%pdf_arr_cmp
+    pdf = pdf / SUM(pdf)
+    DO i=1,norb
+       elements(i,:) = getElements(this%orb_arr_cmp(i), "keplerian")
+    END DO
+    apoapsis = elements(:,1) * (1.0_bp + elements(:,2))
+    periapsis = elements(:,1) * (1.0_bp - elements(:,2))
+    IF (PRESENT(apriori_pdf)) THEN
+       IF (SIZE(apriori_pdf,dim=1) /= norb) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getGroupWeights", &
+               "Size of a priori array not consistent with number of orbits.", 1)
+          RETURN
+       END IF
+       pdf(1:norb) = pdf(1:norb)*apriori_pdf(1:norb)
+       IF (SUM(pdf) < EPSILON(pdf(1))) THEN
+          pdf = 0.0_bp
+       ELSE
+          pdf = pdf / SUM(pdf)
+       END IF
+    END IF
+
+    ! Atira (AKA IEO AKA Apohele)
+    groups(1) = "Atira"
+    mask_array = .FALSE.
+    WHERE (apoapsis <= 0.983_bp)
+       mask_array = .TRUE.
+    END WHERE
+    weights(1) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Aten
+    groups(2) = "NEO/Aten"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) <= 1.0_bp .AND. &
+         apoapsis > 0.983_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(2) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Apollo
+    groups(3) = "NEO/Apollo"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) > 1.0_bp .AND. &
+         periapsis <= 1.017_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(3) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Amor
+    groups(4) = "NEO/Amor"
+    mask_array = .FALSE.
+    WHERE (periapsis > 1.017_bp .AND. &
+         periapsis <= 1.3_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(4) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Aethra (Mars crosser)
+    groups(5) = "Aethra"
+    mask_array = .FALSE.
+    WHERE (periapsis > 1.3_bp .AND. &
+         periapsis <= 5.0_bp/3.0_bp .AND. & ! 1.6666... AU
+         mask_array_tot) mask_array = .TRUE.
+    weights(5) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Hungaria
+    groups(6) = "Hungaria"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 1.8_bp .AND. &
+         elements(:,1) <= 2.0_bp .AND. &
+         elements(:,2) >= 0.0_bp .AND. &
+         elements(:,2) <= 0.16_bp .AND. &
+         elements(:,3) >= 15.0_bp .AND. &
+         elements(:,3) <= 35.0_bp .AND. &
+         periapsis > 5.0_bp/3.0_bp .AND. & ! 1.6666... AU
+         mask_array_tot) mask_array = .TRUE.
+    weights(6) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Phocaea (part of the mainbelt)
+    groups(7) = "MBO/Phocaea"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 2.26_bp .AND. &
+         elements(:,1) <= 2.50_bp .AND. &
+         elements(:,2) >= 0.1_bp .AND. &
+         elements(:,2) <= 0.3_bp .AND. &
+         elements(:,3) >= 10.0_bp .AND. &
+         elements(:,3) <= 30.0_bp .AND. &
+         periapsis > 5.0_bp/3.0_bp .AND. & ! 1.6666... AU
+         mask_array_tot) mask_array = .TRUE.
+    weights(7) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Mainbelt (without Phocaea)
+    groups(8) = "MBO exc. Phocaea"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 2.1_bp .AND. &
+         elements(:,1) <= 3.5_bp .AND. &
+         elements(:,2) >= 0.0_bp .AND. &
+         elements(:,2) <= 0.35_bp .AND. &
+         elements(:,3) >= 0.0_bp .AND. &
+         elements(:,3) <= 35.0_bp .AND. &
+         periapsis > 5.0_bp/3.0_bp .AND. & ! 1.6666... AU
+         periapsis <= 4.95_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(8) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Hilda
+    groups(9) = "Hilda"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 3.75_bp .AND. &
+         elements(:,1) <= 4.02_bp .AND. &
+         elements(:,2) >= 0.0_bp .AND. &
+         elements(:,2) <= 0.26_bp .AND. &
+         elements(:,3) >= 0.0_bp .AND. &
+         elements(:,3) <= 18.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(9) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Jupiter Trojan
+    groups(10) = "Jupiter Trojan"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 5.08_bp .AND. &
+         elements(:,1) <= 5.33_bp .AND. &
+         elements(:,2) >= 0.0_bp .AND. &
+         elements(:,2) <= 0.28_bp .AND. &
+         elements(:,3) >= 0.0_bp .AND. &
+         elements(:,3) <= 40.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(10) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Centaur
+    groups(11) = "Centaur"
+    mask_array = .FALSE.
+    WHERE (periapsis > 5.023_bp .AND. &
+         apoapsis < 30.06_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(11) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! TNO Inner belt
+    groups(12) = "TNO/Inner belt"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 36.0_bp .AND. &
+         elements(:,1) <= 39.0_bp .AND. &
+         periapsis > 35.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(12) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Plutino
+    groups(13) = "TNO/Plutino"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) > 39.0_bp .AND. &
+         periapsis < 40.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(13) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Classical TNO
+    groups(14) = "TNO/Classical"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) >= 40.0_bp .AND. &
+         elements(:,1) <= 48.0_bp .AND. &
+         periapsis > 35.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(14) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! TNO Outer belt
+    groups(15) = "TNO/Outer belt"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) > 48.0_bp .AND. &
+         periapsis > 36.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(15) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! Scattered TNO
+    groups(16) = "TNO/Scattered"
+    mask_array = .FALSE.
+    WHERE (elements(:,1) > 49.0_bp .AND. &
+         periapsis < 36.0_bp .AND. &
+         mask_array_tot) mask_array = .TRUE.
+    weights(16) = SUM(pdf,mask=mask_array)
+    WHERE (mask_array) mask_array_tot = .FALSE.
+
+    ! The rest
+    groups(17) = "The rest"
+    weights(17) = SUM(pdf,mask=mask_array_tot)
+
+    DEALLOCATE(elements, pdf, mask_array, mask_array_tot, &
+         periapsis, apoapsis, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getGroupWeights", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE getGroupWeights
+
+
+
+
+
+  CHARACTER(len=DESIGNATION_LEN) FUNCTION getID_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+
+    getID_SO = this%id_prm
+
+  END FUNCTION getID_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes an rms value using mean residuals computed using the
+  !! sample orbits.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getMeanRMS(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), DIMENSION(6)                :: getMeanRMS
+    INTEGER                               :: norb, i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getMeanRMS", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. ASSOCIATED(this%rms_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getMeanRMS", &
+            "RMSs are missing -> make an orbit distribution.", 1)
+       RETURN       
+    END IF
+
+    norb = SIZE(this%rms_arr_cmp,dim=1)
+    getMeanRMS = 0.0_bp
+    DO i=1,6
+       getMeanRMS(i) = SUM(this%rms_arr_cmp(:,i))/norb
+    END DO
+
+  END FUNCTION getMeanRMS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Depending on the orbital solution returns either 
+  !! 
+  !!  - a discrete sampling of the periapsis distance
+  !!    probability-density function, or
+  !!
+  !!  - the nominal periapsis distance and its 1-sigma uncertainty.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPeriapsisDistance_SO(this, q)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), DIMENSION(:,:), POINTER     :: q
+
+    TYPE (Orbit) :: orb
+    REAL(bp), DIMENSION(6,6) :: partials, covariance1, covariance2
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    REAL(bp) :: jac
+    INTEGER :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPeriapsisDistance", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (containsSampledPDF(this)) THEN
+
+       pdf_arr => getPDFValues(this, "keplerian")
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+
+       ALLOCATE(q(SIZE(this%orb_arr_cmp,dim=1),2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "Could not allocate memory (5).", 1)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       partials = identity_matrix(6)
+       DO i=1,SIZE(this%orb_arr_cmp,dim=1)
+          CALL getPeriapsisDistance(this%orb_arr_cmp(i), &
+               q(i,1), partials=partials(1,1:6))
+          IF (error) THEN
+             CALL errorMessage("Orbit / getPeriapsisDistance", &
+                  "TRACE BACK (5)", 1)
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          jac = ABS(determinant(partials, errstr))
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Orbit / getPeriapsisDistance", &
+                  "Could not compute determinant for Jacobian. " // &
+                  TRIM(errstr), 1)
+             errstr = ""
+             DEALLOCATE(pdf_arr, stat=err)
+             RETURN
+          END IF
+          q(i,2) = pdf_arr(i)*jac
+       END DO
+
+       DEALLOCATE(pdf_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPeriapsisDistance", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+
+    ELSE
+
+       ALLOCATE(q(1,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+       orb = copy(this%orb_ml_cmp)
+       CALL toKeplerian(orb)
+       partials = identity_matrix(6)
+       CALL getPeriapsisDistance(orb, &
+            q(1,1), &
+            partials=partials(1,1:6))
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPeriapsisDistance", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(orb)
+
+       covariance1 = getCovarianceMatrix(this, "keplerian")
+       covariance2 = MATMUL(MATMUL(partials,covariance1),TRANSPOSE(partials))
+       q(1,2) = SQRT(covariance2(1,1))
+
+    END IF
+
+  END SUBROUTINE getPeriapsisDistance_SO
+
+
+
+
+
+  !! Computes the probability of the target described by the sample
+  !! orbits being a PHA (MOID wrt. the Earth <= 0.05 AU) at a given  
+  !! moment (determined by the epoch of the sample orbits). 
+  !! Computations are done using the 2-body approximation.
+  !!
+  REAL(bp) FUNCTION getPHAProbability(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)  :: this
+    TYPE (Orbit)                        :: orbit_earth
+    TYPE (Time)                         :: t
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: moid, pdf
+    REAL(bp), DIMENSION(:,:), POINTER   :: elem
+    REAL(bp)                            :: mjd_tdt
+    INTEGER                             :: norb, err, i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "No sample orbits available.", 1)
+       RETURN
+    END IF
+
+    t = getTime(this%orb_arr_cmp(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    mjd_tdt = getMJD(t, "tdt")
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    elem => JPL_ephemeris(mjd_tdt, 3, 11, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(orbit_earth)
+    CALL NEW(orbit_earth, elem(1,:), "cartesian", "equatorial", t)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+    DEALLOCATE(elem, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+    CALL toKeplerian(orbit_earth)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+
+    norb = SIZE(this%orb_arr_cmp,dim=1)
+    ALLOCATE(moid(norb), pdf(norb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    pdf = this%pdf_arr_cmp
+    pdf = pdf / SUM(pdf)
+
+    getPHAProbability = 0.0_bp
+    DO i=1,norb
+       moid(i) = getMOID(orbit_earth, this%orb_arr_cmp(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getPHAProbability", &
+               "TRACE BACK (35)", 1)
+          RETURN
+       END IF
+       IF (moid(i) <= 0.05_bp) THEN
+          getPHAProbability = getPHAProbability + pdf(i)
+       END IF
+    END DO
+
+    DEALLOCATE(moid, pdf, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPHAProbability", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getPHAProbability
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getNominalOrbit(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Orbit)                       :: getNominalOrbit
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getNominalOrbit", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(this%orb_ml_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getNominalOrbit", &
+            "The nominal orbit is not available.", 1)
+       RETURN
+    END IF
+
+    getNominalOrbit = copy(this%orb_ml_cmp)
+
+  END FUNCTION getNominalOrbit
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION getNrOfSampleOrbits(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getNrOfSampleOrbits", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getNrOfSampleOrbits", &
+            "Sample orbits do not exist.", 1)       
+       RETURN
+    END IF
+
+    getNrOfSampleOrbits = SIZE(this%orb_arr_cmp,dim=1)
+
+  END FUNCTION getNrOfSampleOrbits
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservationMasks_SO(this) RESULT(obs_masks)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    LOGICAL, DIMENSION(:,:), POINTER   :: obs_masks
+    INTEGER                            :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getObservationMasks", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%obs_masks_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getObservationMasks", &
+            "Observation masks have not been allocated.", 1)
+       RETURN       
+    END IF
+
+    ALLOCATE(obs_masks(SIZE(this%obs_masks_prm,dim=1), &
+         SIZE(this%obs_masks_prm,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getObservationMasks", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    obs_masks = this%obs_masks_prm
+
+  END FUNCTION getObservationMasks_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservations_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Observations) :: getObservations_SO
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getObservations", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    getObservations_SO = copy(this%obss)
+
+  END FUNCTION getObservations_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getObservationPairs(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    INTEGER, DIMENSION(:,:), POINTER   :: getObservationPairs
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getObservationPair", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getObservationPairs(SIZE(this%sor_pair_arr_prm,dim=1), &
+         SIZE(this%sor_pair_arr_prm,dim=2)))
+
+    getObservationPairs = this%sor_pair_arr_prm
+
+  END FUNCTION getObservationPairs
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getParameters_SO(this, &
+       dyn_model, &
+       perturbers, &
+       integration_step, &
+       integrator, &
+       finite_diff, &
+       t_inv, &
+       element_type, &
+       multiple_objects, &
+       outlier_rejection, &
+       dchi2_rejection, regularized_pdf, &
+       accept_multiplier, &
+       outlier_multiplier, &
+       res_accept, &
+       gaussian_pdf, &
+       chi2_min_init_prm, &
+       chi2_min_prm, &
+       dchi2_prm, &
+       prob_mass, &
+       apriori_a_max, apriori_a_min, apriori_periapsis_max, apriori_periapsis_min, &
+       apriori_apoapsis_max, apriori_apoapsis_min, apriori_rho_max, apriori_rho_min, &
+       sor_2point_method, &
+       sor_norb, sor_norb_sw, &
+       sor_ntrial, sor_ntrial_sw, &
+       sor_rho1_l, sor_rho1_u, &
+       sor_rho2_l, sor_rho2_u, &
+       sor_random_obs_selection, & 
+       sor_niter, &
+       generat_multiplier, &
+       sor_deviates, &
+       vov_norb, vov_ntrial, vov_norb_iter, vov_ntrial_iter, &
+       vov_nmap, vov_niter, vov_scaling, vov_mapping_mask, &
+       vomcmc_norb, vomcmc_ntrial, vomcmc_norb_iter, vomcmc_ntrial_iter, &
+       vomcmc_nmap, vomcmc_niter, vomcmc_scaling, vomcmc_mapping_mask, &
+       ls_correction_factor, ls_niter_major_max, ls_niter_major_min, ls_niter_minor, &
+       ls_element_mask, &
+       smplx_tol, smplx_niter, smplx_force, smplx_similarity_tol, &
+       os_norb, os_ntrial, os_sampling_type, generat_gaussian_deviates)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Time), INTENT(out), OPTIONAL :: t_inv
+    CHARACTER(len=*), INTENT(out), OPTIONAL :: &
+         dyn_model, &
+         integrator, &
+         element_type, &
+         sor_2point_method
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: &
+         sor_deviates
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL :: &
+         res_accept
+    REAL(bp), DIMENSION(6,2), INTENT(out), OPTIONAL :: &
+         vov_scaling, &
+         vomcmc_scaling
+    REAL(bp), DIMENSION(6), INTENT(out), OPTIONAL :: &
+         finite_diff
+    REAL(bp), INTENT(out), OPTIONAL :: &
+         integration_step, &
+         accept_multiplier, &
+         outlier_multiplier, &
+         chi2_min_init_prm, &
+         chi2_min_prm, &
+         dchi2_prm, &
+         apriori_a_max, &
+         apriori_a_min, &
+         apriori_periapsis_max, &
+         apriori_periapsis_min, &
+         apriori_apoapsis_max, &
+         apriori_apoapsis_min, &
+         apriori_rho_max, &
+         apriori_rho_min, &
+         prob_mass, &
+         sor_rho1_l, &
+         sor_rho1_u, &
+         sor_rho2_l, &
+         sor_rho2_u, &
+         generat_multiplier, &
+         ls_correction_factor, &
+         smplx_tol, &
+         smplx_similarity_tol
+    INTEGER, INTENT(out), OPTIONAL :: &
+         sor_norb, &
+         sor_norb_sw, &
+         sor_ntrial, &
+         sor_ntrial_sw, &
+         sor_niter, &
+         vov_norb, &
+         vov_ntrial, &
+         vov_norb_iter, &
+         vov_ntrial_iter, &
+         vov_nmap, &
+         vov_niter, &
+         vomcmc_norb, &
+         vomcmc_ntrial, &
+         vomcmc_norb_iter, &
+         vomcmc_ntrial_iter, &
+         vomcmc_nmap, &
+         vomcmc_niter, &
+         ls_niter_major_max, &
+         ls_niter_major_min, &
+         ls_niter_minor, &
+         smplx_niter, &
+         os_norb, &
+         os_ntrial, &
+         os_sampling_type
+    LOGICAL, DIMENSION(:), INTENT(out), OPTIONAL :: &
+         perturbers, &
+         vov_mapping_mask, &
+         vomcmc_mapping_mask, &
+         ls_element_mask
+    LOGICAL, INTENT(out), OPTIONAL :: &
+         multiple_objects, &
+         regularized_pdf, &
+         dchi2_rejection, &
+         sor_random_obs_selection, &
+         gaussian_pdf, &
+         outlier_rejection, &
+         smplx_force, &
+         generat_gaussian_deviates
+    INTEGER :: err
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getParameters", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(dyn_model)) THEN
+       dyn_model = this%dyn_model_prm
+    END IF
+    IF (PRESENT(perturbers)) THEN
+       perturbers = this%perturbers_prm
+    END IF
+    IF (PRESENT(integration_step)) THEN
+       integration_step = this%integration_step_prm
+    END IF
+    IF (PRESENT(integrator)) THEN
+       integrator = this%integrator_prm
+    END IF
+    IF (PRESENT(finite_diff)) THEN
+       IF (ASSOCIATED(this%finite_diff_prm)) THEN
+          finite_diff = this%finite_diff_prm
+       ELSE
+          finite_diff = -1.0_bp
+       END IF
+    END IF
+    IF (PRESENT(t_inv)) THEN
+       t_inv = copy(this%t_inv_prm)
+    END IF
+    IF (PRESENT(element_type)) THEN
+       element_type = this%element_type_prm 
+    END IF
+    IF (PRESENT(multiple_objects)) THEN
+       multiple_objects = this%multiple_obj_prm 
+    END IF
+    IF (PRESENT(outlier_rejection)) THEN
+       outlier_rejection = this%outlier_rejection_prm
+    END IF
+    IF (PRESENT(outlier_multiplier)) THEN
+       outlier_multiplier = this%outlier_multiplier_prm 
+    END IF
+    IF (PRESENT(dchi2_rejection)) THEN
+       dchi2_rejection = this%dchi2_rejection_prm 
+    END IF
+    IF (PRESENT(regularized_pdf)) THEN
+       regularized_pdf = this%regularization_prm 
+    END IF
+    IF (PRESENT(accept_multiplier)) THEN
+       accept_multiplier = this%accept_multiplier_prm 
+    END IF
+    IF (PRESENT(res_accept)) THEN
+       IF (ASSOCIATED(this%res_accept_prm)) THEN
+          ALLOCATE(res_accept(SIZE(this%res_accept_prm,dim=1), &
+               SIZE(this%res_accept_prm,dim=2)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getParameters", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          res_accept = this%res_accept_prm
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getParameters", &
+               "Acceptance windows not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(chi2_min_init_prm)) THEN
+       chi2_min_init_prm = this%chi2_min_init_prm 
+    END IF
+    IF (PRESENT(chi2_min_prm)) THEN
+       chi2_min_prm = this%chi2_min_prm 
+    END IF
+    IF (PRESENT(dchi2_prm)) THEN
+       dchi2_prm = this%dchi2_prm 
+    END IF
+    IF (PRESENT(prob_mass)) THEN
+       ! prob_mass = getProbabilityMass(this%dchi2_prm)
+       ! temporarily
+       prob_mass = this%dchi2_prm
+    END IF
+    IF (PRESENT(apriori_a_max)) THEN
+       apriori_a_max = this%apriori_a_max_prm
+    END IF
+    IF (PRESENT(apriori_a_min)) THEN
+       apriori_a_min = this%apriori_a_min_prm
+    END IF
+    IF (PRESENT(apriori_periapsis_max)) THEN
+       apriori_periapsis_max = this%apriori_periapsis_max_prm
+    END IF
+    IF (PRESENT(apriori_periapsis_min)) THEN
+       apriori_periapsis_min = this%apriori_periapsis_min_prm
+    END IF
+    IF (PRESENT(apriori_apoapsis_max)) THEN
+       apriori_apoapsis_max = this%apriori_apoapsis_max_prm
+    END IF
+    IF (PRESENT(apriori_apoapsis_min)) THEN
+       apriori_apoapsis_min = this%apriori_apoapsis_min_prm
+    END IF
+    IF (PRESENT(apriori_rho_max)) THEN
+       apriori_rho_max = this%apriori_rho_max_prm
+    END IF
+    IF (PRESENT(apriori_rho_min)) THEN
+       apriori_rho_min = this%apriori_rho_min_prm
+    END IF
+    IF (PRESENT(sor_2point_method)) THEN
+       sor_2point_method = this%sor_2point_method_prm
+    END IF
+    IF (PRESENT(sor_norb)) THEN
+       sor_norb = this%sor_norb_prm
+    END IF
+    IF (PRESENT(sor_norb_sw)) THEN
+       sor_norb_sw = this%sor_norb_sw_prm 
+    END IF
+    IF (PRESENT(sor_ntrial)) THEN
+       sor_ntrial = this%sor_ntrial_prm 
+    END IF
+    IF (PRESENT(sor_ntrial_sw)) THEN
+       sor_ntrial_sw = this%sor_ntrial_sw_prm
+    END IF
+    IF (PRESENT(sor_rho1_l)) THEN
+       sor_rho1_l = this%sor_rho_prm(1,1) 
+    END IF
+    IF (PRESENT(sor_rho1_u)) THEN
+       sor_rho1_u = this%sor_rho_prm(1,2) 
+    END IF
+    IF (PRESENT(sor_rho2_l)) THEN
+       sor_rho2_l = this%sor_rho_prm(2,1)
+    END IF
+    IF (PRESENT(sor_rho2_u)) THEN
+       sor_rho2_u = this%sor_rho_prm(2,2)
+    END IF
+    IF (PRESENT(sor_random_obs_selection)) THEN
+       sor_random_obs_selection = this%sor_random_obs_prm
+    END IF
+    IF (PRESENT(sor_niter)) THEN
+       sor_niter = this%sor_niter_prm 
+    END IF
+
+    IF (PRESENT(gaussian_pdf)) THEN
+       gaussian_pdf = this%sor_gaussian_pdf_prm
+    END IF
+    IF (PRESENT(generat_multiplier)) THEN
+       generat_multiplier = this%generat_multiplier_prm 
+    END IF
+    IF (PRESENT(generat_gaussian_deviates)) THEN
+       generat_gaussian_deviates = this%generat_gaussian_deviates_prm 
+    END IF
+    IF (PRESENT(sor_deviates)) THEN
+       IF (ASSOCIATED(this%sor_deviates_prm)) THEN
+          ALLOCATE(sor_deviates(SIZE(this%sor_deviates_prm,dim=1), &
+               SIZE(this%sor_deviates_prm,dim=2), &
+               SIZE(this%sor_deviates_prm,dim=3)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getParameters", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          sor_deviates = this%sor_deviates_prm
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getParameters", &
+               "Generation windows not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(vov_norb)) THEN
+       vov_norb = this%vov_norb_prm
+    END IF
+    IF (PRESENT(vov_ntrial)) THEN
+       vov_ntrial = this%vov_ntrial_prm 
+    END IF
+    IF (PRESENT(vov_norb_iter)) THEN
+       vov_norb_iter = this%vov_norb_iter_prm 
+    END IF
+    IF (PRESENT(vov_ntrial_iter)) THEN
+       vov_ntrial_iter = this%vov_ntrial_iter_prm 
+    END IF
+    IF (PRESENT(vov_nmap)) THEN
+       vov_nmap = this%vov_nmap_prm 
+    END IF
+    IF (PRESENT(vov_niter)) THEN
+       vov_niter = this%vov_niter_prm 
+    END IF
+    IF (PRESENT(vov_scaling)) THEN
+       vov_scaling = this%vov_scaling_prm
+    END IF
+    IF (PRESENT(vov_mapping_mask)) THEN
+       vov_mapping_mask = this%vov_mapping_mask_prm 
+    END IF
+    IF (PRESENT(vomcmc_norb)) THEN
+       vomcmc_norb = this%vomcmc_norb_prm
+    END IF
+    IF (PRESENT(vomcmc_ntrial)) THEN
+       vomcmc_ntrial = this%vomcmc_ntrial_prm 
+    END IF
+    IF (PRESENT(vomcmc_norb_iter)) THEN
+       vomcmc_norb_iter = this%vomcmc_norb_iter_prm 
+    END IF
+    IF (PRESENT(vomcmc_ntrial_iter)) THEN
+       vomcmc_ntrial_iter = this%vomcmc_ntrial_iter_prm 
+    END IF
+    IF (PRESENT(vomcmc_nmap)) THEN
+       vomcmc_nmap = this%vomcmc_nmap_prm 
+    END IF
+    IF (PRESENT(vomcmc_niter)) THEN
+       vomcmc_niter = this%vomcmc_niter_prm 
+    END IF
+    IF (PRESENT(vomcmc_scaling)) THEN
+       vomcmc_scaling = this%vomcmc_scaling_prm
+    END IF
+    IF (PRESENT(vomcmc_mapping_mask)) THEN
+       vomcmc_mapping_mask = this%vomcmc_mapping_mask_prm 
+    END IF
+    IF (PRESENT(ls_correction_factor)) THEN
+       ls_correction_factor = this%ls_corr_fac_prm 
+    END IF
+    IF (PRESENT(ls_niter_major_max)) THEN
+       ls_niter_major_max = this%ls_niter_major_max_prm
+    END IF
+    IF (PRESENT(ls_niter_major_min)) THEN
+       ls_niter_major_min = this%ls_niter_major_min_prm
+    END IF
+    IF (PRESENT(ls_niter_minor)) THEN
+       ls_niter_minor = this%ls_niter_minor_prm
+    END IF
+    IF (PRESENT(ls_element_mask)) THEN
+       ls_element_mask = this%ls_elem_mask_prm 
+    END IF
+    IF (PRESENT(smplx_tol)) THEN
+       smplx_tol = this%smplx_tol_prm 
+    END IF
+    IF (PRESENT(smplx_niter)) THEN
+       smplx_niter = this%smplx_niter_prm 
+    END IF
+    IF (PRESENT(smplx_force)) THEN
+       smplx_force = this%smplx_force_prm 
+    END IF
+    IF (PRESENT(smplx_similarity_tol)) THEN
+       smplx_similarity_tol = this%smplx_similarity_tol_prm
+    END IF
+    IF (PRESENT(os_norb)) THEN
+       os_norb = this%os_norb_prm 
+    END IF
+    IF (PRESENT(os_ntrial)) THEN
+       os_ntrial = this%os_ntrial_prm 
+    END IF
+    IF (PRESENT(os_sampling_type)) THEN
+       os_sampling_type = this%os_sampling_type_prm 
+    END IF
+
+
+  END SUBROUTINE getParameters_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPDFValues(this, element_type)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER    :: getPDFValues
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: element_type
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: jac
+    INTEGER                            :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPDFValues", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPDFValues", &
+            "PDF values do not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getPDFValues(SIZE(this%pdf_arr_cmp)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPDFValues", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(element_type)) THEN
+       ALLOCATE(jac(SIZE(this%pdf_arr_cmp)))
+       jac = 1.0_bp
+       IF (this%element_type_prm == "cartesian" .AND. &
+            element_type == "keplerian") THEN
+          ! Changed 2008-12-14
+          !jac = this%jac_arr_cmp(:,2)
+          jac = 1.0_bp/this%jac_arr_cmp(:,2)
+       ELSE IF (this%element_type_prm == "keplerian" .AND. &
+            element_type == "cartesian") THEN
+          ! Changed 2008-12-14
+          !jac = 1.0_bp/this%jac_arr_cmp(:,2)
+          jac = this%jac_arr_cmp(:,2)
+       ELSE IF (this%element_type_prm == "cometary" .OR. &
+            element_type == "cometary") THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPDFValues", &
+               "Not yet implemented for cometary elements.", 1)
+          RETURN
+       END IF
+       getPDFValues = this%pdf_arr_cmp*jac
+       DEALLOCATE(jac, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPDFValues", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+    ELSE
+       getPDFValues = this%pdf_arr_cmp
+    END IF
+
+  END FUNCTION getPDFValues
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a discrete sampling of phase-angle probability-density
+  !! function for an object on this orbit at a given epoch. The
+  !! observer coordinates are assumed to be exact.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPhaseAngle_SO_pdf(this, observer, phase_angle_pdf)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)         :: this
+    TYPE (CartesianCoordinates), INTENT(in)       :: observer
+    REAL(bp), DIMENSION(:,:), POINTER             :: phase_angle_pdf
+
+    REAL(bp), DIMENSION(6,6) :: partials
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    REAL(bp) :: jac
+    INTEGER :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Observer object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp) .OR. &
+         .NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Orbital-element pdf missing.", 1)
+       RETURN
+    END IF
+
+    pdf_arr => getPDFValues(this, "cartesian")
+    IF (error) THEN
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(pdf_arr, stat=err)
+       RETURN
+    END IF
+
+    ALLOCATE(phase_angle_pdf(SIZE(this%orb_arr_cmp,dim=1),2), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(pdf_arr, stat=err)
+       RETURN
+    END IF
+    partials = identity_matrix(6)
+    DO i=1,SIZE(this%orb_arr_cmp,dim=1)
+       CALL getPhaseAngle(this%orb_arr_cmp(i), observer, &
+            phase_angle_pdf(i,1), partials(1,1:6))
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPhaseAngle", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       jac = ABS(determinant(partials, errstr))
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Orbit / getPhaseAngle", &
+               "Could not compute determinant for Jacobian.", 1)
+          errstr = ""
+          DEALLOCATE(pdf_arr, stat=err)
+          RETURN
+       END IF
+       phase_angle_pdf(i,2) = pdf_arr(i)*jac
+    END DO
+
+    DEALLOCATE(pdf_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPhaseAngle", &
+            "Could not deallocate memory (10).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE getPhaseAngle_SO_pdf
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a phase angles corresponding to one or more orbits as
+  !! seen by one or more observers.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPhaseAngles_SO(this, observers, phase_angles)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)                 :: this
+    TYPE (CartesianCoordinates), DIMENSION(:), INTENT(in) :: observers
+    REAL(bp), DIMENSION(:,:), POINTER                     :: phase_angles
+
+    REAL(bp), DIMENSION(:), POINTER :: phase_angles_
+    INTEGER :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    DO i=1,SIZE(observers)
+       IF (.NOT.exist(observers(i))) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+               "All observer objects have not been initialized.", 1)
+          RETURN
+       END IF
+    END DO
+
+    IF (containsSampledPDF(this)) THEN
+       ALLOCATE(phase_angles(SIZE(this%orb_arr_cmp),SIZE(observers)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL getPhaseAngles(this%orb_arr_cmp(i), observers, phase_angles_)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+                  "TRACE BACK (5).", 1)
+             RETURN
+          END IF
+          phase_angles(i,:) = phase_angles_
+          DEALLOCATE(phase_angles_, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+                  "Could not deallocate memory (5).", 1)
+             RETURN
+          END IF
+       END DO
+    ELSE
+       CALL getPhaseAngles(this%orb_ml_cmp, observers, phase_angles_)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+               "TRACE BACK (10).", 1)
+          RETURN
+       END IF
+       ALLOCATE(phase_angles(1,SIZE(phase_angles_)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+               "Could not allocate memory (10).", 1)
+          RETURN
+       END IF
+       phase_angles(1,:) = phase_angles_
+       DEALLOCATE(phase_angles_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getPhaseAngles", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE getPhaseAngles_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the phase angle and its uncertainty for an object on
+  !! this orbit at a given epoch. The observer coordinates are assumed
+  !! to be exact.
+  !!
+  !! Returns error.
+  !! 
+  SUBROUTINE getPhaseAngle_SO_point(this, observer, phase_angle, sigma)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)   :: this
+    TYPE (CartesianCoordinates), INTENT(in) :: observer
+    REAL(bp), INTENT(out) :: phase_angle
+    REAL(bp), INTENT(out), OPTIONAL :: sigma
+
+    REAL(bp), DIMENSION(6,6) :: cov
+    REAL(bp), DIMENSION(1,6) :: partials
+    REAL(bp), DIMENSION(1,1) :: variance
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(observer)) THEN
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Observer object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Phase angle
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp) .AND. &
+         exist(this%orb_ml_cmp)) THEN
+       CALL getPhaseAngle(this%orb_ml_cmp, observer, phase_angle, &
+            partials(1,:))
+       IF (error) THEN
+          CALL errorMessage("Orbit / getPhaseAngle", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       IF (PRESENT(sigma)) THEN
+          ! Compute phase-angle uncertainty (sigma):
+          cov = getCovarianceMatrix(this, &
+               getElementType(this%orb_ml_cmp), &
+               getFrame(this%orb_ml_cmp))
+          IF (error) THEN
+             CALL errorMessage("Orbit / getPhaseAngle", &
+                  "TRACE BACK (10)", 1)
+             RETURN
+          END IF
+          variance(1:1,1:1) = MATMUL(MATMUL(partials(1:1,1:3), &
+               cov(1:3,1:3)), TRANSPOSE(partials(1:1,1:3)))
+          sigma = SQRT(variance(1,1))
+       END IF
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("Orbit / getPhaseAngle", &
+            "Either the orbital-element p.d.f. exist, " // &
+            "or the maximum likelihood orbit does not exist.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE getPhaseAngle_SO_point
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getPositionDistribution(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(:,:), POINTER  :: getPositionDistribution
+    INTEGER                            :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPositionDistribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPositionDistribution", &
+            "Sample orbits do not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getPositionDistribution(SIZE(this%orb_arr_cmp),3), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPositionDistribution", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(this%orb_arr_cmp)
+       getPositionDistribution(i,:) = getPosition(this%orb_arr_cmp(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getPositionDistribution", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+    END DO
+
+  END FUNCTION getPositionDistribution
+
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getRangeBounds_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(4)             :: getRangeBounds_SO
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRangeBounds", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    getRangeBounds_SO(1) = this%sor_rho_prm(1,1) 
+    getRangeBounds_SO(2) = this%sor_rho_prm(1,2)
+    getRangeBounds_SO(3) = this%sor_rho_prm(2,1)
+    getRangeBounds_SO(4) = this%sor_rho_prm(2,2)
+
+  END FUNCTION getRangeBounds_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getReducedChi2Distribution(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER    :: getReducedChi2Distribution
+    INTEGER                            :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getReducedChi2Distribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getReducedChi2Distribution", &
+            "Reduced chi2 array does not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getReducedChi2Distribution(SIZE(this%rchi2_arr_cmp,dim=1)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getReducedChi2Distribution", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    getReducedChi2Distribution(:) = this%rchi2_arr_cmp
+
+  END FUNCTION getReducedChi2Distribution
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getResidualDistribution(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)  :: this
+    REAL(bp), DIMENSION(:,:,:), POINTER :: getResidualDistribution
+    INTEGER                             :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResidualDistribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%res_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResidualDistribution", &
+            "Residuals do not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getResidualDistribution(SIZE(this%res_arr_cmp,dim=1), &
+         SIZE(this%res_arr_cmp,dim=2), SIZE(this%res_arr_cmp,dim=3)), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResidualDistribution", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    getResidualDistribution(:,:,:) = this%res_arr_cmp
+
+  END FUNCTION getResidualDistribution
+
+
+
+
+
+  FUNCTION getResiduals_SO_obss(this, obss)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)                   :: this
+    TYPE (Observations), INTENT(in)                      :: obss
+    REAL(bp), DIMENSION(:,:,:), POINTER                  :: getResiduals_SO_obss
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER   :: obsy_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: computed_scoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER   :: observed_scoords
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE              :: computed_coords
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE                :: observed_coords
+    INTEGER                                              :: err, i, j, nobs, norb
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResults", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResults", &
+            "Object 'obss' has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    norb = SIZE(this%orb_arr_cmp)
+    ALLOCATE(getResiduals_SO_obss(nobs,norb,6), observed_coords(nobs,6), &
+         computed_coords(nobs,norb,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    observed_scoords => getObservationSCoords(obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    obsy_ccoords => getObservatoryCCoords(obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+
+    CALL getEphemerides(this%orb_arr_cmp, obsy_ccoords, computed_scoords)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+    observed_coords = 0.0_bp
+    computed_coords = 0.0_bp
+    DO i=1,nobs
+       CALL rotateToEquatorial(observed_scoords(i))
+       observed_coords(i,:) = getCoordinates(observed_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getResiduals", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       DO j=1,norb
+          CALL rotateToEquatorial(computed_scoords(j,i))
+          computed_coords(i,j,:) = getCoordinates(computed_scoords(j,i))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / getResiduals", &
+                  "TRACE BACK (30)", 1)
+             RETURN
+          END IF
+       END DO
+    END DO
+
+    DO j=1,norb
+       getResiduals_SO_obss(1:nobs,j,1:6) = observed_coords(1:nobs,1:6) - &
+            computed_coords(1:nobs,j,1:6)        
+       getResiduals_SO_obss(1:nobs,j,2) = getResiduals_SO_obss(1:nobs,j,2) * &
+            COS(observed_coords(1:nobs,3))
+       DO i=1,nobs
+          IF (ABS(getResiduals_SO_obss(i,j,2)) > pi) THEN
+             IF (observed_coords(i,2) < computed_coords(i,j,2)) THEN
+                observed_coords(i,2) = observed_coords(i,2) + two_pi
+             ELSE
+                computed_coords(i,j,2) = computed_coords(i,j,2) + two_pi
+             END IF
+             getResiduals_SO_obss(i,j,2) = (observed_coords(i,2) - &
+                  computed_coords(i,j,2)) * COS(observed_coords(i,3))
+          END IF
+       END DO
+    END DO
+    DO i=1,SIZE(observed_scoords)
+       CALL NULLIFY(observed_scoords(i))
+    END DO
+    DO i=1,SIZE(obsy_ccoords)
+       CALL NULLIFY(obsy_ccoords(i))
+    END DO
+    DO i=1,SIZE(computed_scoords,dim=1)
+       DO j=1,SIZE(computed_scoords,dim=2)
+          CALL NULLIFY(computed_scoords(i,j))
+       END DO
+    END DO
+    DEALLOCATE(observed_coords, computed_coords, observed_scoords, &
+         obsy_ccoords, computed_scoords, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getResiduals_SO_obss
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getResiduals_SO_orb(this, orb)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)                 :: this
+    TYPE (Orbit), INTENT(in)                           :: orb
+    REAL(bp), DIMENSION(:,:), POINTER                  :: getResiduals_SO_orb
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: computed_scoords, &
+         observed_scoords
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE              :: observed_coords, &
+         computed_coords
+    INTEGER                                            :: err, i, nobs
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResults", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(orb)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResults", &
+            "Object 'orb' has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getResiduals_SO_orb(nobs,6), observed_coords(nobs,6), &
+         computed_coords(nobs,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    observed_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    obsy_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+
+    CALL getEphemerides(orb, obsy_ccoords, computed_scoords)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+    observed_coords = 0.0_bp
+    computed_coords = 0.0_bp
+    DO i=1,nobs
+       observed_coords(i,:) = getCoordinates(observed_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getResiduals", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+       computed_coords(i,:) = getCoordinates(computed_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getResiduals", &
+               "TRACE BACK (30)", 1)
+          RETURN
+       END IF
+    END DO
+
+    getResiduals_SO_orb(1:nobs,1:6) = observed_coords(1:nobs,1:6) - &
+         computed_coords(1:nobs,1:6)        
+    getResiduals_SO_orb(1:nobs,2) = getResiduals_SO_orb(1:nobs,2) * &
+         COS(observed_coords(1:nobs,3))
+    DO i=1,nobs
+       IF (ABS(getResiduals_SO_orb(i,2)) > pi) THEN
+          getResiduals_SO_orb(i,2) = two_pi - getResiduals_SO_orb(i,2)
+       END IF
+    END DO
+    DO i=1,SIZE(observed_scoords)
+       CALL NULLIFY(observed_scoords(i))
+    END DO
+    DO i=1,SIZE(obsy_ccoords)
+       CALL NULLIFY(obsy_ccoords(i))
+    END DO
+    DO i=1,SIZE(computed_scoords)
+       CALL NULLIFY(computed_scoords(i))
+    END DO
+    DEALLOCATE(observed_coords, computed_coords, observed_scoords, &
+         obsy_ccoords, computed_scoords, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResiduals", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getResiduals_SO_orb
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE getResults_SO(this,&
+       reg_apr_arr, jac_arr, repetition_arr_cmp, &
+       sor_norb_cmp, sor_ntrial_cmp,& 
+       sor_rho_cmp, sor_niter_cmp, &
+       sor_rho_arr_cmp, sor_rho_histo_cmp, &
+       vov_norb_cmp, vov_ntrial_cmp, &
+       vov_niter_cmp, vov_scaling_cmp, &
+       vov_map_cmp, vov_scaling_ready_cmp, &
+       vomcmc_norb_cmp, vomcmc_ntrial_cmp, &
+       vomcmc_niter_cmp, vomcmc_scaling_cmp, &
+       vomcmc_map_cmp, vomcmc_scaling_ready_cmp)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)              :: this
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL     :: &
+         jac_arr
+    REAL(bp), DIMENSION(:), POINTER, OPTIONAL       :: reg_apr_arr
+    INTEGER, DIMENSION(:), POINTER, OPTIONAL       :: repetition_arr_cmp
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL     :: sor_rho_arr_cmp
+    REAL(bp), DIMENSION(2,2), INTENT(out), OPTIONAL :: &
+         sor_rho_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: sor_norb_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: sor_ntrial_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: sor_niter_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: sor_rho_histo_cmp
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL     :: vov_map_cmp    
+    REAL(bp), DIMENSION(6,2), INTENT(out), OPTIONAL :: vov_scaling_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vov_norb_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vov_ntrial_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vov_niter_cmp
+    LOGICAL, DIMENSION(6,2), INTENT(out), OPTIONAL  :: vov_scaling_ready_cmp
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL     :: vomcmc_map_cmp    
+    REAL(bp), DIMENSION(6,2), INTENT(out), OPTIONAL :: vomcmc_scaling_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vomcmc_norb_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vomcmc_ntrial_cmp
+    INTEGER, INTENT(out), OPTIONAL                  :: vomcmc_niter_cmp
+    LOGICAL, DIMENSION(6,2), INTENT(out), OPTIONAL  :: vomcmc_scaling_ready_cmp
+    INTEGER :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getResults", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(reg_apr_arr)) THEN
+       IF (ASSOCIATED(this%reg_apr_arr_cmp)) THEN
+          ALLOCATE(reg_apr_arr(SIZE(this%reg_apr_arr_cmp)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          reg_apr_arr = this%reg_apr_arr_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "Apriori array not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jac_arr)) THEN
+       IF (ASSOCIATED(this%jac_arr_cmp)) THEN
+          ALLOCATE(jac_arr(SIZE(this%jac_arr_cmp,dim=1), &
+               SIZE(this%jac_arr_cmp,dim=2)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          jac_arr = this%jac_arr_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "Jacobians not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(repetition_arr_cmp)) THEN
+       IF (ASSOCIATED(this%repetition_arr_cmp)) THEN
+          ALLOCATE(repetition_arr_cmp(SIZE(this%repetition_arr_cmp)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          repetition_arr_cmp = this%repetition_arr_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "Repetition array not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(sor_norb_cmp)) THEN
+       sor_norb_cmp = this%sor_norb_cmp
+    END IF
+    IF (PRESENT(sor_ntrial_cmp)) THEN
+       sor_ntrial_cmp = this%sor_ntrial_cmp
+    END IF
+
+    IF (PRESENT(sor_rho_cmp)) THEN
+       sor_rho_cmp = this%sor_rho_cmp
+    END IF
+    IF (PRESENT(sor_niter_cmp)) THEN
+       sor_niter_cmp = this%sor_niter_cmp
+    END IF
+    IF (PRESENT(sor_rho_arr_cmp)) THEN
+       IF (ASSOCIATED(this%sor_rho_arr_cmp)) THEN
+          ALLOCATE(sor_rho_arr_cmp(SIZE(this%sor_rho_arr_cmp,dim=1),2), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          sor_rho_arr_cmp = this%sor_rho_arr_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "Generated rho values not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(sor_rho_histo_cmp)) THEN
+       sor_rho_histo_cmp = this%sor_rho_histo_cmp
+    END IF
+    IF (PRESENT(vov_norb_cmp)) THEN
+       vov_norb_cmp = this%vov_norb_cmp
+    END IF
+    IF (PRESENT(vov_ntrial_cmp)) THEN
+       vov_ntrial_cmp = this%vov_ntrial_cmp
+    END IF
+    IF (PRESENT(vov_niter_cmp)) THEN
+       vov_niter_cmp = this%vov_niter_cmp
+    END IF
+    IF (PRESENT(vov_scaling_cmp)) THEN
+       vov_scaling_cmp = this%vov_scaling_cmp
+    END IF
+    IF (PRESENT(vov_map_cmp)) THEN
+       IF (ASSOCIATED(this%vov_map_cmp)) THEN
+          ALLOCATE(vov_map_cmp(this%vov_nmap_prm,12), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          vov_map_cmp = this%vov_map_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "VoV map not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(vov_scaling_ready_cmp)) THEN
+       vov_scaling_ready_cmp = this%vov_scaling_ready_cmp 
+    END IF
+    IF (PRESENT(vomcmc_norb_cmp)) THEN
+       vomcmc_norb_cmp = this%vomcmc_norb_cmp
+    END IF
+    IF (PRESENT(vomcmc_ntrial_cmp)) THEN
+       vomcmc_ntrial_cmp = this%vomcmc_ntrial_cmp
+    END IF
+    IF (PRESENT(vomcmc_niter_cmp)) THEN
+       vomcmc_niter_cmp = this%vomcmc_niter_cmp
+    END IF
+    IF (PRESENT(vomcmc_scaling_cmp)) THEN
+       vomcmc_scaling_cmp = this%vomcmc_scaling_cmp
+    END IF
+    IF (PRESENT(vomcmc_map_cmp)) THEN
+       IF (ASSOCIATED(this%vomcmc_map_cmp)) THEN
+          ALLOCATE(vomcmc_map_cmp(this%vomcmc_nmap_prm,12), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getResults", &
+                  "Could not allocate memory.", 1)
+             RETURN
+          END IF
+          vomcmc_map_cmp = this%vomcmc_map_cmp
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getResults", &
+               "VoV map not available.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(vomcmc_scaling_ready_cmp)) THEN
+       vomcmc_scaling_ready_cmp = this%vomcmc_scaling_ready_cmp 
+    END IF
+
+  END SUBROUTINE getResults_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getRhoDistribution(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(:,:), POINTER  :: getRhoDistribution
+    INTEGER                            :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRhoDistribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%sor_rho_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRhoDistribution", &
+            "Rho distribution does not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getRhoDistribution(SIZE(this%sor_rho_arr_cmp,dim=1), &
+         SIZE(this%sor_rho_arr_cmp,dim=2)), stat=err)
+    getRhoDistribution = this%sor_rho_arr_cmp
+
+  END FUNCTION getRhoDistribution
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getRMS_single(this, orb)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Orbit), INTENT(inout)        :: orb
+    REAL(bp), DIMENSION(6)             :: getRMS_single
+    REAL(bp), DIMENSION(:,:), POINTER  :: residuals
+    INTEGER                            :: i, nobs, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMS", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    residuals => getResiduals(this, orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / getRMS", &
+            "TRACE BACK", 1)
+       RETURN       
+    END IF
+
+    nobs = SIZE(residuals,dim=1)
+    getRMS_single = 0.0_bp
+    DO i=1,6
+       getRMS_single(i) = SQRT(SUM(residuals(1:nobs,i)**2.0_bp)/nobs)
+    END DO
+
+    DEALLOCATE(residuals, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMS", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+
+  END FUNCTION getRMS_single
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getRMSDistribution(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)  :: this
+    REAL(bp), DIMENSION(:,:), POINTER   :: getRMSDistribution
+    INTEGER                             :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMSDistribution", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%rms_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMSDistribution", &
+            "rms distribution does not exist.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getRMSDistribution(SIZE(this%rms_arr_cmp,dim=1), &
+         SIZE(this%rms_arr_cmp,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMSDistribution", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    getRMSDistribution(:,:) = this%rms_arr_cmp
+
+  END FUNCTION getRMSDistribution
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the total O-C residual rms in the Pythagorean sense
+  !! (rms_tot = sqrt(rms_RA^2 + rms_Dec^2)) for each sample orbit.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getRMSValues(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(:), POINTER  :: getRMSValues
+    INTEGER                            :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getRMSValues", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    ALLOCATE(getRMSValues(SIZE(this%rms_arr_cmp,dim=1)))
+    DO i=1,SIZE(this%rms_arr_cmp,dim=1)
+       getRMSValues(i) = SQRT(SUM(this%rms_arr_cmp(i,2:3)**2.0_bp))
+    END DO
+
+  END FUNCTION getRMSValues
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getSampleOrbit_SO(this, index)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    INTEGER, INTENT(in)                :: index
+    TYPE (Orbit)                       :: getSampleOrbit_SO
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getSampleOrbit", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getSampleOrbit", &
+            "Sample orbits do not exist.", 1)
+       RETURN
+    END IF
+
+    getSampleOrbit_SO = copy(this%orb_arr_cmp(index))
+
+  END FUNCTION getSampleOrbit_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns orbits corresponding to the orbital-element PDF.
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getSampleOrbits(this, probability_mass, force_pdf)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in)  :: this
+    REAL(bp), INTENT(in), OPTIONAL :: probability_mass
+    LOGICAL, INTENT(in), OPTIONAL :: force_pdf
+    TYPE (Orbit), DIMENSION(:), POINTER :: getSampleOrbits
+
+    INTEGER, DIMENSION(:), ALLOCATABLE :: indx_arr
+    INTEGER :: err, i, j, norb
+    LOGICAL :: force_pdf_
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getSampleOrbits", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%orb_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getSampleOrbits", &
+            "Sample orbits do not exist.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(force_pdf)) THEN
+       force_pdf_ = force_pdf
+    ELSE
+       force_pdf_ = .FALSE.
+    END IF
+
+    IF (PRESENT(probability_mass)) THEN
+       ALLOCATE(indx_arr(SIZE(this%pdf_arr_cmp)))
+       IF (ASSOCIATED(this%repetition_arr_cmp) .AND. .NOT.force_pdf_) THEN
+          CALL credible_region(this%pdf_arr_cmp, probability_mass, indx_arr, errstr, this%repetition_arr_cmp)
+       ELSE
+          CALL credible_region(this%pdf_arr_cmp, probability_mass, indx_arr, errstr)
+       END IF
+       IF (LEN_TRIM(errstr) > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getSampleOrbits", &
+               "Error in computation of credible region: " // TRIM(errstr), 1)
+          RETURN
+       END IF
+       norb = 0
+       DO i=1,SIZE(indx_arr)
+          IF (indx_arr(i) > 0) THEN
+             norb = norb + 1
+          END IF
+       END DO
+       ALLOCATE(getSampleOrbits(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getSampleOrbits", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+       j = 0
+       DO i=1, SIZE(indx_arr)
+          IF (indx_arr(i) > 0) THEN
+             j = j + 1
+             getSampleOrbits(j) = copy(this%orb_arr_cmp(indx_arr(i)))
+          END IF
+       END DO
+       DEALLOCATE(indx_arr)
+    ELSE
+       ALLOCATE(getSampleOrbits(SIZE(this%orb_arr_cmp)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getSampleOrbits", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+       DO i=1, SIZE(this%orb_arr_cmp)
+          getSampleOrbits(i) = copy(this%orb_arr_cmp(i))
+       END DO
+    END IF
+
+
+  END FUNCTION getSampleOrbits
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getStandardDeviations_SO(this, element_type)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    REAL(bp), DIMENSION(6)             :: getStandardDeviations_SO, stdev
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: element_type
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: element_arr
+    REAL(bp), DIMENSION(:), POINTER :: pdf
+    CHARACTER(len=ELEMENT_TYPE_LEN)    :: element_type_
+    INTEGER                            :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPDFValues", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getPDFValues", &
+            "PDF values do not exist.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(element_type)) THEN
+       element_type_ = element_type
+    ELSE
+       element_type_ = this%element_type_prm
+    END IF
+
+    ALLOCATE(element_arr(SIZE(this%orb_arr_cmp,dim=1),6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getStandardDeviations", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(element_type)) THEN
+       pdf => getPDFValues(this, element_type)
+    ELSE
+       pdf = this%pdf_arr_cmp
+    ENDIF
+
+    DO i=1,SIZE(this%orb_arr_cmp,dim=1)
+       !       IF (element_type_ == "cartesian") THEN
+       !          CALL rotateToEcliptic(this%orb_arr_cmp(l))
+       !       END IF
+       element_arr(i,1:6) = getElements(this%orb_arr_cmp(i), element_type_)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / getStandardDeviations", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+    END DO
+    DO i=1,6
+       CALL moments(element_arr(:,i), pdf=pdf, std_dev=stdev(i), &
+            errstr=errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / getStandardDeviations", &
+               "TRACE BACK (15) " // TRIM(errstr), 1)
+          RETURN
+       END IF
+    END DO
+    getStandardDeviations_SO = stdev
+
+    DEALLOCATE(pdf, element_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getStandardDeviations", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION getStandardDeviations_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getTime_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+    TYPE (Time)                        :: getTime_SO
+    TYPE (Time)                        :: t
+    INTEGER                            :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getTime", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (exist(this%orb_ml_cmp) .AND. .NOT. ASSOCIATED(this%orb_arr_cmp)) THEN
+       t = getTime(this%orb_ml_cmp)
+    ELSE IF (.NOT.exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%orb_arr_cmp)) THEN
+       t = getTime(this%orb_arr_cmp(1))
+       DO i=2,SIZE(this%orb_arr_cmp,dim=1)
+          IF (.NOT.equal(getTime(this%orb_arr_cmp(i)),t)) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getTime", &
+                  "Sample orbits have different epochs.", 1)
+             CALL NULLIFY(t)
+             RETURN
+          END IF
+       END DO
+    ELSE IF (exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%orb_arr_cmp)) THEN
+       t = getTime(this%orb_ml_cmp)
+       DO i=1,SIZE(this%orb_arr_cmp,dim=1)
+          IF (.NOT.equal(getTime(this%orb_arr_cmp(i)),t)) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / getTime", &
+                  "Sample orbits and the nominal orbit have different epochs.", 1)
+             CALL NULLIFY(t)
+             RETURN
+          END IF
+       END DO
+    END IF
+
+    getTime_SO = copy(t)
+
+  END FUNCTION getTime_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION getTrials(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / getTrials", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getTrials = this%sor_ntrial_cmp
+
+  END FUNCTION getTrials
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE includeObservations(this, obss)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Observations), INTENT(in)       :: obss
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / includeObservations", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / includeObservations", &
+            "Observations not intialized.", 1)
+       RETURN
+    END IF
+
+    IF (exist(this%obss)) THEN
+       CALL NULLIFY(this%obss)
+       DEALLOCATE(this%obs_masks_prm)
+    END IF
+
+    this%obss = copy(obss)
+    this%obs_masks_prm => getObservationMasks(this%obss)
+
+    ! Initialize other variables needed in the computation
+    CALL setObservationPair(this)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / includeObservations", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE includeObservations
+
+
+
+
+
+  !! *Description:*
+  !!
+  !! Markov Chain Monte Carlo ranging method.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE MCMCRanging(this, first_orbit)
+
+    IMPLICIT NONE
+    TYPE(StochasticOrbit), INTENT(inout) :: this
+    TYPE(Orbit), INTENT(inout) :: first_orbit
+
+    TYPE(Orbit) :: orb
+    TYPE(SphericalCoordinates), DIMENSION(:), POINTER :: obs_scoords, comp_scoords !observed and computed sky positions
+    TYPE(SphericalCoordinates) :: obs_scoord1, obs_scoord2, obs_help
+    TYPE(CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE(CartesianCoordinates) :: obs_ccoord_helio1, obs_ccoord_helio2, obs_ccoord_topo1, obs_ccoord_topo2
+    TYPE(Time) :: tt
+    REAL(bp), DIMENSION(:,:,:), POINTER :: information_matrix_obs, &
+         partials_arr
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: residuals, &
+         comp_coords, &
+         obs_coords, &
+         jacobians
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: cosdec0
+    REAL(bp), DIMENSION(6,6):: information_matrix_elem, jacobian_matrix
+    REAL(bp), DIMENSION(6) :: elements, rans, state, state_, proposal_density
+    REAL(bp), DIMENSION(3) :: pos
+    REAL(bp) :: chi2, pdf, pdf_, ran, t1, t2, obs_coord, jac_sph_inv, jac_sph_inv_, chi2_, chi2min, avalue
+    INTEGER, DIMENSION(:,:), POINTER :: obs_pair_arr
+    INTEGER, DIMENSION(6) :: n0, n0_
+    INTEGER, DIMENSION(2) :: obs_pair
+    INTEGER :: ndof, iorb, i, itrial, err, nobs, j, iorb_diff
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+
+    IF (info_verb >= 2) THEN
+       WRITE(*,*)"Starting MCMC ranging"
+    END IF
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+    IF (.NOT. exist(first_orbit)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "first_orbit has not yet been initialized.", 1)
+       RETURN
+    END IF
+    IF (ALL(proposal_density < 0.0_bp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Proposal density has not yet been defined.", 1)
+       RETURN
+    END IF
+    IF(.NOT.equal(getTime(first_orbit), this%t_inv_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Epochs not equal.", 1)
+       RETURN
+    END IF
+
+    ! Allocate memory for solution storing - orbits
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+    END IF
+    ALLOCATE(this%orb_arr_cmp(this%sor_norb_prm), stat=err) 
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Could not allocate memory (5).", 1)
+       RETURN
+    END IF
+    nobs = getNrOfObservations(this%obss)
+    ALLOCATE(this%sor_rho_arr_cmp(this%sor_norb_prm,2), &
+         this%res_arr_cmp(this%sor_norb_prm,nobs,6), &
+         this%pdf_arr_cmp(this%sor_norb_prm), &
+         residuals(nobs,6), obs_coords(nobs,6), &
+         comp_coords(nobs, 6), cosdec0(nobs), &
+         this%reg_apr_arr_cmp(this%sor_norb_prm), &
+         this%jac_arr_cmp(this%sor_norb_prm,3), &
+         this%rchi2_arr_cmp(this%sor_norb_prm), &
+         this%rms_arr_cmp(this%sor_norb_prm,6), &
+                                !         this%wei_cmp(this%sor_norb_prm),&
+         jacobians(this%sor_norb_prm,3), &
+         obs_pair_arr(this%sor_norb_prm,2), &
+         this%cov_ml_cmp(6,6), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Could not allocate memory (10).", 1)
+       RETURN 
+    END IF
+    ! Allocate memory for solution storing - pdf 
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+    END IF
+    ALLOCATE(this%pdf_arr_cmp(this%sor_norb_prm), stat=err) 
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Could not allocate memory (15).", 1)
+       RETURN
+    END IF
+
+    ! Get observed sky positions (original observational data) 
+    obs_scoords => getObservationSCoords(this%obss) 
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    obs_coords = 0.0_bp
+    DO i=1,nobs
+       CALL rotateToEquatorial(obs_scoords(i))
+       obs_coords(i,:) = getCoordinates(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "TRACE BACK (10)", 1)
+          CALL NULLIFY(obs_scoords(i))
+          RETURN
+       END IF
+       ! CALL NULLIFY(obs_scoords(i))
+       cosdec0(i) = COS(obs_coords(i,3))
+    END DO
+
+    obs_masks => getObservationMasks(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    ! Observation number counter (observation mask must be up-to-date!), 
+    ! construct cosine array:
+    DO i=1,6
+       n0(i) = COUNT(obs_masks(:,i))
+    END DO
+    ndof = COUNT(obs_masks) - 6
+
+    information_matrix_obs => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (20)", 1)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(comp_coords, stat=err)
+       RETURN
+    END IF
+
+    obsy_ccoords => getObservatoryCCoords(this%obss) 
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+
+    ! Use predefined observation pair if not using random selection
+    IF (.NOT. this%sor_random_obs_prm) THEN
+       obs_pair = RESHAPE(this%sor_pair_arr_prm, (/ 2 /))
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Use of random observation pairs not accepted.", 1)
+       RETURN
+    END IF
+    ! Copy observation pair
+    obs_scoord1 = copy(obs_scoords(obs_pair(1)))
+    obs_scoord2 = copy(obs_scoords(obs_pair(2)))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (30)", 1)
+       RETURN
+    END IF
+
+    ! Calculate pdf value of the first orbit
+    orb = copy(first_orbit)
+    chi2 = getChi2(this, orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (35)", 1)
+       DEALLOCATE(obs_masks, stat=err)
+       RETURN
+    END IF
+    chi2_ = chi2
+
+    ! get partial derivatives
+    CALL getEphemerides(orb, obsy_ccoords, comp_scoords, partials_arr=partials_arr)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "TRACE BACK (40)", 1)
+       DEALLOCATE(comp_scoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       !DEALLOCATE(partial_arr, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(obs_masks, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(obs_coords, stat=err)         
+       DEALLOCATE(comp_coords, stat=err)
+       RETURN
+    END IF
+
+    jacobian_matrix(1:3,:) = partials_arr(1:3,:,obs_pair(1)) / &
+         cosdec0(obs_pair(1))
+    jacobian_matrix(4:6,:) = partials_arr(1:3,:,obs_pair(2)) / &
+         cosdec0(obs_pair(2))
+    jac_sph_inv = ABS(determinant(jacobian_matrix, errstr))
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Unsuccessful computation of determinant of orbital element " // &
+            "jacobian matrix: " // TRIM(errstr), 1)
+       CALL matrix_print(jacobian_matrix, stderr, errstr)
+       errstr = ""
+    END IF
+
+    ! proposal density
+    pos = getPosition(comp_scoords(obs_pair(1)))
+    proposal_density(1) = pos(1)
+    proposal_density(2) = 1.0_bp / SQRT(information_matrix_obs(obs_pair(1),2,2))
+    proposal_density(3) = 1.0_bp / SQRT(information_matrix_obs(obs_pair(1),3,3))
+    pos = getPosition(comp_scoords(obs_pair(2)))
+    proposal_density(4) = proposal_density(1) - pos(1)
+    proposal_density(5) = 1.0_bp / SQRT(information_matrix_obs(obs_pair(2),2,2))
+    proposal_density(6) = 1.0_bp / SQRT(information_matrix_obs(obs_pair(2),3,3))
+    IF (info_verb >= 2) THEN
+       WRITE(*,*)"Proposal density for the first observation (range[AU], RA[rad], dec[rad]): "
+       WRITE(*,*) proposal_density(1)
+       WRITE(*,*) proposal_density(2)
+       WRITE(*,*) proposal_density(3)
+       WRITE(*,*)"Proposal density for the second observation (drange[AU], RA[rad], dec[rad]): "
+       WRITE(*,*) proposal_density(4)
+       WRITE(*,*) proposal_density(5)
+       WRITE(*,*) proposal_density(6)
+    END IF
+
+    DEALLOCATE(comp_scoords, partials_arr)
+
+    pdf_  = EXP(-0.5_bp * (chi2 - ndof))
+    jac_sph_inv_ = jac_sph_inv
+
+    !set counter some parameters
+    this%sor_norb_cmp = 0
+    iorb = 0
+    itrial = 0 
+    iorb_diff = 0
+    chi2min = HUGE(chi2min)
+
+    DO WHILE (iorb_diff < this%sor_norb_prm .AND. itrial < this%sor_ntrial_prm)
+
+       IF (.NOT. equal(this%t_inv_prm,getTime(orb))) THEN
+          CALL propagate(orb, this%t_inv_prm)
+          IF (error) THEN 
+             error = .FALSE.
+             CYCLE ! main loop
+          END IF
+       END IF
+
+       itrial = itrial + 1
+       ! get computed sky positions - spherical coordinates
+       CALL getEphemerides(orb, obsy_ccoords, comp_scoords, partials_arr=partials_arr)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "TRACE BACK (45)", 1)
+          DEALLOCATE(comp_scoords, stat=err)
+          !DEALLOCATE(partial_arr, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(obs_masks, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(obs_coords, stat=err)         
+          DEALLOCATE(comp_coords, stat=err)
+          RETURN
+       END IF
+
+       ! delta1, RA1, Dec1, ddelta12, RA2, Dec2 of the proposed orbit
+       state(1:3) = getPosition(comp_scoords(obs_pair(1)))
+       pos = getPosition(comp_scoords(obs_pair(2)))
+       state(5:6) = pos(2:3)
+       state(4) = pos(1) - state(1)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "TRACE BACK (50)", 1)
+          DEALLOCATE(obs_masks, stat=err)
+          RETURN
+       END IF
+
+       comp_coords = 0.0_bp
+       DO i=1,nobs
+          CALL rotateToEquatorial(comp_scoords(i))
+          comp_coords(i,:) = getCoordinates(comp_scoords(i))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (55)", 1)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(obs_masks, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(comp_coords, stat=err)
+             RETURN
+          END IF
+          CALL NULLIFY(comp_scoords(i))
+       END DO
+       DEALLOCATE(comp_scoords)
+
+       ! calculate residuals
+       residuals(1:nobs,1:6) = obs_coords(1:nobs,1:6) - &
+            comp_coords(1:nobs,1:6)        
+       residuals(1:nobs,2) = residuals(1:nobs,2) * &
+            COS(obs_coords(1:nobs,3))
+       DO i=1,nobs
+          IF (ABS(residuals(i,2)) > pi) THEN
+             obs_coord = obs_coords(i,2)
+             IF (obs_coord < comp_coords(i,2)) THEN
+                obs_coord = obs_coord + two_pi
+             ELSE
+                comp_coords(i,2) = comp_coords(i,2) + two_pi
+             END IF
+             residuals(i,2) = (obs_coord - &
+                  comp_coords(i,2)) * COS(obs_coords(i,3))
+          END IF
+       END DO
+
+       ! Determinant of Jacobian between topocentric
+       ! coordinates (inverse problem coordinates)
+       ! and orbital parameters required for output
+       ! ("Topocentric Wrt Cartesian/Keplerian"):
+       jacobian_matrix(1:3,:) = partials_arr(1:3,:,obs_pair(1)) / &
+            cosdec0(obs_pair(1))
+       jacobian_matrix(4:6,:) = partials_arr(1:3,:,obs_pair(2)) / &
+            cosdec0(obs_pair(2))
+       jac_sph_inv = ABS(determinant(jacobian_matrix, errstr))
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "Unsuccessful computation of determinant of orbital element " // &
+               "jacobian matrix: " // TRIM(errstr), 1)
+          CALL matrix_print(jacobian_matrix, stderr, errstr)
+          errstr = ""
+          CYCLE ! main loop
+       END IF
+       DEALLOCATE(partials_arr)
+
+       ! Calculate pdf value of the new proposed orbit orbit
+       chi2 = getChi2(this, orb)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / MCMCRanging", &
+               "TRACE BACK (60)", 1)
+          DEALLOCATE(obs_masks, stat=err)
+          RETURN
+       END IF
+
+       pdf = EXP(-0.5_bp * (chi2 - REAL(ndof)))
+       avalue = EXP(-0.5_bp*(chi2-chi2_))*jac_sph_inv_/jac_sph_inv
+       IF (pdf > 0.0_bp) THEN
+          ! Decision making accept or reeject depending on pdf
+          IF (avalue >= 1.0_bp) THEN
+             !          IF (avalue > 1.0_bp) THEN
+             CALL  NULLIFY(this%orb_ml_cmp)
+             this%orb_ml_cmp = copy(orb)
+             iorb_diff = iorb_diff + 1
+             iorb = iorb + 1
+             this%rchi2_arr_cmp(iorb) = chi2 - ndof
+             this%pdf_arr_cmp(iorb) = pdf
+             this%res_arr_cmp(iorb,1:nobs,1:6) = residuals(1:nobs,1:6)
+             this%orb_arr_cmp(iorb) = copy(orb)
+             state_ = state
+             pdf_ = pdf
+             jac_sph_inv_ = jac_sph_inv
+             IF (chi2min > chi2) THEN
+                chi2min = chi2
+             END IF
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,*) "Orbit accepted. pdf higher:", pdf, "", iorb, itrial 
+             END IF
+          ELSE
+             CALL randomNumber(ran)
+             IF (ran < avalue) THEN
+                iorb_diff = iorb_diff + 1
+                iorb = iorb + 1
+                this%rchi2_arr_cmp(iorb) = chi2 - ndof
+                this%pdf_arr_cmp(iorb) = pdf
+                this%res_arr_cmp(iorb,1:nobs,1:6) = residuals(1:nobs,1:6)
+                this%orb_arr_cmp(iorb) = copy(orb)
+                state_ = state
+                pdf_ = pdf
+                jac_sph_inv_ = jac_sph_inv
+                IF (chi2min > chi2) THEN
+                   chi2min = chi2
+                END IF
+                IF (info_verb >= 3) THEN
+                   WRITE(stdout,*)"Orbit accepted. pdf random: ", pdf, iorb, itrial
+                END IF
+             ELSE
+                !this%wei_cmp(iorb) = this%wei_cmp(iorb) + 1
+             END IF
+          END IF
+       END IF
+
+       ! Update nr of orbits in stochastic orbit
+       this%sor_norb_cmp = iorb
+
+       ! Get next state(topocentric distances and sky positions for
+       ! the two observations) around the previous computed state
+       DO
+          CALL randomGaussian(rans)
+          state = state_ + rans * proposal_density
+          ! Check if the distances are smaller than Earth radius
+          IF (state(1) <= planetary_radii(3) .OR. state(1)+state(4) <= planetary_radii(3)) THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,F10.7,A)") &
+                     "Failed (One or both topocentric distances smaller than the Earth radius.)" 
+             END IF
+             itrial = itrial + 1
+             CYCLE ! next-state-generation loop
+          END IF
+
+          ! Create new spherical coordinates with generated states in equatorial frame
+          CALL NULLIFY(obs_scoord1)
+          CALL NULLIFY(obs_scoord2)
+          CALL NEW(obs_scoord1, state(1), state(2), state(3), getTime(obsy_ccoords(obs_pair(1))))
+          CALL NEW(obs_scoord2, state(1)+state(4), state(5), state(6), getTime(obsy_ccoords(obs_pair(2))))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (65)", 1)
+             RETURN
+          END IF
+
+          ! Create new topocentric cartesian coordinates of the observations in equatorial frame
+          CALL NULLIFY(obs_ccoord_topo1)
+          CALL NULLIFY(obs_ccoord_topo2)
+          CALL NEW(obs_ccoord_topo1, obs_scoord1) 
+          CALL NEW(obs_ccoord_topo2, obs_scoord2) 
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (70)", 1)
+             RETURN
+          END IF
+
+          ! Rotate to ecliptic
+          CALL rotateToEcliptic(obs_ccoord_topo1)
+          CALL rotateToEcliptic(obs_ccoord_topo2)
+          CALL rotateToEcliptic(obsy_ccoords(obs_pair(1)))
+          CALL rotateToEcliptic(obsy_ccoords(obs_pair(2)))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (75)", 1)
+             RETURN
+          END IF
+
+          ! Cartesian heliocentric coordinates
+          CALL NULLIFY(obs_ccoord_helio1)
+          CALL NULLIFY(obs_ccoord_helio2)
+          obs_ccoord_helio1 = copy(obsy_ccoords(obs_pair(1)) + obs_ccoord_topo1)
+          obs_ccoord_helio2 = copy(obsy_ccoords(obs_pair(2)) + obs_ccoord_topo2)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (80)", 1)
+             RETURN
+          END IF
+
+          CALL estimateLightTime(obs_ccoord_helio1, state(1))! changed from 3 and 6
+          CALL estimateLightTime(obs_ccoord_helio2, state(1)+state(4))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (85)", 1)
+             RETURN
+          END IF
+
+          ! Find orbit candidate at the epoch of the first observation by
+          ! using the chosen method to solve the 2-point boundary value
+          ! problem:
+          CALL NULLIFY(orb)
+          CALL NEW(orb, obs_ccoord_helio1, obs_ccoord_helio2, &
+               this%sor_2point_method_prm, this%apriori_a_max_prm)
+          IF (error) THEN 
+             CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                  "TRACE BACK (86)", 1)
+             error = .FALSE.
+             itrial = itrial + 1
+             CYCLE ! next-state-generation loop
+          END IF
+
+          ! checking if the epochs are the same
+          IF (.NOT. equal(this%t_inv_prm,getTime(orb))) THEN
+             CALL propagate(orb, this%t_inv_prm)
+             IF (error) THEN 
+                CALL errorMessage("StochasticOrbit / MCMCRanging", &
+                     "TRACE BACK (90)", 1)
+                error = .FALSE.
+                itrial = itrial + 1
+                CYCLE ! next-state-generation loop
+             END IF
+          END IF
+          CALL toCartesian(orb, "ecliptic")
+          elements = getElements(orb, "cartesian", "ecliptic")
+          IF (.NOT. boundOrbit(orb, this%apriori_a_max_prm, elements(1))) THEN
+             ! Make sure the semimajor axis is within the boundary values.
+             ! Lower bound:
+             IF (elements(1) < planetary_radii(11)) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F13.7,A)") &
+                        "Failed (semimajor axis too small: ", elements(1), " AU)"
+                END IF
+                itrial = itrial + 1
+                CYCLE ! next-state-generation loop
+             END IF
+             ! Upper bound:
+             IF (elements(1) > this%apriori_a_max_prm) THEN
+                IF (info_verb >= 5) THEN
+                   WRITE(stdout,"(2X,A,F10.7,A)") &
+                        "Failed (semimajor axis too large: ", elements(1), " AU)"
+                END IF
+                itrial = itrial + 1
+                CYCLE ! next-state-generation loop
+             END IF
+          END IF
+          ! Exit if this point has been reached
+          EXIT
+       END DO
+
+    END DO
+
+    this%sor_norb_cmp = iorb
+    this%sor_ntrial_cmp = itrial
+
+    CALL propagate(this%orb_arr_cmp, this%t_inv_prm)
+    i = MAXLOC(this%pdf_arr_cmp,dim=1)
+    this%orb_ml_cmp       = copy(this%orb_arr_cmp(i))
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,*) "element type cov", this%cov_type_prm, getElementType(this%orb_ml_cmp)
+       WRITE(*,*) "END OF THE SECOND STEP"
+       WRITE(*,*) "Final number of orbits: ", iorb
+       WRITE(*,*) "Final number of trials: ", itrial
+       WRITE(*,*) "Acceptance rate: ", REAL(iorb)/REAL(itrial)
+       WRITE(*,*) "chi2 min: ", chi2min
+    END IF
+
+    DEALLOCATE(obs_masks, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Could not deallocate memory (20).", 1)
+       RETURN
+    END IF
+    DO i=1,nobs
+       CALL NULLIFY(obs_scoords(i))
+    END DO
+    DEALLOCATE(obs_scoords, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / MCMCRanging", &
+            "Could not deallocate memory (25).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE MCMCRanging
+
+
+
+
+
+  SUBROUTINE observationSampling(this, orb_arr)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+    TYPE (Orbit), DIMENSION(:), INTENT(in) :: orb_arr    
+
+    TYPE (StochasticOrbit) :: storb
+    TYPE (Observations) :: obss
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: scoord_arr
+    TYPE (Time) :: t
+    TYPE (Orbit), DIMENSION(:), ALLOCATABLE :: orb_arr_init
+    TYPE (Orbit), DIMENSION(7) :: orb_arr_tmp
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=DYN_MODEL_LEN) :: dyn_model, dyn_model_
+    CHARACTER(len=INTEGRATOR_LEN) :: orb_integrator
+    CHARACTER(len=32) :: str
+    REAL(bp), DIMENSION(:,:,:), POINTER :: cov_mat_obs, center_and_absbound_arr
+    REAL(bp), DIMENSION(:,:), POINTER :: orb_additional_perturbers, stddev_arr
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: mean_arr, coordinates_arr
+    REAL(bp), DIMENSION(6) :: elements, elements_, coordinates, coordinates_
+    REAL(bp) :: sigma_multiplier_rms, orb_integration_step, a_r, &
+         pdv, chi2, dchi2, rchi2, ran, pdv_previous
+    INTEGER :: i, j, k, err, nobs, info_verb_, iorb, ipreli
+    LOGICAL :: first, accept
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "MCMC OBSERVATION SAMPLING"
+       WRITE(stdout,"(1X)")
+       WRITE(stdout,"(2X,A)") "Parameters:"
+       WRITE(stdout,"(2X,A,1X,L1)") "outlier_rejection_prm", this%outlier_rejection_prm
+       WRITE(stdout,"(2X,A,1X,F10.5)") "accept_multiplier_prm", this%accept_multiplier_prm
+       WRITE(stdout,"(2X,A,1X,L1)") "generat_gaussian_deviates_prm", this%generat_gaussian_deviates_prm
+       WRITE(stdout,"(2X,A,1X,I0)") "os_sampling_type_prm", this%os_sampling_type_prm
+       WRITE(stdout,"(2X,A,1X,A)") "dyn_model_prm", TRIM(this%dyn_model_prm)
+       WRITE(stdout,"(2X,A,1X,A)") "element_type_prm", TRIM(this%element_type_prm)
+       WRITE(stdout,"(2X,A,1X,I0)") "os_norb_prm", this%os_norb_prm
+       WRITE(stdout,"(2X,A,1X,I0)") "os_ntrial_prm", this%os_ntrial_prm
+    END IF
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / observationSampling", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(orb_arr(1))) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / observationSampling", &
+            "Preliminary orbit (#1) has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%outlier_rejection_prm) THEN
+       IF (this%outlier_multiplier_prm < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / observationSampling", &
+               "Outlier criterion has not been defined.", 1)
+          RETURN
+       END IF
+    END IF
+    sigma_multiplier_rms = this%accept_multiplier_prm
+
+    IF (.NOT.ASSOCIATED(this%obs_masks_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / observationSampling", &
+            "Observation mask is missing.", 1)
+       RETURN
+    END IF
+
+    ! Observational information
+    nobs = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    IF (this%generat_gaussian_deviates_prm) THEN
+       cov_mat_obs => getCovarianceMatrices(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (10)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(mean_arr(nobs,6))
+       mean_arr = 0.0_bp
+    ELSE
+       stddev_arr => getStandardDeviations(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (15)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(center_and_absbound_arr(nobs,6,2))
+       center_and_absbound_arr = 0.0_bp
+       DO i=1,nobs
+          DO j=2,3
+             center_and_absbound_arr(i,j,2) = this%generat_multiplier_prm * stddev_arr(i,j)
+          END DO
+       END DO
+       DEALLOCATE(stddev_arr)
+    END IF
+    IF (info_verb >= 3 .OR. this%os_sampling_type_prm == 2) THEN
+       scoord_arr => getObservationSCoords(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (20)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(coordinates_arr(nobs,6))
+       DO i=1,nobs
+          coordinates_arr(i,:) = getCoordinates(scoord_arr(i))
+          CALL NULLIFY(scoord_arr(i))
+       END DO
+       DEALLOCATE(scoord_arr)
+    END IF
+
+    ! Orbital information
+    ! Inversion epoch is equal to epoch of first preliminary orbit:
+    t = getTime(orb_arr(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+    CALL getParameters(orb_arr(1), dyn_model=dyn_model)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "TRACE BACK (30)", 1)
+       RETURN
+    END IF
+    IF (dyn_model /= this%dyn_model_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "Inconsistent propagation schemes: " // &
+            "orb=" // TRIM(dyn_model) // " and storb=" // &
+            TRIM(this%dyn_model_prm) // ".", 1)
+       RETURN
+    END IF
+    dyn_model_ = dyn_model
+    ! Initialize elements:
+    frame = getFrame(orb_arr(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "TRACE BACK (35)", 1)
+       RETURN
+    END IF
+    element_type = this%element_type_prm
+    CALL locase(element_type, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / observationSampling", &
+            "The element type string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    ALLOCATE(orb_arr_init(MAX(7,SIZE(orb_arr))))
+    IF (SIZE(orb_arr) >= 7) THEN
+       DO i=1,SIZE(orb_arr)
+          orb_arr_init(i) = copy(orb_arr(i))
+       END DO
+    ELSE
+       elements = getElements(orb_arr(1), element_type, frame=frame)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (45)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          RETURN
+       END IF
+       orb_arr_init(1) = copy(orb_arr(1))
+       DO i=1,6
+          elements_ = elements
+          elements_(i) = 1.01_bp*elements_(i)
+          CALL NEW(orb_arr_init(i+1), elements_, element_type, frame, t)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "observationSampling", &
+                  "TRACE BACK (50)", 1)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             RETURN
+          END IF
+       END DO
+       DO i=1,7
+          CALL setParameters(orb_arr_init(i), &
+               dyn_model=this%dyn_model_prm, &
+               perturbers=this%perturbers_prm, &
+               integration_step=this%integration_step_prm, &
+               integrator=this%integrator_prm)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "observationSampling", &
+                  "TRACE BACK (55)", 1)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             DEALLOCATE(center_and_absbound_arr, stat=err)
+             RETURN
+          END IF
+       END DO
+    END IF
+    DO i=1,SIZE(orb_arr_init)
+       SELECT CASE (TRIM(element_type))
+       CASE ("cartesian")
+          CALL toCartesian(orb_arr_init(i), frame=frame)
+       CASE ("keplerian")
+          CALL toKeplerian(orb_arr_init(i))
+       CASE default
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / observationSampling", &
+               "Can not use elements of type: " // TRIM(element_type), 1)
+          RETURN
+       END SELECT
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (40)", 1)
+          RETURN
+       END IF
+    END DO
+
+    first = .TRUE.
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp)
+    END IF
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp)
+    END IF
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp)
+    END IF
+    IF (ASSOCIATED(this%repetition_arr_cmp)) THEN
+       DEALLOCATE(this%repetition_arr_cmp)
+    END IF
+    ALLOCATE(this%orb_arr_cmp(this%os_norb_prm), &
+         this%rchi2_arr_cmp(this%os_norb_prm), &
+         this%pdf_arr_cmp(this%os_norb_prm), &
+         this%repetition_arr_cmp(this%os_norb_prm))
+    this%repetition_arr_cmp = 0
+    iorb = 0
+    pdv_previous = 1
+    DO i=0,this%os_ntrial_prm
+
+       ! Delete working copies
+       CALL NULLIFY(storb)
+       DO j=1,7
+          CALL NULLIFY(orb_arr_tmp(j))
+       END DO
+
+       ! Make working copy of the original observations and
+       ! configuration for orbit inversion:
+       storb = copy(this)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (65)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(center_and_absbound_arr, stat=err)
+          RETURN
+       END IF
+
+       IF (.NOT.first) THEN
+          ! Add noise to original observations:
+          IF (this%generat_gaussian_deviates_prm) THEN
+             CALL addMultinormalDeviates(storb%obss, mean_arr, this%generat_multiplier_prm**2 * cov_mat_obs)
+          ELSE
+             CALL addUniformDeviates(storb%obss, center_and_absbound_arr)
+          END IF
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "observationSampling", &
+                  "TRACE BACK (70)", 1)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             DEALLOCATE(center_and_absbound_arr, stat=err)
+             RETURN
+          END IF
+       END IF
+
+       ! Make a working copy of the set of initial orbits
+       IF (ipreli+7 > SIZE(orb_arr_init)) THEN
+          ipreli = 0
+       END IF
+       DO j=1,7
+          orb_arr_tmp(j) = copy(orb_arr_init(ipreli+j))
+       END DO
+       ipreli = ipreli + 7
+
+       ! Run simplex on the set of modified observations
+       info_verb_ = info_verb
+       info_verb = info_verb - 1
+       CALL simplexOrbits(storb, orb_arr_tmp)
+       info_verb = info_verb_
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (75)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(center_and_absbound_arr, stat=err)
+          RETURN
+       END IF
+
+       ! Compute chi2 on between the best-fitting simplex orbit and
+       ! the original observations
+       chi2 = getChi2(this, storb%orb_ml_cmp)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "observationSampling", &
+               "TRACE BACK (80)", 1)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(center_and_absbound_arr, stat=err)
+          RETURN
+       END IF
+
+       ! Compute the "reduced" chi2 by subtracting the number of
+       ! measured angles (or number of measured coordinates in
+       ! general)
+       rchi2 = chi2 - COUNT(this%obs_masks_prm)
+
+       ! Compute probability density value
+       pdv = EXP(-0.5_bp*rchi2)
+
+       ! If this is the first trial then the observations were the
+       ! nominal ones and the computations were done only to set up
+       ! the variables used in the MCMC comparison
+       IF (first) THEN
+          pdv_previous = pdv
+          this%chi2_min_prm = chi2
+          first = .FALSE.
+          CYCLE
+       END IF
+
+       IF (this%mh_acceptance_prm) THEN
+
+          ! Compute the pdv ratio between the previous accepted orbit
+          ! and the current trial orbit and use the MCMC MH criterion
+          ! to decide whether the trial orbit should be accepted or
+          ! rejected
+          a_r = pdv/MAX(TINY(a_r),pdv_previous)
+          CALL randomNumber(ran)
+          accept = .FALSE.
+          IF (ran < a_r) THEN
+             accept = .TRUE.
+          END IF
+
+       ELSE IF (this%dchi2_rejection_prm) THEN
+
+          ! Compute dchi2 between the best fit orbit and the current
+          ! trial orbit, and use that and the maximum allowed dchi2 to
+          ! decide whether the trial orbit should be accepted or rejected
+          dchi2 = chi2 - this%chi2_min_prm
+          accept = .FALSE.
+          IF (dchi2 < this%dchi2_prm) THEN
+             accept = .TRUE.
+          END IF
+
+       ELSE
+
+          accept = .TRUE.
+
+       END IF
+
+       ! Write cometary elements and other information for each trial
+       ! orbit (incl whether it was rejected or accepted)
+       IF (info_verb >= 2) THEN
+          elements = getElements(storb%orb_ml_cmp, "cometary")
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "observationSampling", &
+                  "TRACE BACK (85)", 1)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             RETURN
+          END IF
+          elements(3:5) = elements(3:5)/rad_deg
+          IF (accept) THEN
+             WRITE(stdout,"(A,1X,10(F15.8,1X),A,1X,I0)") "COMETARY", elements, pdv, chi2, a_r, ran, "ACCEPTED", iorb + 1
+          ELSE
+             WRITE(stdout,"(A,1X,10(F15.8,1X),A,1X,I0)") "COMETARY", elements, pdv, chi2, a_r, ran, "REJECTED", i - iorb
+          END IF
+       END IF
+
+       ! Write offset (from original measurement) for each angle and,
+       ! if using "dependence" sampling and trial orbit is accepted,
+       ! update the offsets from the original position
+       IF (info_verb >= 3 .OR. (accept .AND. this%os_sampling_type_prm == 2)) THEN
+          scoord_arr => getObservationSCoords(storb%obss)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "observationSampling", &
+                  "TRACE BACK (90)", 1)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             DEALLOCATE(center_and_absbound_arr, stat=err)
+             RETURN
+          END IF
+          DO j=1,nobs
+             coordinates = getCoordinates(scoord_arr(j))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / " // &
+                     "observationSampling", &
+                     "TRACE BACK (95)", 1)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                RETURN
+             END IF
+             IF (accept .AND. this%os_sampling_type_prm == 2) THEN ! "dependence" sampling
+                IF (this%generat_gaussian_deviates_prm) THEN
+                   mean_arr(j,:) = coordinates - coordinates_arr(j,:)
+                ELSE
+                   center_and_absbound_arr(j,:,1) = coordinates - coordinates_arr(j,:)
+                END IF
+             END IF
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(A,I0,2(1X,F10.5))") "NOISE IN ARCSEC FOR RA,DEC PAIR #", &
+                     j, (coordinates(2:3)-coordinates_arr(j,2:3))/rad_asec
+             END IF
+             CALL NULLIFY(scoord_arr(j))
+          END DO
+          DEALLOCATE(scoord_arr)
+       END IF
+
+       ! Update the solution if the trial orbit is accepted
+       IF (accept) THEN
+          iorb = iorb + 1
+          this%orb_arr_cmp(iorb) = copy(storb%orb_ml_cmp)
+          this%rchi2_arr_cmp(iorb) = rchi2
+          this%pdf_arr_cmp(iorb) = pdv
+          pdv_previous = pdv
+       END IF
+       IF (iorb /= 0) THEN
+          this%repetition_arr_cmp(iorb) = this%repetition_arr_cmp(iorb) + 1
+       END IF
+
+       ! Exit the loop when enough sample orbits have been found
+       IF (iorb == this%os_norb_prm) THEN
+          EXIT
+       END IF
+
+    END DO
+
+    this%orb_arr_cmp => reallocate(this%orb_arr_cmp, iorb)
+    this%rchi2_arr_cmp => reallocate(this%rchi2_arr_cmp, iorb)
+    this%pdf_arr_cmp => reallocate(this%pdf_arr_cmp, iorb)
+    this%repetition_arr_cmp => reallocate(this%repetition_arr_cmp, iorb)
+
+    DO i=1,7
+       CALL NULLIFY(orb_arr_tmp(i))
+       CALL NULLIFY(orb_arr_init(i))
+    END DO
+    DEALLOCATE(orb_arr_init, stat=err)
+    DEALLOCATE(mean_arr, stat=err)
+    DEALLOCATE(cov_mat_obs, stat=err)
+    DEALLOCATE(center_and_absbound_arr, stat=err)
+    CALL NULLIFY(storb)
+
+  END SUBROUTINE observationSampling
+
+
+
+
+
+  SUBROUTINE autoVolumeOfVariation(this, preliminary_orbit)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Orbit), INTENT(in)              :: preliminary_orbit
+    TYPE (Orbit) :: orb
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type
+    CHARACTER(len=64) :: frmt = "(2X,A,1X,6(F7.3,1X))"
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE:: element_arr, histo
+    REAL(bp), DIMENSION(:), ALLOCATABLE::  elem_data
+    REAL(bp), DIMENSION(6,2) :: scaling_cmp
+    REAL(bp), DIMENSION(6) :: elements_1, elements_2
+    REAL(bp) :: dchi2, ddchi2, xmin, xmax, mean1, stdev1, &
+         tmp, mean2, stdev2
+    INTEGER, DIMENSION(2) :: scaling
+    INTEGER :: i, j, k, l, err, iiter, indx, norb, norb_final, &
+         ntrial_final, imap_zero, nmax, nbin, &
+         ibin_zero, imap, max_indx, nmap, scalar
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask1, mask2, mask3
+    LOGICAL, DIMENSION(6,2) :: scaling_ready
+
+    ! For automated volumeOfVariation:
+    ! I) Iterate to find the unbiased interval(s) of variation for the mapping parameter(s)
+    !    (iterate scaling parameter for all parameters?)
+    !    1) Check for unpopulated mapping bins, increase mapping interval (in practise, psc1)
+    !       if necessary and repeat, at maximum niter_max (=5?) times
+    !    2) Use a smaller number of sample orbits (i.e., 500) in the iteration of
+    !       the mapping interval?
+    ! II) Iterate the maximum point of the rigorous p.d.f. until convergence
+    !     (as in Ranging: d(dchi2)=abs(2.e0_bp*log(pdf_ml_final/pdf_ml)) < 2.0)
+    !     Note: should inform the user if the global ls-solution does not correspond
+    !           to the maximum point!
+
+    iiter = -1
+
+    orb = copy(preliminary_orbit)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+
+    norb_final = this%vov_norb_prm
+    ntrial_final = this%vov_ntrial_prm
+    CALL setParameters(this, &
+         vov_norb=this%vov_norb_iter_prm, &
+         vov_ntrial=this%vov_ntrial_iter_prm)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+
+    ! Find mapping element:
+    DO i=1,6
+       IF (this%vov_mapping_mask_prm(i)) THEN
+          indx = i
+          EXIT
+       END IF
+    END DO
+    ! Initialize scaling factors:
+    scaling_cmp = this%vov_scaling_prm
+
+    ddchi2 = HUGE(ddchi2)
+    scaling_ready = .FALSE.
+    DO
+
+       iiter = iiter + 1
+       this%vov_niter_cmp = iiter
+
+       IF ((ALL(scaling_ready) .AND. &
+            norb >= this%vov_norb_iter_prm .AND. & 
+            ddchi2 < 2.0_bp) .OR. iiter == this%vov_niter_prm) THEN
+          CALL setParameters(this, &
+               vov_norb=norb_final, &
+               vov_ntrial=ntrial_final)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+                  "TRACE BACK (15)", 1)
+             RETURN
+          END IF
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X)")
+             WRITE(stdout,"(2X,A)")       "===================="
+             WRITE(stdout,"(2X,A,1X,I0)") "STARTING FINAL ROUND"
+             WRITE(stdout,"(2X,A)")       "===================="
+             WRITE(stdout,"(2X)")
+          END IF
+       ELSE
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X)")
+             WRITE(stdout,"(2X,A)")       "===================="
+             WRITE(stdout,"(2X,A,1X,I0)") "STARTING ITERATION",iiter
+             WRITE(stdout,"(2X,A)")       "===================="
+             WRITE(stdout,"(2X)")
+          END IF
+       END IF
+
+       ! Starting from the 2nd iteration:
+       IF (iiter > 0) THEN
+          ! Use iterated scaling parameters
+          this%vov_scaling_prm = scaling_cmp
+          CALL NULLIFY(orb)
+          ! Use existing ml orbit as preliminary orbit
+          max_indx = MINLOC(this%rchi2_arr_cmp,dim=1)
+          this%chi2_min_prm = MIN(this%chi2_min_prm,this%chi2_min_cmp)
+          orb = copy(this%orb_arr_cmp(max_indx))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+          ! Remove nominal orbit
+          CALL NULLIFY(this%orb_ml_cmp)
+          IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+             DEALLOCATE(this%cov_ml_cmp, stat=err)
+             IF (err /= 0) THEN
+                CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+                     "Could not deallocate memory ()", 1)
+                RETURN
+             END IF
+          END IF
+       END IF
+
+       CALL volumeOfVariation(this, orb)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "TRACE BACK (25)", 1)
+          RETURN       
+       END IF
+       norb = SIZE(this%orb_arr_cmp,dim=1)
+       IF ((ALL(scaling_ready) .AND. norb >= norb_final) &
+            .OR. iiter == this%vov_niter_prm) THEN
+          CALL NULLIFY(orb)
+          EXIT
+       END IF
+       dchi2 = MAXVAL(this%rchi2_arr_cmp) - MINVAL(this%rchi2_arr_cmp)
+       ddchi2 = ABS(dchi2 - this%dchi2_prm)
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,F10.4)") "Delta dchi2: ", ddchi2
+       END IF
+       ALLOCATE(element_arr(norb,6), elem_data(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Could not allocate memory (5).", 1)
+          RETURN       
+       END IF
+
+       DO i=1,norb
+          element_arr(i,1:6) = getElements(this%orb_arr_cmp(i), this%element_type_prm)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+                  "TRACE BACK (30)", 1)
+             RETURN       
+          END IF
+       END DO
+
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A)") "------------"
+          WRITE(stdout,"(2X,A)") "UPDATING ..."
+          WRITE(stdout,"(2X,A)") "------------"       
+       END IF
+
+       scaling_cmp = this%vov_scaling_cmp
+       imap_zero = NINT(this%vov_nmap_prm*this%vov_scaling_cmp(indx,1) / &
+            SUM(this%vov_scaling_cmp(indx,:)))
+
+       ! Histogram for mapping parameter
+       xmin = MINVAL(this%vov_map_cmp(:,indx))
+       xmax = MAXVAL(this%vov_map_cmp(:,indx))
+       nmax = norb
+       nbin = this%vov_nmap_prm
+       ibin_zero = imap_zero
+       IF (nbin > 1000) THEN
+          nbin = 101
+          ! Not true if unsymmetric scaling parameters
+          ibin_zero = 51
+       END IF
+       ALLOCATE(histo(nbin,2), mask1(nbin), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Could not allocate memory (10).", 1)
+          RETURN       
+       END IF
+       histo = 0.0_bp
+       elem_data = element_arr(:,indx)
+       CALL histogram(elem_data(1:nmax), histo, xmin_in=xmin, xmax_in=xmax)
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,I0,A)") "Mapping element (", indx, "):"
+          WRITE(stdout,"(2X,A,2(F15.7,1X))") "Histo min/max:", xmin, xmax
+          WRITE(stdout,"(2X,A,2(F15.7,1X))") "Data min/max: ", &
+               MINVAL(elem_data(1:nmax)), &
+               MAXVAL(elem_data(1:nmax))
+       END IF
+
+       ! Assume Gaussian statistics and adjust the scaling parameter to 
+       ! cover the 3-sigma range: 
+       CALL moments(elem_data(1:nmax), mean=mean1, std_dev=stdev1, &
+            errstr=errstr)
+       IF (LEN_TRIM(errstr) > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Computation of moments failed: " // TRIM(errstr), 1)
+          RETURN
+       END IF
+       tmp = 3.0_bp*stdev1/(this%vov_scaling_cmp(indx,1)*this%vov_map_cmp(1,6+indx))
+       scaling_cmp(indx,1:2) = REAL(CEILING(tmp*this%vov_scaling_cmp(indx,1:2)),bp)
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,2(1X,F15.7))") "3-sigma_pdf vs. n-sigma_ls:", &
+               3.0_bp*stdev1, &
+               (this%vov_scaling_cmp(indx,1)*this%vov_map_cmp(1,6+indx))
+       END IF
+
+       ! Assume that scaling is ok, and check 
+       ! whether this assumption holds:
+       scaling_ready = .TRUE.
+       ! Empty bins in the mapping parameter direction:
+       mask1 = .FALSE.
+       WHERE (histo(:,2) < 1.0_bp)
+          mask1 = .TRUE.
+       END WHERE
+       IF (ANY(.NOT.mask1(1:CEILING(0.05_bp*nbin)))) THEN
+          scaling_ready(indx,1:2) = .FALSE.
+       ELSE IF (ANY(.NOT.mask1(nbin+1-CEILING(0.05_bp*nbin):nbin))) THEN
+          scaling_ready(indx,1:2) = .FALSE.
+       END IF
+       DEALLOCATE(histo, mask1, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Could not deallocate memory (5).", 1)
+          RETURN       
+       END IF
+
+       nbin = 20
+       nmap = SIZE(this%vov_map_cmp, dim=1)
+       ALLOCATE(histo(nbin,2), mask1(norb), mask2(nbin), mask3(nbin), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Could not allocate memory (15).", 1)
+          RETURN       
+       END IF
+       DO i=1,6
+          IF (i == indx) THEN
+             CYCLE
+          END IF
+          scaling = 0.0_bp
+          mask3 = .FALSE.
+          DO j=1,nmap
+             ! Select all points around a specific
+             ! mapping point:
+             mask1 = .FALSE.
+             IF (j == 1) THEN
+                xmin = this%vov_map_cmp(j,indx)
+             ELSE
+                xmin = 0.5_bp * (this%vov_map_cmp(j,indx) + &
+                     this%vov_map_cmp(j-1,indx))
+             END IF
+             IF (j == nmap) THEN
+                xmax = this%vov_map_cmp(j,indx)
+             ELSE
+                xmax = 0.5_bp * (this%vov_map_cmp(j,indx) + &
+                     this%vov_map_cmp(j+1,indx))
+             END IF
+             WHERE(element_arr(:,indx) < xmax .AND. element_arr(:,indx) >= xmin)
+                mask1 = .TRUE.
+             END WHERE
+             elem_data(1:COUNT(mask1)) = PACK(element_arr(:,i), mask1)
+             xmin = this%vov_map_cmp(j,i) - &
+                  this%vov_scaling_cmp(i,1)*this%vov_map_cmp(j,6+i)
+             xmax = this%vov_map_cmp(j,i) + &
+                  this%vov_scaling_cmp(i,2)*this%vov_map_cmp(j,6+i)
+             histo = 0.0_bp
+             CALL histogram(elem_data(1:COUNT(mask1)), histo, &
+                  xmin_in=xmin, xmax_in=xmax)
+             ! Which bins corresponding to this particular mapping
+             ! element value do have solutions?
+             mask2 = .TRUE.
+             WHERE(histo(:,2) < 1.0_bp)
+                mask2 = .FALSE.
+             END WHERE
+             ! Which bins covering the entire mapping space do have
+             ! solutions?
+             WHERE (mask2)
+                mask3 = .TRUE.
+             END WHERE
+             IF (ANY(mask3(1:CEILING(0.1_bp*nbin))) .OR. &
+                  ANY(mask3(nbin+1-CEILING(0.1_bp*nbin):nbin))) THEN
+                ! The current interval needs to be widened
+                EXIT
+             END IF
+             ! Find min and max of the topical orbital element
+             ! around the mapping point (if orbits exist!):
+             IF (COUNT(mask1) /= 0) THEN
+                xmin = MINVAL(element_arr(:,i), mask1)
+                xmax = MAXVAL(element_arr(:,i), mask1)
+                ! Compare with used sampling intervals and find
+                ! the smallest integer scaling factor that accepts all
+                ! sample orbits from the previous round:
+                scalar = CEILING(ABS((xmin - this%vov_map_cmp(j,i))/this%vov_map_cmp(j,6+i)))
+                IF (COUNT(mask1) /= 0 .AND. scalar > scaling(1)) THEN 
+                   scaling(1) = scalar
+                   IF (info_verb >= 3) THEN
+                      WRITE(stdout,"(2X,2(A,1X,I0,1X))") &
+                           "Lower scaling factor for element", i, &
+                           "is", scaling(1)
+                   END IF
+                END IF
+                scalar = CEILING(ABS((xmax - this%vov_map_cmp(j,i))/this%vov_map_cmp(j,6+i)))
+                IF (COUNT(mask1) /= 0 .AND. scalar > scaling(2)) THEN 
+                   scaling(2) = scalar
+                   IF (info_verb >= 3) THEN
+                      WRITE(stdout,"(2X,2(A,1X,I0,1X))") &
+                           "Upper scaling factor for element", i, &
+                           "is", scaling(2)
+                   END IF
+                END IF
+             END IF
+          END DO
+          IF (info_verb >= 2) THEN
+             !WRITE(stdout,"(2X,A,1X,I0)")    "Nr of empty bins      =", &
+             !     COUNT(mask1)
+             WRITE(stdout,*) " Are first n bins empty for element ", i, &
+                  "? ", .NOT.mask3(1:CEILING(0.1_bp*nbin))
+             WRITE(stdout,*) " Are last n bins empty for element  ", i, &
+                  "? ", .NOT.mask3(nbin+1-CEILING(0.1_bp*nbin):nbin)
+          END IF
+          IF (ANY(mask3(1:CEILING(0.1_bp*nbin))) .OR. &
+               ANY(mask3(nbin+1-CEILING(0.1_bp*nbin):nbin))) THEN
+             ! Lower end of the sampling region is too small -> 
+             ! increase scaling parameter value by at most 50% or
+             ! at least one unit:
+             scaling_cmp(i,1) = scaling_cmp(i,1) + &
+                  MAX(1.0_bp,REAL(FLOOR(0.3_bp*scaling_cmp(i,1)),bp))
+             scaling_ready(i,1) = .FALSE.
+             ! Upper end of the sampling region is too small -> 
+             ! increase scaling parameter value by at most 50% or
+             ! at least one unit:
+             scaling_cmp(i,2) = scaling_cmp(i,2) + &
+                  MAX(1.0_bp,REAL(FLOOR(0.3_bp*scaling_cmp(i,2)),bp))
+             scaling_ready(i,2) = .FALSE.
+          END IF
+          IF (.NOT.ANY(mask3(1:CEILING(0.1_bp*nbin))) .AND. &
+               CEILING(1.2*scaling(1)) < NINT(scaling_cmp(i,1))) THEN
+             ! Sampling region may be unnecessary wide in the lower end -> 
+             ! optimize scaling parameters:
+             scaling_cmp(i,1) = CEILING(1.2*scaling(1))
+          END IF
+          IF (.NOT.ANY(mask3(nbin+1-CEILING(0.1_bp*nbin):nbin)) .AND. &
+               CEILING(1.2*scaling(2)) < NINT(scaling_cmp(i,2))) THEN
+             ! Sampling region may be unnecessary wide in the upper end -> 
+             ! optimize scaling parameters:
+             scaling_cmp(i,2) = CEILING(1.2*scaling(2))
+          END IF
+       END DO
+
+       DEALLOCATE(element_arr, elem_data, mask1, mask2, mask3, &
+            histo, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "Could not deallocate memory (15).", 1)
+          RETURN       
+       END IF
+
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,TRIM(frmt)) "Adjusted scaling parameters (lo):", &
+               scaling_cmp(:,1)
+          WRITE(stdout,TRIM(frmt)) "Adjusted scaling parameters (up):", &
+               scaling_cmp(:,2)
+          WRITE(stdout,"(2X,A,6(1X,L1))") "Scaling ready?", &
+               scaling_ready(:,1)
+          WRITE(stdout,"(2X,A,6(1X,L1))") "Scaling ready?", &
+               scaling_ready(:,2)
+       END IF
+
+    END DO
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "... ITERATIONS READY"       
+       WRITE(stdout,TRIM(frmt)) "Final scaling parameters (lo):", &
+            this%vov_scaling_cmp(:,1)
+       WRITE(stdout,TRIM(frmt)) "Final scaling parameters (up):", &
+            this%vov_scaling_cmp(:,2)
+    END IF
+
+    this%vov_scaling_ready_cmp = scaling_ready
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,6(1X,L1))") "Scaling ready?", scaling_ready(:,1)
+       WRITE(stdout,"(2X,A,6(1X,L1))") "Scaling ready?", scaling_ready(:,2)
+       dchi2 = MAXVAL(this%rchi2_arr_cmp) - MINVAL(this%rchi2_arr_cmp)
+       ddchi2 = ABS(dchi2 - this%dchi2_prm)
+       WRITE(stdout,"(2X,A,F10.4)") "Delta dchi2: ", ddchi2
+       element_type = "keplerian"
+       elements_1 = getElements(this%orb_ml_cmp, element_type)
+       elements_1(3:6) = elements_1(3:6)/rad_deg
+       elements_2 = getElements(this%orb_arr_cmp(indx), element_type)
+       elements_2(3:6) = elements_2(3:6)/rad_deg
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+               "TRACE BACK (50)", 1)
+          error = .FALSE.
+          element_type = "cartesian"
+          elements_1 = getElements(this%orb_ml_cmp, element_type)
+          elements_2 = getElements(this%orb_arr_cmp(indx), element_type)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / autoVolumeOfVariation", &
+                  "TRACE BACK (55)", 1)
+             RETURN
+          END IF
+       END IF
+       WRITE(stdout,"(2X,A)") "Global least-squares solution in " // &
+            TRIM(element_type) // " orbital elements:"
+       WRITE(stdout,"(2X,6(F15.10,1X))") elements_1
+       WRITE(stdout,"(2X,A)") "Maximum likelihood solution in " // &
+            TRIM(element_type) // " orbital elements:"
+       WRITE(stdout,"(2X,6(F15.10,1X))") elements_2
+    END IF
+
+  END SUBROUTINE autoVolumeOfVariation
+
+
+
+
+
+  SUBROUTINE volumeOfVariation(this, preliminary_orbit)
+
+    ! VoV parameters: vov_nmap, vov_norb, vov_ntrial, vov_niter_max
+    !                 vov_scaling_parameters(6), vov_automatic
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Orbit), INTENT(in)              :: preliminary_orbit
+    TYPE (Time) :: &
+         t0, &
+         t
+    TYPE (Orbit), DIMENSION(:), POINTER :: &
+         orb_arr
+    TYPE (Orbit), DIMENSION(this%vov_norb_prm) :: &
+         orb_accepted
+    TYPE (Orbit) :: &
+         orb, &
+         orb_global, &
+         orb_local
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: &
+         comp_scoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: &
+         obs_scoords
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: &
+         obsy_ccoords
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=DYN_MODEL_LEN) :: &
+         storb_dyn_model, &
+         orb_dyn_model
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         storb_integrator, &
+         orb_integrator
+    CHARACTER(len=64) :: &
+         frmt = "(F20.15,1X)", &
+         efrmt = "(E10.4,1X)"
+    CHARACTER(len=64) :: &
+         str
+    REAL(bp), DIMENSION(:,:,:,:), POINTER :: &
+         partials4
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         residuals3, &
+         information_matrix_obs
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         principal_axes
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         residuals2
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+         obs_coords, &
+         jac_arr, &
+         rms_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         debiasing_factor_map, &
+         debiasing_factor_arr, &
+         reg_apriori_arr, &
+         rchi2_arr, &
+         pdf_arr, &
+         cosdec0, &
+                                !chi2_local, &
+         diff
+    REAL(bp), DIMENSION(this%vov_nmap_prm,6) :: &
+         elements_local_arr
+    REAL(bp), DIMENSION(6,6) :: &
+         covariance_global, &
+         partial_covariance_global, &
+         covariance_local, &
+         information_matrix_global, &
+         information_matrix_local, &
+         correlation_matrix, &
+         partial_inverse_stdev_global, &
+         eigenvectors, jacobian_matrix
+    REAL(bp), DIMENSION(6) :: &
+         stdev_global, &
+         partial_stdev_global, &
+         elements_global, &
+         elements_local, &
+         elements, &
+         partial_eigenvalues_global, &
+         eigenvalues, &
+         comp_coord, &
+         storb_finite_diff, &
+         orb_finite_diff, &
+         ran_arr, &
+         upper_limit, &
+         lower_limit, &
+         diff_elem
+    REAL(bp) :: &
+         apriori, &
+         chi2_ml_global_ls, &
+         partial_product_global, &
+         product_local, &
+         mapping_interval, &
+         mapping_point, &
+         chi2, &
+         dchi2, &
+         pdf, &
+         variation, &
+         storb_integration_step, &
+         orb_integration_step,&
+         jac_car_kep, jac_equ_kep, sma, tmp, &
+         obs_, comp_
+    INTEGER, DIMENSION(:), ALLOCATABLE :: &
+         failed_flag, &
+         imap_arr
+    INTEGER, DIMENSION(6) :: &
+         n0, n0_, &
+         ind_arr
+    INTEGER :: &
+         i, &
+         j, &
+         k, &
+         imap, &
+         jmap, &
+         itrial, &
+         iorb, &
+         mmap, &
+         indx, &
+         nrot, &
+         err, &
+         nobs, &
+         nset, &
+         nfailed, &
+         norb, &
+         naccepted, &
+         ielem, &
+         iobs, &
+         imulti, &
+         isigma, &
+         imap_zero, &
+         ires, &
+         ipdf, &
+         info_verb_, &
+         err_verb_
+    LOGICAL, DIMENSION(:,:), POINTER :: &
+         mask_arr2
+    LOGICAL, DIMENSION(6) :: &
+         element_mask
+    LOGICAL :: &
+         parameters_agree, outlier_rejection_
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+    IF (.NOT.exist(preliminary_orbit)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Preliminary orbit has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    IF (nobs < 2) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Less than two observations available.", 1)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%res_accept_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Window for accepted residuals not set.", 1)
+       RETURN
+    END IF
+    IF (this%vov_norb_prm < 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Required number of sample orbits not set.", 1)
+       RETURN
+    END IF
+    CALL comparePropagationParameters(this, preliminary_orbit, &
+         parameters_agree=parameters_agree)
+    IF (error .OR. .NOT.parameters_agree) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (1)", 1)
+       RETURN
+    END IF
+
+    IF (MOD(this%vov_nmap_prm,2) == 0) THEN
+       mmap = this%vov_nmap_prm/2
+       this%vov_nmap_prm = this%vov_nmap_prm + 1
+    ELSE
+       mmap = (this%vov_nmap_prm-1)/2
+    END IF
+    nobs = getNrOfObservations(this%obss)
+    ALLOCATE( &
+         principal_axes(this%vov_nmap_prm,6,6), &
+         debiasing_factor_arr(this%vov_norb_prm), &
+         debiasing_factor_map(this%vov_nmap_prm), &
+         obs_coords(nobs,6), &
+         cosdec0(nobs), &
+         residuals3(this%vov_norb_prm,nobs,6), &
+         mask_arr2(nobs,6), &
+         failed_flag(8), &
+         reg_apriori_arr(this%vov_norb_prm), &
+         pdf_arr(this%vov_norb_prm), &
+         rchi2_arr(this%vov_norb_prm), &
+         jac_arr(this%vov_norb_prm,3), &
+         rms_arr(this%vov_norb_prm,6), &
+                                !chi2_local(this%vov_nmap_prm), &
+         diff(this%vov_nmap_prm), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       RETURN
+    END IF
+
+    ! Set type of mapping elements:
+    IF (LEN_TRIM(this%element_type_prm) == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Element type missing.", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       RETURN
+    ELSE       
+       element_type = this%element_type_prm
+    END IF
+
+    obs_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (45)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       RETURN
+    END IF
+    DO i=1,nobs
+       obs_coords(i,:) = getCoordinates(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (50)",1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          RETURN
+       END IF
+       cosdec0(i) = COS(obs_coords(i,3))
+    END DO
+    obsy_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (55)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       RETURN
+    END IF
+    IF (this%chi2_min_prm < 0.0_bp) THEN
+       !       first = .TRUE.
+       IF (this%chi2_min_init_prm <= 0.0_bp) THEN
+          this%chi2_min_prm = REAL(COUNT(this%obs_masks_prm),bp)
+       ELSE
+          this%chi2_min_prm = this%chi2_min_init_prm
+       END IF
+       !    ELSE
+       !       first = .FALSE.
+    END IF
+
+    orb = copy(preliminary_orbit)
+    frame = getFrame(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (70)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb)
+       RETURN
+    END IF
+    IF (element_type == "keplerian") THEN
+       CALL toKeplerian(orb)
+    ELSE IF (element_type == "cartesian") THEN
+       CALL toCartesian(orb, frame=frame)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Cannot recognize element type: " // TRIM(element_type), 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb)
+       RETURN       
+    END IF
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (60)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb)
+       RETURN
+    END IF
+    ! Epoch is bound to the epoch of the preliminary orbit
+    t0 = getTime(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (65)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+
+    !!
+    !! 1) INTERVAL FOR MAPPING PARAMETER VIA GLOBAL LEAST-SQUARES:
+    !!
+
+    ! Check number of mapping parameters; only one allowed for now!
+    IF (COUNT(this%vov_mapping_mask_prm) /= 1) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Too many or no mapping parameters chosen.", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! Mapping index
+    DO i=1,6
+       IF (this%vov_mapping_mask_prm(i)) THEN
+          indx = i
+          EXIT
+       END IF
+    END DO
+
+    ! Only do least squares if (nominal) ml orbit and covariance matrix 
+    ! do not yet exist
+    IF (.NOT. exist(this%orb_ml_cmp) .AND. .NOT. ASSOCIATED(this%cov_ml_cmp)) THEN
+       info_verb_ = info_verb
+       IF (this%vov_niter_cmp > 0) THEN
+          info_verb = info_verb - 1
+       END IF
+       CALL levenbergMarquardt(this, orb)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Global least-squares solution not found.", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          CALL NULLIFY(orb)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       IF (info_verb == 1 .AND. info_verb_ == 2) THEN
+          t = getTime(this%orb_ml_cmp)
+          str = getCalendarDateString(t, 'TDT')
+          CALL NULLIFY(t)
+          elements = getElements(this%orb_ml_cmp, "keplerian")
+          IF (error) THEN
+             error = .FALSE.
+             elements = getElements(orb, "cartesian", frame="ecliptic")
+             WRITE(stdout,"(2X,A)") "Cartesian ecliptic elements resulting " // &
+                  "from global least squares:"
+             WRITE(stdout,"(2X,6(1X,F20.13),1X,A)") elements, &
+                  TRIM(str)
+          ELSE
+             WRITE(stdout,"(2X,A)") "Keplerian elements resulting " // &
+                  "from global least squares:"
+             WRITE(stdout,"(2X,6(1X,F20.13),1X,A)") elements(1:2), &
+                  elements(3:6)/rad_deg, TRIM(str)
+          END IF
+       END IF
+       info_verb = info_verb_
+    END IF
+    CALL NULLIFY(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (90)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! LS orbit
+    orb_global = getNominalOrbit(this)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (95)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! Orbital elements at the specified epoch:
+    elements_global = getElements(orb_global, element_type)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (100)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! Correlation/Standard deviation matrix:
+    covariance_global = getCovarianceMatrix(this, element_type, frame)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (105)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    DO i=1,6
+       stdev_global(i) = SQRT(covariance_global(i,i))
+    END DO
+    ! Maximum likelihood point
+    information_matrix_global = matinv(covariance_global, errstr, "Cholesky")
+    IF (LEN_TRIM(errstr) > 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Error in matrix inversion: " // TRIM(errstr), 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    IF (this%regularization_prm) THEN
+       ! Jeffrey's apriori
+       apriori = SQRT(ABS(determinant(information_matrix_global, errstr)))
+       IF (LEN_TRIM(errstr) > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Error in computation of determinant: " // TRIM(errstr), 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+    ELSE
+       apriori = 1.0_bp
+    END IF
+    ! Residuals for the global fit:
+    residuals2 => getResiduals(this, orb_global)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (130)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    information_matrix_obs => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (135)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    DO i=1,6
+       n0(i) = COUNT(this%obs_masks_prm(:,i))
+    END DO
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,6(1X,I0))") "Nr of included observations:", n0
+    END IF
+
+    ! Chi2 for the global fit
+    chi2_ml_global_ls = chi_square(residuals2, information_matrix_obs, this%obs_masks_prm, errstr)
+    IF (LEN_TRIM(errstr) > 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Computation of chi2 for the global solution failed: " // TRIM(errstr), 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+
+    ! 
+    ! S :: stdev (diagonal) matrix
+    ! S^(-1) :: inverse stdev (diagonal) matrix
+    ! 5x5 global covariance matrix:
+    information_matrix_global(indx,:) = 0.0_bp
+    information_matrix_global(:,indx) = 0.0_bp
+    information_matrix_global(indx,indx) = 1.0_bp
+    partial_covariance_global = matinv(information_matrix_global, errstr, "Cholesky")
+    IF (LEN_TRIM(errstr) > 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Error in inversion of partial global information matrix: " // TRIM(errstr), 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    partial_stdev_global = 0.0_bp
+    partial_inverse_stdev_global = 0.0_bp
+    DO i=1,6
+       IF (this%vov_mapping_mask_prm(i)) THEN
+          CYCLE
+       ELSE
+          partial_stdev_global(i) = SQRT(partial_covariance_global(i,i))
+          partial_inverse_stdev_global(i,i) = 1.0_bp/partial_stdev_global(i)
+       END IF
+    END DO
+    ! C = S^(-1) Sigma S^(-1)
+    correlation_matrix = MATMUL(MATMUL(partial_inverse_stdev_global, &
+         partial_covariance_global), partial_inverse_stdev_global)
+    ! 
+    CALL eigen_decomposition_jacobi(correlation_matrix, &
+         partial_eigenvalues_global, eigenvectors, nrot, errstr)
+    IF (LEN_TRIM(errstr) > 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Error in eigen decomposition: " // TRIM(errstr), 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    partial_product_global = 1.0_bp
+    DO i=1,6
+       IF (this%vov_mapping_mask_prm(i)) THEN
+          CYCLE
+       END IF
+       IF (partial_eigenvalues_global(i) < 0.0_bp) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Negative global eigenvalue:", 1)
+          IF (err_verb >= 1) THEN
+             WRITE(0,"(E15.7)") partial_eigenvalues_global
+          END IF
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       partial_product_global = partial_product_global*ABS(partial_eigenvalues_global(i))
+    END DO
+
+    ! If initial estimate for chi2 corresponding to maximum likelihood
+    ! solution remains unknown (indicated by a negative value), set it
+    ! equal to the chi2 computed for the global least squares
+    ! solution:
+    IF (this%chi2_min_prm < 0.0_bp) THEN
+       this%chi2_min_prm = chi2_ml_global_ls
+    END IF
+    IF (this%vov_niter_cmp < 1 .AND. info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "Global orbital elements " // &
+            "(element type=" // TRIM(element_type) // &
+            " and frame=" // TRIM(getFrame(orb_global)) // "):"
+       t = getTime(orb_global)
+       str = getCalendarDateString(t,"tdt")
+       IF (element_type == "keplerian") THEN
+          WRITE(stdout,"(2X,6"//TRIM(frmt)//",A,2X,2(A,1X))") &
+               elements_global(1:2), elements_global(3:6)/rad_deg, &
+               TRIM(str), TRIM(element_type), TRIM(getFrame(orb_global))
+       ELSE
+          WRITE(stdout,"(2X,6"//TRIM(frmt)//",A,2X,2(A,1X))") &
+               elements_global, TRIM(str), TRIM(element_type), &
+               TRIM(getFrame(orb_global))
+       END IF
+       CALL NULLIFY(t)
+       WRITE(stdout,"(2X,A)") "Global standard deviations:"
+       WRITE(stdout, "(2X)", advance="no")
+       DO i=1,6
+          IF (element_type == "keplerian" .AND. i>=3) THEN
+             WRITE(stdout, TRIM(frmt),advance="no") &
+                  SQRT(covariance_global(i,i))/rad_deg
+          ELSE
+             WRITE(stdout,TRIM(frmt),advance="no") &
+                  SQRT(covariance_global(i,i))
+          END IF
+       END DO
+       WRITE(stdout,*)
+       WRITE(stdout,"(2X,A)") "Global correlation:"
+       CALL matrix_print(correlation_matrix, stdout, errstr, frmt=frmt)
+       WRITE(stdout,"(2X,A)") "Global 5x5 eigenvalues:"
+       WRITE(stdout,"(2X,6"//TRIM(frmt)//")") partial_eigenvalues_global
+       WRITE(stdout,"(2X,A)") "Global 5x5 eigenvectors:"
+       CALL matrix_print(eigenvectors, stdout, errstr, frmt=frmt)
+       WRITE(stdout,"(2X,A,1X,3(E10.4,1X))") "Global apriori:", apriori
+       WRITE(stdout,"(2X,A,1X,3(E10.4,1X))") "Global chi2:", chi2
+       WRITE(stdout,*)
+    END IF
+
+    ! -----------------------------------
+    ! Precomputed map:
+    ! Map plausible semimajor axis region
+    ! -----------------------------------
+    ! Note: 1) number of mapping points, nmap, used is an input
+    !          parameter (case-dependent)
+    !          (nmap => vov_nmap, typically 101 or 1001)
+    !       2) mapping could be made asymmetric with respect to 
+    !          the global solution, i.e., different psc1 for
+    !          decreasing/increasing loop below
+    !          (psc1 => vov_scaling_parameter(1))
+
+    ! Save initial element mask:
+    element_mask = this%ls_elem_mask_prm
+
+    ! Save initial outlier rejection, do not use it here
+    outlier_rejection_ = this%outlier_rejection_prm
+    CALL setParameters(this, outlier_rejection=.FALSE.)
+
+    ! Adjust scaling parameter for Keplerian elements if needed
+    ! (requirements: a>0 and 0<e<1):
+    IF (element_type == "keplerian") THEN
+       IF (elements_global(1) - &
+            this%vov_scaling_prm(1,1)*stdev_global(1) < &
+            planetary_radii(11)) THEN
+          WRITE(stderr,*) "Problem in semimajor axis interval:",elements_global(1) - &
+               this%vov_scaling_prm(1,1)*stdev_global(1)
+          this%vov_scaling_prm(1,1) = (elements_global(1) - &
+               planetary_radii(11))/stdev_global(1)
+       END IF
+       IF (elements_global(2) - &
+            this%vov_scaling_prm(2,1)*stdev_global(2) <= &
+            0.0_bp) THEN
+          PRINT*,"Problem in eccentricity interval:",elements_global(2) - &
+               this%vov_scaling_prm(2,1)*stdev_global(2)
+          this%vov_scaling_prm(2,1) = (elements_global(2) - &
+               EPSILON(elements_global(2)))/stdev_global(2)
+       END IF
+       IF (elements_global(2) + &
+            this%vov_scaling_prm(2,2)*stdev_global(2) >= &
+            1.0_bp) THEN
+          PRINT*,"Problem in eccentricity interval:",elements_global(2) + &
+               this%vov_scaling_prm(2,2)*stdev_global(2)
+          this%vov_scaling_prm(2,2) = (1.0_bp - &
+               EPSILON(elements_global(2) - elements_global(2))) / &
+               stdev_global(2)
+       END IF
+    END IF
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "STARTING MAPPING ..."
+       WRITE(stdout,"(2X,A,1X,6(F7.3,1X))") "Scaling parameters (lo):", this%vov_scaling_prm(:,1)
+       WRITE(stdout,"(2X,A,1X,6(F7.3,1X))") "Scaling parameters (hi):", this%vov_scaling_prm(:,2)
+    END IF
+
+
+    !!
+    !! 2) LOCAL MAPS VIA LOCAL LEAST SQUARES
+    !!
+    !!
+    imap_zero = NINT(this%vov_nmap_prm*this%vov_scaling_prm(indx,1) / &
+         SUM(this%vov_scaling_prm(indx,:)))
+    mapping_interval = SUM(this%vov_scaling_prm(indx,:))*stdev_global(indx)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,1X,I0)") "Central mapping element:", imap_zero
+       WRITE(stdout,"(2X,A,1X,F10.6)") "Mapping interval:", mapping_interval
+    END IF
+    ! Elements used for local least squares solutions:
+    CALL setParameters(this, ls_element_mask=.NOT.this%vov_mapping_mask_prm)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (230)", 1)
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! Mapping parameters lower or equal to midpoint (<= global ls)
+    DO imap=imap_zero,1,-1
+       IF (imap == imap_zero) THEN
+          ! First local solution -> start from the global solution:
+          elements_local = elements_global
+       ELSE
+          !Â Start from the nearest local solution:
+          elements_local = elements_local_arr(imap+1,1:6)
+       END IF
+       elements_local(indx) = elements_global(indx) + &
+            REAL(imap-imap_zero,bp)/(this%vov_nmap_prm-imap_zero) * &
+            this%vov_scaling_prm(indx,1)*stdev_global(indx)
+       CALL NEW(orb_local, elements_local, element_type, frame, t0)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (235)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       CALL setParameters(orb_local, &
+            dyn_model=this%dyn_model_prm, &
+            perturbers=this%perturbers_prm, &
+            integration_step=this%integration_step_prm, &
+            integrator=this%integrator_prm)
+       !, &
+       !finite_diff=this%finite_diff_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (245)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! Local least-squares fits:
+       info_verb_ = info_verb
+       IF (this%vov_niter_cmp > 0) THEN
+          info_verb = info_verb - 1
+       END IF
+       CALL levenbergMarquardt(this, orb_local)
+       info_verb = info_verb_
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (250)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       CALL NULLIFY(orb_local)
+       orb_local = copy(this%orb_ml_cmp)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (255)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       elements_local_arr(imap,1:6) = getElements(orb_local, element_type)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (260)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! 6x6 correlation matrix where elements on the lines
+       ! corresponding to the mapping parameter are zero and the
+       ! diagonal element is 1:
+       covariance_local = getCovarianceMatrix(this, element_type, frame)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (265)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! C = S^(-1) Sigma S^(-1)
+       correlation_matrix = MATMUL(MATMUL(partial_inverse_stdev_global, &
+            covariance_local), partial_inverse_stdev_global)
+       ! Find eigenvalues and eigenvectors:
+       CALL eigen_decomposition_jacobi(correlation_matrix, &
+            eigenvalues, eigenvectors, nrot, errstr)
+       IF (LEN_TRIM(errstr) > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Eigen decomposition failed: " // TRIM(errstr), 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       DO i=1,6
+          principal_axes(imap,1:6,i) = SQRT(eigenvalues(i))*partial_stdev_global(1:6)*eigenvectors(1:6,i)
+       END DO
+       product_local = 1.0_bp
+       DO i=1,6
+          IF (this%vov_mapping_mask_prm(i)) THEN
+             CYCLE
+          END IF
+          IF (eigenvalues(i) < 0.0_bp) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "Negative local eigenvalue:", 1)
+             IF (err_verb >= 1) THEN
+                WRITE(stderr,"(6(E15.7,1X))") eigenvalues
+             END IF
+          END IF
+          product_local = product_local*ABS(eigenvalues(i))
+       END DO
+       debiasing_factor_map(imap) = SQRT(product_local/partial_product_global)
+       CALL NULLIFY(orb_local)
+       IF (info_verb >= 2) THEN
+          IF (MOD(imap-1,100) == 0) THEN
+             WRITE(stdout,"(2X,I0,1X,A)") imap_zero-imap, "local least squares computed..."
+          END IF
+!!$          IF (MOD(imap,100) == 0) THEN
+!!$             WRITE(stdout,*) imap
+!!$          END IF
+       END IF
+    END DO
+
+    ! Mapping parameters larger than midpoint (> global ls)
+    DO imap=imap_zero+1,this%vov_nmap_prm
+       !Â Start from the nearest local solution:
+       elements_local = elements_local_arr(imap-1,1:6)
+       elements_local(indx) = elements_global(indx) + &
+            REAL(imap-imap_zero,bp)/(this%vov_nmap_prm-imap_zero) * &
+            this%vov_scaling_prm(indx,2)*stdev_global(indx)
+       CALL NEW(orb_local, elements_local, element_type, frame, t0)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (235)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       CALL setParameters(orb_local, &
+            perturbers=this%perturbers_prm, &
+            dyn_model=this%dyn_model_prm, &
+            integration_step=this%integration_step_prm, &
+            integrator=this%integrator_prm)
+       !, &
+       !finite_diff=this%finite_diff_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (245)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! Local least-squares fits:
+       info_verb_ = info_verb
+       IF (this%vov_niter_cmp > 0) THEN
+          info_verb = info_verb - 1
+       END IF
+       CALL levenbergMarquardt(this, orb_local)
+       info_verb = info_verb_
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (250)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       CALL NULLIFY(orb_local)
+       orb_local = copy(this%orb_ml_cmp)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (255)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       elements_local_arr(imap,1:6) = getElements(orb_local, element_type)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (260)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! 6x6 correlation matrix where elements on the lines
+       ! corresponding to the mapping parameter are zero and the
+       ! diagonal element is 1:
+       covariance_local = getCovarianceMatrix(this, element_type, frame)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (265)", 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       ! C = S^(-1) Sigma S^(-1)
+       correlation_matrix = MATMUL(MATMUL(partial_inverse_stdev_global, &
+            covariance_local), partial_inverse_stdev_global)
+       ! Find eigenvalues and eigenvectors:
+       CALL eigen_decomposition_jacobi(correlation_matrix, &
+            eigenvalues, eigenvectors, nrot, errstr)
+       IF (LEN_TRIM(errstr) > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Eigen decomposition failed: " // TRIM(errstr), 1)
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+       DO i=1,6
+          principal_axes(imap,1:6,i) = SQRT(eigenvalues(i))*partial_stdev_global(1:6)*eigenvectors(1:6,i)
+       END DO
+       product_local = 1.0_bp
+       DO i=1,6
+          IF (this%vov_mapping_mask_prm(i)) THEN
+             CYCLE
+          END IF
+          IF (eigenvalues(i) < 0.0_bp) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "Negative local eigenvalue:", 1)
+             IF (err_verb >= 1) THEN
+                WRITE(stderr,"(6(E15.7,1X))") eigenvalues
+             END IF
+          END IF
+          product_local = product_local*ABS(eigenvalues(i))
+       END DO
+       debiasing_factor_map(imap) = SQRT(product_local/partial_product_global)
+       CALL NULLIFY(orb_local)
+       IF (info_verb >= 2) THEN
+          IF (MOD(imap,100) == 0) THEN
+             WRITE(stdout,"(2X,I0,1X,A)") imap, "local least squares computed..."
+          END IF
+       END IF
+    END DO
+
+    !PRINT*,' Mapping done.'
+
+    !!
+    !! 3) MONTE CARLO SIMULATION USING MAPPED INTERVALS
+    !!
+    CALL setParameters(this, outlier_rejection=outlier_rejection_)
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "STARTING MONTE CARLO SAMPLING ..."
+    END IF
+    failed_flag = 0
+    iorb = 0
+    itrial = 0
+    norb = this%vov_norb_prm
+    IF (norb > norb_simult_max) THEN
+       norb = norb_simult_max
+    END IF
+    ires = 0 ; ipdf = 0
+    vov_main: DO WHILE (iorb < this%vov_norb_prm .AND. itrial < this%vov_ntrial_prm)
+
+       itrial = itrial + norb
+       naccepted = 0
+       IF (.NOT.ASSOCIATED(orb_arr)) THEN
+          ALLOCATE(orb_arr(norb), imap_arr(norb), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "Could not allocate memory (10).", 1)
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(principal_axes, stat=err)
+             DEALLOCATE(debiasing_factor_arr, stat=err)
+             DEALLOCATE(debiasing_factor_map, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(cosdec0, stat=err)
+             DEALLOCATE(residuals3, stat=err)
+             DEALLOCATE(mask_arr2, stat=err)
+             DEALLOCATE(failed_flag, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(jac_arr, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms_arr, stat=err)
+             DEALLOCATE(diff, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(residuals2, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(imap_arr, stat=err)
+             CALL NULLIFY(orb_global)
+             CALL NULLIFY(orb_local)
+             CALL NULLIFY(t0)
+             RETURN
+          END IF
+       END IF
+
+       !!
+       !! 4) ORBIT GENERATION
+       !! 
+
+       ! Uniform sampling for the mapping parameter over the predefined mapping inteval:
+
+       ! NOTES:
+       ! 1) Currently we use directly the precomputed map, that is, we choose the closest 
+       !    mapping point of the local maximum-p.d.f.'s points and use the corresponding 
+       !    local intervals of variation. Should this be done with interpolation as stated 
+       !    in Muinonen et al.?
+       i = 0
+       DO
+
+          CALL randomNumber(ran_arr)
+          ! Generate random point along the mapping axis:
+          mapping_point = elements_local_arr(1,indx) + &
+               ran_arr(indx) * mapping_interval
+          ! Find mapping point closest to the random point:
+          imap = NINT(1+ABS(mapping_point - elements_local_arr(1,indx)) / &
+               (mapping_interval/(this%vov_nmap_prm-1)))
+          ! Uniform sampling for the remaining parameters using the (not
+          ! interpolated!) precomputed map:
+          DO ielem=1,6
+             IF (this%vov_mapping_mask_prm(ielem)) THEN
+                ! Use the generated mapping point
+                elements(ielem) = mapping_point
+             ELSE
+                ! Use 5x5 covariances of the nearest mapping point
+                variation = this%vov_scaling_prm(ielem,1) * &
+                     SUM((2.0_bp*ran_arr - 1.0_bp)*principal_axes(imap,ielem,:))
+                elements(ielem) = elements_local_arr(imap,ielem) + variation 
+             END IF
+          END DO
+          IF (element_type == "keplerian") THEN
+             IF (elements(2) < 0.0_bp .OR. elements(2) > 1.0_bp) THEN
+                ! Eccentricity out of bounds (or should non-elliptic orbits be accepted?).
+                itrial = itrial + 1
+                failed_flag(1) = failed_flag(1) + 1
+                WRITE(*,*) "ran", ran_arr
+                CYCLE
+             END IF
+             IF (elements(3) < 0.0_bp .OR. elements(2) > two_pi) THEN
+                ! Inclination not defined.
+                itrial = itrial + 1
+                failed_flag(2) = failed_flag(2) + 1
+                WRITE(*,*) "ran", ran_arr
+                CYCLE
+             END IF
+             ! 0 <= angle < 2pi :
+             elements(4:6) = MODULO(elements(4:6), two_pi)
+          END IF
+          i = i + 1
+          CALL NULLIFY(orb_arr(i))
+          CALL NEW(orb_arr(i), elements, element_type, frame, t0)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "TRACE BACK (315)", 1)
+             error = .FALSE.
+             CALL NULLIFY(orb_arr(i))
+             itrial = itrial + 1
+             i = i - 1
+             CYCLE
+          END IF
+          CALL setParameters(orb_arr(i), &
+               perturbers=this%perturbers_prm, &
+               dyn_model=this%dyn_model_prm, &
+               integration_step=this%integration_step_prm, &
+               integrator=this%integrator_prm)
+          !, &
+          !finite_diff=this%finite_diff_prm)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "TRACE BACK (325)", 1)
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(principal_axes, stat=err)
+             DEALLOCATE(debiasing_factor_arr, stat=err)
+             DEALLOCATE(debiasing_factor_map, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(cosdec0, stat=err)
+             DEALLOCATE(residuals3, stat=err)
+             DEALLOCATE(mask_arr2, stat=err)
+             DEALLOCATE(failed_flag, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(jac_arr, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms_arr, stat=err)
+             DEALLOCATE(diff, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(residuals2, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(imap_arr, stat=err)
+             CALL NULLIFY(orb_global)
+             CALL NULLIFY(orb_local)
+             CALL NULLIFY(t0)
+             RETURN
+          END IF
+          imap_arr(i) = imap
+          IF (i == norb) THEN
+             EXIT
+          END IF
+       END DO
+
+       IF (ASSOCIATED(comp_scoords)) THEN
+          DEALLOCATE(comp_scoords)
+       END IF
+       NULLIFY(comp_scoords)
+       IF (ASSOCIATED(partials4)) THEN
+          DEALLOCATE(partials4)
+       END IF
+       NULLIFY(partials4)
+
+       !!
+       !! 5) ACCEPTANCE / REJECTION OF GENERATED ORBIT
+       !!
+       CALL getEphemerides(orb_arr, obsy_ccoords, comp_scoords, &
+            partials_arr=partials4)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (330)",1)
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(imap_arr, stat=err)
+          DEALLOCATE(comp_scoords, stat=err)
+          DEALLOCATE(partials4, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+
+       DO i=1,norb
+          IF (.NOT. boundOrbit(orb_arr(i), this%apriori_a_max_prm, sma)) THEN
+             IF (err_verb >= 2) THEN
+                WRITE(stderr,*) " PROBLEM: Unbound orbit!", sma
+                CYCLE
+             END IF
+          END IF
+          DO iobs=1,nobs
+             ! Multiply RA partials with cosine of observed declination:
+             partials4(i,2,:,iobs) = partials4(i,2,:,iobs)*cosdec0(iobs)
+             ! Sky-plane residuals and chi-squares:
+             comp_coord = getCoordinates(comp_scoords(i,iobs))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                     "TRACE BACK (335)",1)
+                DO j=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(j))
+                END DO
+                DEALLOCATE(principal_axes, stat=err)
+                DEALLOCATE(debiasing_factor_arr, stat=err)
+                DEALLOCATE(debiasing_factor_map, stat=err)
+                DEALLOCATE(obs_coords, stat=err)
+                DEALLOCATE(cosdec0, stat=err)
+                DEALLOCATE(residuals3, stat=err)
+                DEALLOCATE(mask_arr2, stat=err)
+                DEALLOCATE(failed_flag, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(jac_arr, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms_arr, stat=err)
+                DEALLOCATE(diff, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(residuals2, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(imap_arr, stat=err)
+                DEALLOCATE(comp_scoords, stat=err)
+                DEALLOCATE(partials4, stat=err)
+                RETURN
+             END IF
+             residuals3(iorb+1,iobs,1:6) = obs_coords(iobs,1:6) - comp_coord(1:6)
+             residuals3(iorb+1,iobs,2) = residuals3(iorb+1,iobs,2) * cosdec0(iobs)
+             IF (ABS(residuals3(iorb+1,iobs,2)) > pi) THEN
+                obs_ = obs_coords(iobs,2)
+                comp_ = comp_coord(2)
+                IF (obs_ < comp_) THEN
+                   obs_ = obs_ + two_pi
+                ELSE
+                   comp_ = comp_ + two_pi
+                END IF
+                residuals3(iorb+1,iobs,2) = (obs_ - comp_) * cosdec0(iobs)
+             END IF
+             IF (info_verb >= 4) THEN
+                WRITE(stdout,"(2X,A,3"//TRIM(frmt)//")") "  observed pos.", obs_coords(iobs,1:3)
+                WRITE(stdout,"(2X,A,3"//TRIM(frmt)//")") "  computed pos.", comp_coord(1:3)
+             END IF
+          END DO
+          mask_arr2 = .FALSE.
+          WHERE (this%obs_masks_prm .AND. ABS(residuals3(iorb+1,:,:)) > this%res_accept_prm)
+             mask_arr2 = .TRUE.
+          END WHERE
+          IF (info_verb >= 4) THEN
+             DO iobs=1,nobs
+                WRITE(stdout,"(2X,A,2"//TRIM(frmt)//")") "  O-C residuals (RA, Dec):", &
+                     residuals3(iorb+1,iobs,2:3)/rad_asec
+             END DO
+             WRITE(stdout,"(2X,A,I0,A,I0)") &
+                  " No of omitted obs/included obs: ", &
+                  COUNT(mask_arr2),"/",n0(2)
+          END IF
+          IF (COUNT(mask_arr2) > 0) THEN
+             ! Residuals are too large for at least one observation.
+             failed_flag(3) = failed_flag(3) + 1
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A)") &
+                     " Failed (residuals are too large)"
+             END IF
+             elements = getElements(orb_arr(i),element_type)
+             IF (elements(indx) < elements_global(indx)) THEN
+                ires = ires + 1
+             END IF
+             CYCLE
+          END IF
+
+          ! Compute chi2:
+          chi2 = chi_square(residuals3(iorb+1,:,:), information_matrix_obs, this%obs_masks_prm, errstr)
+          IF (LEN_TRIM(errstr) > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "Computation of chi2 for a sampled orbit failed: " // TRIM(errstr), 1)
+             DO j=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(j))
+             END DO
+             DEALLOCATE(principal_axes, stat=err)
+             DEALLOCATE(debiasing_factor_arr, stat=err)
+             DEALLOCATE(debiasing_factor_map, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(cosdec0, stat=err)
+             DEALLOCATE(residuals3, stat=err)
+             DEALLOCATE(mask_arr2, stat=err)
+             DEALLOCATE(failed_flag, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(jac_arr, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms_arr, stat=err)
+             DEALLOCATE(diff, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(residuals2, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(imap_arr, stat=err)
+             DEALLOCATE(comp_scoords, stat=err)
+             DEALLOCATE(partials4, stat=err)
+             CALL NULLIFY(orb_global)
+             CALL NULLIFY(orb_local)
+             CALL NULLIFY(t0)
+             RETURN
+          END IF
+
+          ! Compute dchi2 wrt best fit orbit
+          dchi2 = chi2 - this%chi2_min_prm
+          IF (this%dchi2_rejection_prm .AND. &
+               dchi2 > this%dchi2_prm) THEN
+             ! The dchi2 is used and its value is not acceptable.
+             failed_flag(4) = failed_flag(4) + 1
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A)") &
+                     "Failed (Delta chi2 value not acceptable)"
+             END IF
+             elements = getElements(orb_arr(i),element_type)
+             IF (elements(indx) < elements_global(indx)) THEN
+                ipdf = ipdf + 1
+             END IF
+             CYCLE
+          END IF
+
+          ! Sigma_elements^(-1) = A^T Sigma_obs^(-1) A, where A is the
+          ! partial derivatives matrix of ephemerides wrt elements:
+          information_matrix_local(:,:) = 0.0_bp
+          DO j=1,nobs
+             information_matrix_local = information_matrix_local + &
+                  MATMUL(MATMUL(TRANSPOSE(partials4(i,1:6,1:6,j)), &
+                  information_matrix_obs(j,1:6,1:6)), &
+                  partials4(i,1:6,1:6,j))
+          END DO
+          IF (this%regularization_prm) THEN
+             ! Jeffrey's apriori:
+             apriori = SQRT(ABS(determinant(information_matrix_local, errstr)))
+             IF (LEN_TRIM(errstr) > 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                     "Computation of determinant for local information matrix failed: " //TRIM(errstr), 1)
+                DO j=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(j))
+                END DO
+                DEALLOCATE(principal_axes, stat=err)
+                DEALLOCATE(debiasing_factor_arr, stat=err)
+                DEALLOCATE(debiasing_factor_map, stat=err)
+                DEALLOCATE(obs_coords, stat=err)
+                DEALLOCATE(cosdec0, stat=err)
+                DEALLOCATE(residuals3, stat=err)
+                DEALLOCATE(mask_arr2, stat=err)
+                DEALLOCATE(failed_flag, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(jac_arr, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms_arr, stat=err)
+                DEALLOCATE(diff, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(residuals2, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(imap_arr, stat=err)
+                DEALLOCATE(comp_scoords, stat=err)
+                DEALLOCATE(partials4, stat=err)
+                CALL NULLIFY(orb_global)
+                CALL NULLIFY(orb_local)
+                CALL NULLIFY(t0)
+                RETURN
+             END IF
+          ELSE
+             apriori = 1.0_bp
+          END IF
+          ! Probability density function:
+          pdf = apriori*EXP(-0.5_bp*(chi2 - SUM(n0(1:6))))*debiasing_factor_map(imap_arr(i))
+          IF (info_verb >= 3) THEN
+             WRITE(stdout,"(2X,A)") "Sample information matrix:"
+             CALL matrix_print(information_matrix_local, stdout, errstr)
+             WRITE(stdout,"(2X,A,1X,2"//TRIM(frmt)//")") "Sample chi2:", chi2, chi2-SUM(n0(1:6))
+             WRITE(stdout,"(2X,A,1X,1"//TRIM(efrmt)//")") "Sample apriori:", apriori
+             WRITE(stdout,"(2X,A,1X,1"//TRIM(efrmt)//")") "Sample pdf:", pdf
+             WRITE(stdout,*)
+          END IF
+
+          ! Jaocobians between different elements
+          CALL partialsCartesianWrtKeplerian(orb_arr(i), jacobian_matrix, "equatorial")
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "TRACE BACK (356) ",4)
+             RETURN
+          ELSE
+             jac_car_kep = ABS(determinant(jacobian_matrix, errstr))
+             IF (LEN_TRIM(errstr) > 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                     "Computation of determinant for local " // &
+                     "jacobian matrix failed: " // TRIM(errstr), 1)
+                DO j=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(j))
+                END DO
+                DEALLOCATE(principal_axes, stat=err)
+                DEALLOCATE(debiasing_factor_arr, stat=err)
+                DEALLOCATE(debiasing_factor_map, stat=err)
+                DEALLOCATE(obs_coords, stat=err)
+                DEALLOCATE(cosdec0, stat=err)
+                DEALLOCATE(residuals3, stat=err)
+                DEALLOCATE(mask_arr2, stat=err)
+                DEALLOCATE(failed_flag, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(jac_arr, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms_arr, stat=err)
+                DEALLOCATE(diff, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(residuals2, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(imap_arr, stat=err)
+                DEALLOCATE(comp_scoords, stat=err)
+                DEALLOCATE(partials4, stat=err)
+                CALL NULLIFY(orb_global)
+                CALL NULLIFY(orb_local)
+                CALL NULLIFY(t0)
+                RETURN
+             END IF
+          END IF
+          elements = getElements(orb_arr(i), "keplerian")
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "TRACE BACK (357) ",4)
+             !error = .FALSE.
+             !jac_equ_kep = -1.0_bp
+             RETURN
+          ELSE
+             jac_equ_kep = 0.5_bp*elements(2)*SIN(0.5_bp*elements(3)) / &
+                  COS(0.5_bp*elements(3))**3
+          END IF
+          !err_verb = err_verb_
+          naccepted = naccepted + 1
+          iorb = iorb + 1
+          orb_accepted(iorb) = copy(orb_arr(i))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "TRACE BACK (355)", 1)
+             DO j=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(j))
+             END DO
+             DEALLOCATE(principal_axes, stat=err)
+             DEALLOCATE(debiasing_factor_arr, stat=err)
+             DEALLOCATE(debiasing_factor_map, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(cosdec0, stat=err)
+             DEALLOCATE(residuals3, stat=err)
+             DEALLOCATE(mask_arr2, stat=err)
+             DEALLOCATE(failed_flag, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(jac_arr, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms_arr, stat=err)
+             DEALLOCATE(diff, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(residuals2, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(imap_arr, stat=err)
+             DEALLOCATE(comp_scoords, stat=err)
+             DEALLOCATE(partials4, stat=err)
+             CALL NULLIFY(orb_global)
+             CALL NULLIFY(orb_local)
+             CALL NULLIFY(t0)
+             RETURN
+          END IF
+
+          reg_apriori_arr(iorb) = apriori
+          pdf_arr(iorb) = pdf
+          debiasing_factor_arr(iorb) = debiasing_factor_map(imap_arr(i))
+          rchi2_arr(iorb) = chi2 - SUM(n0(1:6))
+          jac_arr(iorb,1) = -1.0_bp
+          jac_arr(iorb,2) = jac_car_kep
+          jac_arr(iorb,3) = jac_equ_kep
+          n0_ = n0
+          WHERE (n0_ == 0)
+             n0_ = 1
+          END WHERE
+          rms_arr(iorb,:) = SQRT(SUM(residuals3(iorb,:,:)**2.0_bp,dim=1,mask=this%obs_masks_prm)/n0_)
+          ! P.d.f.:
+          ! - exponential part
+          ! - a priori p.d.f. for invariance (optionally)
+          IF (iorb == this%vov_norb_prm) THEN
+             itrial = itrial - (norb - i)
+             EXIT
+          END IF
+       END DO
+
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,2(I0,1X))") "Nr of accepted orbits and trials: ",naccepted,norb
+       ENDIF
+       IF (naccepted == 0) THEN
+          norb = norb*100
+       ELSE
+          norb = NINT((this%vov_norb_prm - iorb)*(1.2_bp*norb/naccepted))
+       END IF
+       IF (norb > norb_simult_max) THEN
+          norb = norb_simult_max
+       END IF
+       IF (norb /= SIZE(orb_arr,dim=1)) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, imap_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+                  "Could not deallocate memory (10).", 1)
+             DEALLOCATE(principal_axes, stat=err)
+             DEALLOCATE(debiasing_factor_arr, stat=err)
+             DEALLOCATE(debiasing_factor_map, stat=err)
+             DEALLOCATE(obs_coords, stat=err)
+             DEALLOCATE(cosdec0, stat=err)
+             DEALLOCATE(residuals3, stat=err)
+             DEALLOCATE(mask_arr2, stat=err)
+             DEALLOCATE(failed_flag, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(jac_arr, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms_arr, stat=err)
+             DEALLOCATE(diff, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(residuals2, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(imap_arr, stat=err)
+             DEALLOCATE(comp_scoords, stat=err)
+             DEALLOCATE(partials4, stat=err)
+             CALL NULLIFY(orb_global)
+             CALL NULLIFY(orb_local)
+             CALL NULLIFY(t0)
+             RETURN
+          END IF
+       END IF
+       DEALLOCATE(comp_scoords, partials4, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Could not deallocate memory (15).", 1)
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(imap_arr, stat=err)
+          DEALLOCATE(comp_scoords, stat=err)
+          DEALLOCATE(partials4, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+
+    END DO vov_main
+
+    this%vov_ntrial_cmp = itrial
+    this%vov_norb_cmp = iorb
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "Final number of orbits and the required trials:"
+       WRITE(stdout,"(2X,2(I0,2X))") iorb, itrial
+       WRITE(stdout,*) " Total failure percentage (1), and failure " // &
+            "due to (2) eccentricity, (3) inclination, " // &
+            "(4) residuals, and (5) pdf:"
+       nfailed = SUM(failed_flag)
+       nfailed = MAX(1,nfailed)
+       WRITE(stdout,"(2X,5"//TRIM(frmt)//")") &
+            100.0_lp*REAL(SUM(failed_flag),lp)/itrial, &
+            100.0_lp*REAL(failed_flag(1),lp)/nfailed, &
+            100.0_lp*REAL(failed_flag(2),lp)/nfailed, &
+            100.0_lp*REAL(failed_flag(3),lp)/nfailed, &
+            100.0_lp*REAL(failed_flag(4),lp)/nfailed
+    END IF
+
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "Could not deallocate memory (20).", 1)
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(imap_arr, stat=err)
+          DEALLOCATE(comp_scoords, stat=err)
+          DEALLOCATE(partials4, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(this%orb_arr_cmp(iorb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "Could not allocate memory (15).", 1)
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(imap_arr, stat=err)
+       DEALLOCATE(comp_scoords, stat=err)
+       DEALLOCATE(partials4, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(orb_local)
+       CALL NULLIFY(t0)
+       RETURN       
+    END IF
+    IF (iorb == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "No sample orbit found.", 1)
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(imap_arr, stat=err)
+       DEALLOCATE(comp_scoords, stat=err)
+       DEALLOCATE(partials4, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(orb_local)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+
+    ! Output: sample orbits, mapping orbits and local intervals of variation (for plotting)
+    DO i=1,iorb
+       this%orb_arr_cmp(i) = copy(orb_accepted(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+               "TRACE BACK (365)", 1)
+          IF (ASSOCIATED(orb_arr)) THEN
+             DO j=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(j))
+             END DO
+             DEALLOCATE(orb_arr, stat=err)
+          END IF
+          DEALLOCATE(principal_axes, stat=err)
+          DEALLOCATE(debiasing_factor_arr, stat=err)
+          DEALLOCATE(debiasing_factor_map, stat=err)
+          DEALLOCATE(obs_coords, stat=err)
+          DEALLOCATE(cosdec0, stat=err)
+          DEALLOCATE(residuals3, stat=err)
+          DEALLOCATE(mask_arr2, stat=err)
+          DEALLOCATE(failed_flag, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(jac_arr, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms_arr, stat=err)
+          DEALLOCATE(diff, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(residuals2, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(imap_arr, stat=err)
+          DEALLOCATE(comp_scoords, stat=err)
+          DEALLOCATE(partials4, stat=err)
+          CALL NULLIFY(orb_global)
+          CALL NULLIFY(orb_local)
+          CALL NULLIFY(t0)
+          RETURN
+       END IF
+    END DO
+    CALL propagate(this%orb_arr_cmp, t0)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (370)", 1)
+       IF (ASSOCIATED(orb_arr)) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+       END IF
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(imap_arr, stat=err)
+       DEALLOCATE(comp_scoords, stat=err)
+       DEALLOCATE(partials4, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(orb_local)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    ! Maximum likelihood point:
+    CALL NULLIFY(this%orb_ml_cmp)
+    this%orb_ml_cmp = copy(orb_global)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / volumeOfVariation", &
+            "TRACE BACK (375)", 1)
+       IF (ASSOCIATED(orb_arr)) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, stat=err)
+       END IF
+       DEALLOCATE(principal_axes, stat=err)
+       DEALLOCATE(debiasing_factor_arr, stat=err)
+       DEALLOCATE(debiasing_factor_map, stat=err)
+       DEALLOCATE(obs_coords, stat=err)
+       DEALLOCATE(cosdec0, stat=err)
+       DEALLOCATE(residuals3, stat=err)
+       DEALLOCATE(mask_arr2, stat=err)
+       DEALLOCATE(failed_flag, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(jac_arr, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms_arr, stat=err)
+       DEALLOCATE(diff, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(residuals2, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(imap_arr, stat=err)
+       DEALLOCATE(comp_scoords, stat=err)
+       DEALLOCATE(partials4, stat=err)
+       CALL NULLIFY(orb_global)
+       CALL NULLIFY(orb_local)
+       CALL NULLIFY(t0)
+       RETURN
+    END IF
+    CALL NULLIFY(orb_global)
+    IF (.NOT.ASSOCIATED(this%cov_ml_cmp)) THEN
+       ALLOCATE(this%cov_ml_cmp(6,6), stat=err)
+    END IF
+    this%cov_ml_cmp = covariance_global
+    this%cov_type_prm = this%element_type_prm
+    this%ls_elem_mask_prm = element_mask
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%pdf_arr_cmp(iorb), stat=err)
+    this%pdf_arr_cmp = pdf_arr(1:iorb)
+    IF (ASSOCIATED(this%reg_apr_arr_cmp)) THEN
+       DEALLOCATE(this%reg_apr_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%reg_apr_arr_cmp(iorb), stat=err)
+    this%reg_apr_arr_cmp = reg_apriori_arr(1:iorb)
+    IF (ASSOCIATED(this%jac_arr_cmp)) THEN
+       DEALLOCATE(this%jac_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%jac_arr_cmp(iorb,3), stat=err)
+    this%jac_arr_cmp = jac_arr(1:iorb,1:3)
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%rchi2_arr_cmp(iorb), stat=err)
+    this%rchi2_arr_cmp = rchi2_arr(1:iorb)
+    this%chi2_min_cmp = MINVAL(this%rchi2_arr_cmp) + SUM(n0(1:6))
+    IF (ASSOCIATED(this%rms_arr_cmp)) THEN
+       DEALLOCATE(this%rms_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%rms_arr_cmp(iorb,6), stat=err)
+    this%rms_arr_cmp = rms_arr(1:iorb,1:6)
+    IF (ASSOCIATED(this%vov_map_cmp)) THEN
+       DEALLOCATE(this%vov_map_cmp, stat=err)
+    END IF
+    ALLOCATE(this%vov_map_cmp(this%vov_nmap_prm,12), stat=err)
+    DO i=1,this%vov_nmap_prm
+       this%vov_map_cmp(i,1:6) = elements_local_arr(i,1:6)
+       DO j=1,6
+          this%vov_map_cmp(i,6+j) = 0.0_bp
+          IF (j == indx) THEN
+             this%vov_map_cmp(i,6+j) = stdev_global(j)
+             CYCLE
+          END IF
+
+          DO k=1,6
+             IF (principal_axes(i,j,k) > 0.0_bp) THEN
+                this%vov_map_cmp(i,6+j) = this%vov_map_cmp(i,6+j) + principal_axes(i,j,k)
+             ELSE
+                this%vov_map_cmp(i,6+j) = this%vov_map_cmp(i,6+j) - principal_axes(i,j,k)                
+             END IF
+          END DO
+       END DO
+    END DO
+    this%vov_scaling_cmp = this%vov_scaling_prm
+
+    IF (ASSOCIATED(orb_arr)) THEN
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(orb_arr, stat=err)
+    END IF
+    DO i=1,SIZE(orb_accepted)
+       CALL NULLIFY(orb_accepted(i))
+    END DO
+    DEALLOCATE(principal_axes, stat=err)
+    DEALLOCATE(debiasing_factor_arr, stat=err)
+    DEALLOCATE(debiasing_factor_map, stat=err)
+    DEALLOCATE(obs_coords, stat=err)
+    DEALLOCATE(cosdec0, stat=err)
+    DEALLOCATE(residuals3, stat=err)
+    DEALLOCATE(mask_arr2, stat=err)
+    DEALLOCATE(failed_flag, stat=err)
+    DEALLOCATE(reg_apriori_arr, stat=err)
+    DEALLOCATE(pdf_arr, stat=err)
+    DEALLOCATE(jac_arr, stat=err)
+    DEALLOCATE(rchi2_arr, stat=err)
+    DEALLOCATE(rms_arr, stat=err)
+    DEALLOCATE(diff, stat=err)
+    DEALLOCATE(obs_scoords, stat=err)
+    DEALLOCATE(obsy_ccoords, stat=err)
+    DEALLOCATE(residuals2, stat=err)
+    DEALLOCATE(information_matrix_obs, stat=err)
+    DEALLOCATE(imap_arr, stat=err)
+    DEALLOCATE(comp_scoords, stat=err)
+    DEALLOCATE(partials4, stat=err)
+
+  END SUBROUTINE volumeOfVariation
+
+
+
+
+
+  SUBROUTINE virtualObservationMCMC(this, orb_arr_in)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+    TYPE (Orbit), DIMENSION(:), INTENT(in) :: orb_arr_in
+    TYPE (Time) :: &
+         t0, &
+         t
+    TYPE (Orbit), DIMENSION(:), POINTER :: &
+         orb_accepted, &
+         orb_arr
+    TYPE (Orbit) :: &
+         orb
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=DYN_MODEL_LEN) :: &
+         storb_dyn_model, &
+         orb_dyn_model
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         storb_integrator, &
+         orb_integrator
+    CHARACTER(len=64) :: &
+         frmt = "(F20.15,1X)", &
+         efrmt = "(E10.4,1X)"
+    CHARACTER(len=64) :: &
+         str
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE :: &
+         principal_axes
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         elements_arr, &
+         elements_arr_, &
+         elements_mean, &
+         elements_running_mean
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         rchi2_arr, &
+         sampling_volume_arr, &
+         sampling_cdf, &
+         pdf_arr
+    REAL(bp), DIMENSION(this%vomcmc_nmap_prm,6) :: &
+         elements_local_arr
+    REAL(bp), DIMENSION(this%vomcmc_nmap_prm,2) :: &
+         mapping_intervals
+    REAL(bp), DIMENSION(6,6) :: &
+         local_covariance
+    REAL(bp), DIMENSION(5,5) :: &
+         eigenvectors, &
+         element_ranges, &
+         inv_local_sigmas, &
+         local_sigmas, &
+         local_5x5_covariance, &
+         local_5x5_correlation, &
+         mat
+    REAL(bp), DIMENSION(3) :: &
+         ran_arr
+    REAL(bp), DIMENSION(6) :: &
+         elements_local, &
+         elements, &
+         local_mean, &
+         upper_limit, &
+         lower_limit
+    REAL(bp), DIMENSION(5) :: &
+         eigenvalues
+    REAL(bp) :: &
+         a_r, &
+         product_local, &
+         mapping_end, &
+         mapping_interval, &
+         mapping_point, &
+         mapping_resolution, &
+         mapping_start, &
+         ran, &
+         running_mean_start, &
+         storb_integration_step, &
+         orb_integration_step,&
+         variation
+    INTEGER, DIMENSION(:), ALLOCATABLE :: &
+         indx_arr
+    INTEGER :: &
+         i, &
+         j, &
+         k, &
+         imap, &
+         jmap, &
+         itrial, &
+         iorb, &
+         indx, &
+         err, &
+         norb, &
+         naccepted, &
+         nmap, &
+         nrot, &
+         ielem
+    LOGICAL, DIMENSION(:,:), ALLOCATABLE :: &
+         obs_masks_
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: &
+         mask_arr
+    LOGICAL, DIMENSION(6) :: &
+         mask
+    LOGICAL :: &
+         accept, &
+         first, &
+         outlier_rejection_, &
+         parameters_agree
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (getNrOfObservations(this%obss) < 3) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Less than two observations available.", 1)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%obs_masks_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Observation masks not set.", 1)
+       RETURN
+    END IF
+    ALLOCATE(obs_masks_(SIZE(this%obs_masks_prm,dim=1),SIZE(this%obs_masks_prm,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "observationSampling", &
+            "Could not allocate memory.", 1)
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    obs_masks_ = this%obs_masks_prm
+
+    IF (.NOT.ASSOCIATED(this%res_accept_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Window for accepted residuals not set.", 1)
+       RETURN
+    END IF
+    IF (this%vomcmc_norb_prm < 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Required number of sample orbits not set.", 1)
+       RETURN
+    END IF
+!!$    CALL comparePropagationParameters(this, orb_arr(1), &
+!!$         parameters_agree=parameters_agree)
+!!$    IF (error .OR. .NOT.parameters_agree) THEN
+!!$       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+!!$            "TRACE BACK (1)", 1)
+!!$       RETURN
+!!$    END IF
+
+    frame = getFrame(orb_arr_in(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "TRACE BACK (70)", 1)
+       RETURN
+    END IF
+    ! Inversion epoch is bound to the epoch of the first input orbit:
+    t0 = getTime(orb_arr_in(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "TRACE BACK (65)", 1)
+       RETURN
+    END IF
+
+    !!
+    !! 1) LOCAL SAMPLING MAPS AND VOLUMES VIA LOCAL EMPIRICAL
+    !!     COVARIANCES
+    !!
+
+    ! Generate the orbits needed for mapping the relevant phase-space
+    ! regime. Also set this%chi2_min_prm to the chi2 corresponding to
+    ! the best fit orbit to the nominal set of obserations:
+    IF (.FALSE.) THEN
+       CALL observationSampling(this, orb_arr_in)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "TRACE BACK (66)", 1)       
+          RETURN
+       END IF
+       ALLOCATE(orb_arr(SIZE(this%orb_arr_cmp)), rchi2_arr(SIZE(this%orb_arr_cmp)))
+       DO i=1,SIZE(this%orb_arr_cmp)
+          orb_arr(i) = copy(this%orb_arr_cmp(i))
+       END DO
+       !       rchi2_arr = this%rchi2_arr_cmp
+    ELSE
+       ALLOCATE(orb_arr(SIZE(orb_arr_in)), rchi2_arr(SIZE(orb_arr_in)))
+       DO i=1,SIZE(orb_arr_in)
+          orb_arr(i) = copy(orb_arr_in(i))
+          !          rchi2_arr(i) = getChi2(this, orb_arr(i)) - COUNT(this%obs_masks_prm)
+       END DO
+       !       this%chi2_min_prm = MINVAL(rchi2_arr) + COUNT(this%obs_masks_prm)
+    END IF
+    ALLOCATE(elements_arr(SIZE(orb_arr),6))!, &
+    !        indx_arr(SIZE(orb_arr)), &
+    !        mask_arr(SIZE(orb_arr)), &
+    !        elements_mean(this%vomcmc_nmap_prm,6), &
+    !        principal_axes(this%vomcmc_nmap_prm,5,5), &
+    !        sampling_volume_arr(this%vomcmc_nmap_prm))
+    DO i=1,SIZE(orb_arr)
+       elements_arr(i,:) = getElements(orb_arr(i), this%element_type_prm)
+    END DO
+!!$    ! Use one of the first three elements with the largest variability
+!!$    ! as mapping parameter:
+!!$    a_r = TINY(a_r)
+!!$    DO i=1,3
+!!$       IF (MAXVAL(elements_arr(:,i)) - MINVAL(elements_arr(:,i)) > a_r) THEN
+!!$          indx = i
+!!$          a_r = MAXVAL(elements_arr(:,i)) - MINVAL(elements_arr(:,i))
+!!$       END IF
+!!$    END DO
+!!$    mask=.TRUE.
+!!$    mask(indx) = .FALSE.
+!!$    WRITE(stdout,*) "Mapping parameter: ", indx
+!!$    CALL quickSort(elements_arr(:,indx), indx_arr, errstr)
+!!$    IF (LEN_TRIM(errstr) > 0) THEN
+!!$       error = .TRUE.
+!!$       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+!!$            "quickSort failed: " // TRIM(errstr), 1)
+!!$       RETURN
+!!$    END IF
+!!$
+!!$    ! find lower bound for mapping parameter
+!!$    mapping_start = elements_arr(indx_arr(1),indx) - EPSILON(mapping_start)
+!!$    ! find upper bound for mapping parameter
+!!$    mapping_end = elements_arr(indx_arr(SIZE(orb_arr)),indx) + EPSILON(mapping_end)
+!!$    IF (.TRUE.) THEN
+!!$       ! tune mapping start by starting from the smallest mapping
+!!$       ! parameter that has a small enough dchi2 
+!!$       DO i=1,SIZE(rchi2_arr)
+!!$          IF (rchi2_arr(indx_arr(i)) - (this%chi2_min_prm - COUNT(this%obs_masks_prm)) < this%dchi2_prm) THEN
+!!$             !mapping_start = elements_arr(indx_arr(MAX(1,i-1)),indx)
+!!$             mapping_start = elements_arr(indx_arr(MAX(1,i)),indx) - &
+!!$                  10000*EPSILON(mapping_start)
+!!$             EXIT
+!!$          END IF
+!!$       END DO
+!!$       ! tune mapping stop by stopping after the largest mapping
+!!$       ! parameter that has a small enough dchi2
+!!$       DO i=SIZE(rchi2_arr),1,-1
+!!$          IF (rchi2_arr(indx_arr(i)) - (this%chi2_min_prm - COUNT(this%obs_masks_prm)) < this%dchi2_prm) THEN
+!!$             !mapping_end = elements_arr(indx_arr(MIN(SIZE(orb_arr),i+1)),indx)
+!!$             mapping_end = elements_arr(indx_arr(MIN(SIZE(orb_arr),i)),indx) + &
+!!$                  10000*EPSILON(mapping_end)
+!!$             EXIT
+!!$          END IF
+!!$       END DO
+!!$    END IF
+!!$    mapping_resolution = (mapping_end - mapping_start) / this%vomcmc_nmap_prm
+!!$    !    WRITE(stdout,*) mapping_start, mapping_end, mapping_resolution
+!!$
+!!$    !    OPEN(78,file="fort.78")
+!!$
+!!$    ! Local 5D hyperrectangles:
+!!$    DO imap=1, this%vomcmc_nmap_prm
+!!$
+!!$       IF (.TRUE.) THEN ! Fixed bin width, variable sample size
+!!$          ! Select orbits that fall within the boundaries of the local
+!!$          ! bin:
+!!$          mask_arr = .FALSE.
+!!$          WHERE (elements_arr(:,indx) > mapping_start + (imap-1)*mapping_resolution .AND. &
+!!$               elements_arr(:,indx) <= mapping_start + imap*mapping_resolution)
+!!$             mask_arr = .TRUE.
+!!$          END WHERE
+!!$          IF (COUNT(mask_arr) < 10) THEN
+!!$             error = .TRUE.
+!!$             CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+!!$                  "Too few orbits in bin:", 1)
+!!$             WRITE(stderr,"(A,I0,A,1X,I0,1X,A)") "Bin #", imap, ":", COUNT(mask_arr), "orbits"
+!!$             RETURN
+!!$          END IF
+!!$          ALLOCATE(elements_arr_(COUNT(mask_arr),6))
+!!$          j = 0
+!!$          DO i=1,SIZE(elements_arr,dim=1)
+!!$             IF (mask_arr(i)) THEN
+!!$                j = j + 1
+!!$                elements_arr_(j,:) = elements_arr(i,:)
+!!$             END IF
+!!$          END DO
+!!$          mapping_intervals(imap,1) = mapping_start + (imap-1)*mapping_resolution
+!!$          mapping_intervals(imap,2) = mapping_start + imap*mapping_resolution
+!!$       ELSE ! Variable bin width, fixed sample size
+!!$          ! The last element of the previous subset:
+!!$          i = (imap-1)*FLOOR(1.0_bp*SIZE(elements_arr,dim=1)/this%vomcmc_nmap_prm)
+!!$          ! Allocate temporary container for orbital elements
+!!$          IF (imap /= this%vomcmc_nmap_prm) THEN
+!!$             ALLOCATE(elements_arr_(FLOOR(1.0_bp*SIZE(elements_arr,dim=1)/this%vomcmc_nmap_prm),6))
+!!$          ELSE
+!!$             ALLOCATE(elements_arr_(SIZE(elements_arr,dim=1)-i,6))
+!!$          END IF
+!!$          ! Fill temporary container with orbital elements
+!!$          DO k=1,SIZE(elements_arr_,dim=1)
+!!$             elements_arr_(k,:) = elements_arr(indx_arr(i+k),:)
+!!$          END DO
+!!$          mapping_intervals(imap,1) = elements_arr_(1,indx) 
+!!$          mapping_intervals(imap,2) = elements_arr_(SIZE(elements_arr_,dim=1),indx) 
+!!$       END IF
+!!$       ! Compute local 6D population covariance:
+!!$       CALL population_covariance(elements_arr_, local_covariance, local_mean)
+!!$       IF (error) THEN
+!!$          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+!!$               "TRACE BACK (265)", 1)
+!!$          RETURN
+!!$       END IF
+!!$       DEALLOCATE(elements_arr_)
+!!$       ! Extract the local 5x5 covariance by removing the row and
+!!$       ! column containing the covariances for the mapping parameter
+!!$       DO i=1,6
+!!$          IF (mask(i)) THEN
+!!$             local_5x5_covariance(COUNT(mask(:i)),:) = PACK(local_covariance(i,:), mask)
+!!$          END IF
+!!$       END DO
+!!$       ! Extract sigmas and construct correlation matrix for a more
+!!$       ! robust eigenvalue decomposition
+!!$       local_5x5_correlation = local_5x5_covariance
+!!$       local_sigmas = 0.0_bp
+!!$       inv_local_sigmas = 0.0_bp
+!!$       DO i=1,5
+!!$          local_sigmas(i,i) = SQRT(local_5x5_covariance(i,i))
+!!$          inv_local_sigmas(i,i) = 1.0_bp/local_sigmas(i,i)
+!!$       END DO
+!!$       local_5x5_correlation = MATMUL(MATMUL(inv_local_sigmas,local_5x5_covariance),inv_local_sigmas)
+!!$
+    !       write(*,*) 
+    !       write(*,*) "local_5x5_correlation:"
+    !       call matrix_print(local_5x5_correlation, stdout, errstr)
+    !       write(stdout,*)
+    !       !stop
+!!$
+!!$       ! Compute eigenvalues and eigenvectors for the local 5D covariance
+!!$       ! matrix:
+!!$       CALL eigen_decomposition_jacobi(local_5x5_correlation, &
+!!$            eigenvalues, eigenvectors, nrot, errstr)
+!!$       IF (LEN_TRIM(errstr) > 0) THEN
+!!$          error = .TRUE.
+!!$          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+!!$               "Eigen decomposition failed: " // TRIM(errstr), 1)
+!!$          RETURN
+!!$       END IF
+    !       ! Compute eigenvalues and eigenvectors for the local 5D covariance
+    !       ! matrix:
+    !       CALL eigen_decomposition_jacobi(local_5x5_covariance, &
+    !            eigenvalues, eigenvectors, nrot, errstr)
+    !       IF (LEN_TRIM(errstr) > 0) THEN
+    !          error = .TRUE.
+    !          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+    !               "Eigen decomposition failed: " // TRIM(errstr), 1)
+    !          RETURN
+    !       END IF
+!!$
+    !       WRITE(stdout,*) "eigendecomposition", imap, nrot
+    !       call matrix_print(eigenvectors, stdout, errstr)
+    !       write(stdout,*)
+    !       do i=1,5
+    !          write(stdout,*) sqrt(eigenvalues(i))
+    !       end do
+    !       write(stdout,*)
+!!$
+!!$       ! Put sigmas back into the eigen solution
+!!$       eigenvectors = MATMUL(MATMUL(TRANSPOSE(local_sigmas),eigenvectors),local_sigmas)
+!!$       DO i=1,5
+!!$          eigenvectors(:,i) = eigenvalues(i)*eigenvectors(:,i)
+!!$          eigenvalues(i) = SQRT(SUM(eigenvectors(:,i)**2))
+!!$          eigenvectors(:,i) = eigenvectors(:,i)/eigenvalues(i)
+!!$       END DO
+!!$
+    !       WRITE(stdout,*) "reconstructed eigendecomposition"
+    !       call matrix_print(eigenvectors, stdout, errstr)
+    !       write(stdout,*)
+    !       do i=1,5
+    !          write(stdout,*) sqrt(eigenvalues(i))
+    !       end do
+    !       write(stdout,*)
+!!$
+!!$       ! Mean elements:
+!!$       elements_mean(imap,1:6) = local_mean
+!!$       ! Relative sampling volumes (= lenght of mapping range times volume of 5-parallelotope):
+!!$       mat = TRANSPOSE(eigenvectors)
+!!$       DO i=1,5
+!!$          mat(i,:) = eigenvalues(i)*mat(i,:)
+!!$       END DO
+!!$       sampling_volume_arr(imap) = &
+!!$            (mapping_intervals(imap,2) - mapping_intervals(imap,1)) * &
+!!$            SQRT(ABS(determinant(mat,errstr)))
+!!$       ! Compute sampling maps:
+!!$       DO i=1,5
+!!$          principal_axes(imap,1:5,i) = SQRT(eigenvalues(i))*eigenvectors(1:5,i)
+!!$          !WRITE(78,*) imap, sampling_volume_arr(imap), nrot, i, SQRT(eigenvalues(i)), eigenvectors(1:5,i)
+!!$       END DO
+    !
+    !       j = 0
+    !       do i=1,6
+    !          if (i /= indx) then
+    !             j = j + 1
+    !             element_ranges(j,1) = minval(elements_arr_(:,i))
+    !             element_ranges(j,2) = maxval(elements_arr_(:,i))
+    !          end if
+    !       end do
+    !       sampling_volume_arr(imap) = &
+    !            (mapping_intervals(imap,2) - mapping_intervals(imap,1)) * &
+    !            product(element_ranges(:,2)-element_ranges(:,1))
+    !       ! Compute sampling maps:
+    !       principal_axes(imap,1:5,1:5) = 0.0_bp
+    !       DO i=1,5
+    !          principal_axes(imap,i,i) = 0.5_bp*(element_ranges(i,2)-element_ranges(i,1))
+    !          WRITE(78,*) imap, sampling_volume_arr(imap), nrot, i, &
+    !               principal_axes(imap,i,i), principal_axes(imap,1:5,i)
+    !       END DO
+!!$
+!!$    END DO
+!!$    !CLOSE(78)
+!!$
+!!$    ! Running mean for elements with 10x denser sampling than the 5D
+!!$    ! local covariances:
+!!$    running_mean_start = MINVAL(elements_arr(:,indx))
+!!$    ! N full-width bins + 2 half-width bins at the endpoints
+!!$    nmap = CEILING((MAXVAL(elements_arr(:,indx)) - running_mean_start)/mapping_resolution) + 1
+!!$    ALLOCATE(elements_running_mean(10*nmap,6))
+!!$    DO imap=1,10*nmap
+!!$       ! Select orbits that fall within the boundaries of the local
+!!$       ! running bin:
+!!$       mask_arr = .FALSE.
+!!$       WHERE (elements_arr(:,indx) > running_mean_start + ((imap-1)/10.0_bp - 0.5_bp)*mapping_resolution .AND. &
+!!$            elements_arr(:,indx) <=  running_mean_start + ((imap-1)/10.0_bp + 0.5_bp)*mapping_resolution)
+!!$          mask_arr = .TRUE.
+!!$       END WHERE
+!!$       ALLOCATE(elements_arr_(COUNT(mask_arr),6))
+!!$       j = 0
+!!$       DO i=1,SIZE(elements_arr,dim=1)
+!!$          IF (mask_arr(i)) THEN
+!!$             j = j + 1
+!!$             elements_arr_(j,:) = elements_arr(i,:)
+!!$          END IF
+!!$       END DO
+!!$       ! Store running mean for elements:
+!!$       DO i=1,6
+!!$          IF (i == indx) THEN
+!!$             elements_running_mean(imap,i) = running_mean_start + ((imap-1)/10.0_bp)*mapping_resolution
+!!$          ELSE
+!!$             elements_running_mean(imap,i) = SUM(elements_arr_(:,i))/REAL(j,bp)
+!!$          END IF
+!!$       END DO
+!!$       DEALLOCATE(elements_arr_)
+!!$    END DO
+
+
+
+
+    !!
+    !! 3) MCMC USING MAPPED INTERVALS
+    !!
+
+    CALL setParameters(this, outlier_rejection=outlier_rejection_)
+    ! Generate a cumulative distribution for the mapping parameter
+    ! based on the local sampling volumes:
+    IF (ASSOCIATED(this%repetition_arr_cmp)) THEN
+       DEALLOCATE(this%repetition_arr_cmp)
+    END IF
+    DEALLOCATE(rchi2_arr)
+    ALLOCATE( &
+                                !sampling_cdf(this%vomcmc_nmap_prm), &
+         orb_accepted(this%vomcmc_norb_prm), &
+         pdf_arr(0:this%vomcmc_norb_prm), &
+         rchi2_arr(this%vomcmc_norb_prm), &
+         this%repetition_arr_cmp(this%vomcmc_norb_prm))
+    this%repetition_arr_cmp = 0
+    !    sampling_cdf(1) = sampling_volume_arr(1)
+    !    DO i=2,this%vomcmc_nmap_prm
+    !       sampling_cdf(i) = sampling_cdf(i-1) + sampling_volume_arr(i)
+    !    END DO
+    !    sampling_cdf = sampling_cdf/sampling_cdf(this%vomcmc_nmap_prm)
+    pdf_arr(0) = TINY(pdf_arr(0))
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "STARTING MCMC SAMPLING ..."
+    END IF
+    iorb = 0
+    itrial = 0
+    norb = this%vomcmc_norb_prm
+    naccepted = 0
+    first = .TRUE.
+    DO WHILE (iorb < this%vomcmc_norb_prm .AND. itrial < this%vomcmc_ntrial_prm)
+
+       itrial = itrial + 1
+
+       !!
+       !! 4) ORBIT GENERATION
+       !! 
+
+       ! Uniform sampling for the mapping parameter over the predefined mapping inteval:
+
+       ! NOTES:
+       ! 1) Currently we use directly the precomputed map, that is, we choose the closest 
+       !    mapping point of the local maximum-p.d.f.'s points and use the corresponding 
+       !    local intervals of variation. Should this be done with interpolation as stated 
+       !    in Muinonen et al.?
+
+       CALL randomNumber(ran_arr)
+!!$       ! Generate random point along the mapping axis based on the
+!!$       ! mapping parameter cdf. First choose a random bin in the
+!!$       ! mapping parameter using the cdf:
+!!$       DO j=1,this%vomcmc_nmap_prm
+!!$          IF  (ran_arr(1+indx) <= sampling_cdf(j)) THEN
+!!$             EXIT
+!!$          END IF
+!!$       END DO
+!!$       ! Generate a random point within the mapping bin using a
+!!$       ! uniform distribution:
+!!$       elements(indx) = mapping_intervals(j,1) + &
+!!$            ran_arr(8) * (mapping_intervals(j,2) - mapping_intervals(j,1))
+!!$       ! Find running-mean elements closest to generated mapping
+!!$       ! parameter:
+!!$       k = MINLOC(ABS(elements(indx)-elements_running_mean(:,indx)), dim=1)
+!!$       ! Uniform sampling for the remaining parameters using the (not
+!!$       ! interpolated!) precomputed map:
+!!$       DO ielem=1,6
+!!$          IF (mask(ielem)) THEN
+!!$             ! Use 5x5 covariances of the nearest mapping point
+!!$             variation = this%vomcmc_scaling_prm(ielem,1) * &
+!!$                  SUM((2.0_bp*ran_arr(2:6) - 1.0_bp)*principal_axes(j,COUNT(mask(:ielem)),1:5))
+!!$             elements(ielem) = elements_running_mean(k,ielem) + variation 
+!!$             !WRITE(80,*) itrial, j, ielem, this%vomcmc_scaling_prm(1,1), ran_arr(2:6), COUNT(mask(:ielem)), &
+!!$             !     elements(ielem), elements_running_mean(k,ielem), variation
+!!$          END IF
+!!$       END DO
+
+       IF (first) THEN
+          elements = elements_arr(1,:)
+          first = .FALSE.
+       ELSE
+          i = CEILING(ran_arr(2)*SIZE(elements_arr,dim=1))
+          j = CEILING(ran_arr(3)*SIZE(elements_arr,dim=1))
+          IF (i == j) THEN
+             CYCLE
+          END IF
+          elements = getElements(orb_accepted(iorb), this%element_type_prm, frame)
+          elements = elements + (elements_arr(i,:)-elements_arr(j,:))
+       END IF
+
+       CALL NULLIFY(orb)
+       CALL NEW(orb, elements, this%element_type_prm, frame, t0)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "TRACE BACK (315)", 1)
+          RETURN
+       END IF
+       CALL setParameters(orb, &
+            perturbers=this%perturbers_prm, &
+            dyn_model=this%dyn_model_prm, &
+            integration_step=this%integration_step_prm, &
+            integrator=this%integrator_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "TRACE BACK (325)", 1)
+          RETURN
+       END IF
+
+       !!
+       !! 5) ACCEPTANCE / REJECTION OF GENERATED ORBIT
+       !!
+
+       ! Compute "reduced" chi2:
+       rchi2_arr(iorb+1) = getChi2(this, orb) - COUNT(obs_masks_)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "TRACE BACK (330)", 1)
+          RETURN
+       END IF
+
+       ! Probability density function value:
+       pdf_arr(iorb+1) = EXP(-0.5_bp*(rchi2_arr(iorb+1)))
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,1X,2"//TRIM(frmt)//")") "Sample chi2:", rchi2_arr(iorb+1)
+          WRITE(stdout,"(2X,A,1X,1"//TRIM(efrmt)//")") "Sample pdf:", pdf_arr(iorb+1)
+          WRITE(stdout,*)
+       END IF
+
+       ! Compute the pdv ratio between the previous accepted orbit and
+       ! the current trial orbit and use the MH criterion to decide
+       ! whether the trial orbit should be accepted or rejected
+       a_r = pdf_arr(iorb+1)/pdf_arr(iorb)
+       accept = .FALSE.
+       IF (ran_arr(1) < a_r) THEN
+          accept = .TRUE.
+       END IF
+
+       IF (info_verb >= 1) THEN
+          elements = getElements(orb, this%element_type_prm)
+          IF (this%element_type_prm == "cometary") THEN
+             elements(3:5) = elements(3:5)/rad_deg
+          END IF
+          IF (accept) THEN
+             WRITE(79,"(A,1X,10(F15.8,1X),A,1X,I0)") "CAR", &
+                  elements, pdf_arr(iorb+1), rchi2_arr(iorb+1), a_r, &
+                  ran, "ACCEPTED", iorb + 1
+          ELSE
+             WRITE(79,"(A,1X,10(F15.8,1X),A,1X,I0)") "CAR", &
+                  elements, pdf_arr(iorb+1), rchi2_arr(iorb+1), a_r, ran, &
+                  "REJECTED", itrial - iorb
+          END IF
+       END IF
+
+       IF (accept) THEN
+          naccepted = naccepted + 1
+          iorb = iorb + 1
+          orb_accepted(iorb) = copy(orb)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+                  "TRACE BACK (355)", 1)
+             RETURN
+          END IF
+       END IF
+       IF (iorb /= 0) THEN
+          this%repetition_arr_cmp(iorb) = this%repetition_arr_cmp(iorb) + 1
+       END IF
+
+       IF (info_verb >= 2 .AND. MOD(itrial,5000) == 0) THEN
+          WRITE(stdout,"(2X,A,3(I0,1X))") "Nr of accepted orbits and trials: ", naccepted, itrial
+       END IF
+
+    END DO
+
+    this%vomcmc_ntrial_cmp = itrial
+    this%vomcmc_norb_cmp = iorb
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "Final number of orbits and the required trials:"
+       WRITE(stdout,"(2X,2(I0,2X))") iorb, itrial
+    END IF
+
+    this%repetition_arr_cmp => reallocate(this%repetition_arr_cmp, iorb)
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "Could not deallocate memory (20).", 1)
+          RETURN       
+       END IF
+    END IF
+    ALLOCATE(this%orb_arr_cmp(iorb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "Could not allocate memory (15).", 1)
+       RETURN       
+    END IF
+    IF (iorb == 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+            "No sample orbit found.", 1)
+       RETURN
+    END IF
+    DO i=1,iorb
+       this%orb_arr_cmp(i) = copy(orb_accepted(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / virtualObservationMCMC", &
+               "TRACE BACK (365)", 1)
+          RETURN
+       END IF
+    END DO
+    CALL NULLIFY(this%orb_ml_cmp)
+    i = MAXLOC(pdf_arr(1:iorb),dim=1)
+    this%orb_ml_cmp = copy(orb_accepted(i))
+    IF (ASSOCIATED(this%pdf_arr_cmp)) THEN
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%pdf_arr_cmp(iorb), stat=err)
+    this%pdf_arr_cmp = pdf_arr(1:iorb)
+    IF (ASSOCIATED(this%rchi2_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+    END IF
+    ALLOCATE(this%rchi2_arr_cmp(iorb), stat=err)
+    this%rchi2_arr_cmp = rchi2_arr(1:iorb)
+    this%chi2_min_cmp = MINVAL(this%rchi2_arr_cmp) + COUNT(obs_masks_)
+!!$    IF (ASSOCIATED(this%vomcmc_map_cmp)) THEN
+!!$       DEALLOCATE(this%vomcmc_map_cmp, stat=err)
+!!$    END IF
+!!$    ALLOCATE(this%vomcmc_map_cmp(this%vomcmc_nmap_prm,12), stat=err)
+!!$    DO i=1,this%vomcmc_nmap_prm
+!!$       this%vomcmc_map_cmp(i,1:6) = elements_mean(i,1:6)
+!!$       DO j=1,6
+!!$          IF (j == indx) THEN
+!!$             this%vomcmc_map_cmp(i,6+j) = (mapping_end - mapping_start) / &
+!!$                  (2.0_bp*this%vomcmc_scaling_prm(j,1))
+!!$          ELSE
+!!$             this%vomcmc_map_cmp(i,6+j) = SUM(ABS(principal_axes(i,COUNT(mask(:j)),:)))
+!!$          END IF
+!!$       END DO
+!!$    END DO
+!!$    this%vomcmc_scaling_cmp = this%vomcmc_scaling_prm
+
+    DEALLOCATE(elements_arr, stat=err)
+    DO i=1,SIZE(orb_arr)
+       CALL NULLIFY(orb_arr(i))
+    END DO
+    DEALLOCATE(orb_arr)
+    DO i=1,SIZE(orb_accepted)
+       CALL NULLIFY(orb_accepted(i))
+    END DO
+    DEALLOCATE(orb_accepted, stat=err)
+!!$    DEALLOCATE(elements_running_mean, stat=err)
+!!$    DEALLOCATE(principal_axes, stat=err)
+    DEALLOCATE(pdf_arr, stat=err)
+    DEALLOCATE(rchi2_arr, stat=err)
+
+  END SUBROUTINE virtualObservationMCMC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computation of the least-squares orbital elements (Cartesian or
+  !! Keplerian) and their covariances in the two-body and full
+  !! many-body approaches.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE leastSquares_SO(this, preliminary_orbit)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Orbit), INTENT(in)              :: preliminary_orbit    
+
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: obs_scoords, ephemerides
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (Time) :: t, t_
+    TYPE (Orbit) :: orb
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), POINTER :: obsy_codes
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type, element_type_ls
+    CHARACTER(len=FRAME_LEN) :: frame
+    CHARACTER(len=DYN_MODEL_LEN) :: dyn_model, dyn_model_
+    CHARACTER(len=INTEGRATOR_LEN) :: orb_integrator
+    CHARACTER(len=32) :: str
+    REAL(bp), DIMENSION(:,:,:), POINTER :: partials_arr, &
+         cov_mat_obs, inform_mat_obs_bd
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE :: design_mat ! (data,obs,parameter)
+    REAL(bp), DIMENSION(:,:), POINTER :: stdev_arr_obs, &
+         elements_iter_arr, rmss_iter_arr, orb_additional_perturbers
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: observed, & ! incl. cos(dec)
+         computed, & ! incl. cos(dec)
+         residuals
+    REAL(bp), DIMENSION(6,6) :: cov
+    REAL(bp), DIMENSION(6) :: elements, elements_pre, &
+         elem_diff, stdev, stdev_max, rms_pre, orb_finite_diff
+    REAL(bp) :: sigma_multiplier_rms, &
+         correction_factor, orb_integration_step, obs_, comp_
+    INTEGER, DIMENSION(6) :: nobs_arr
+    INTEGER, DIMENSION(3) :: approach_direction
+    INTEGER :: i, j, k, err, iiter, approach, &
+         final_iterations, nobs, err_verb_
+    LOGICAL, DIMENSION(:,:), ALLOCATABLE :: obs_masks_
+    LOGICAL, DIMENSION(6) :: element_mask
+    LOGICAL :: elements_converge, rmss_converge, elements_exist
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "LEAST SQUARES"
+    END IF
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(preliminary_orbit)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "Preliminary orbit has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%accept_multiplier_prm < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "Acceptance criterion has not been defined.", 1)
+       RETURN
+    END IF
+
+    IF (this%outlier_rejection_prm) THEN
+       IF (this%outlier_multiplier_prm < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / leastSquares", &
+               "Outlier criterion has not been defined.", 1)
+          RETURN
+       END IF
+    END IF
+    sigma_multiplier_rms = this%accept_multiplier_prm
+    stdev_max = 0.0_bp
+    ! Number of previous iteration rounds to consider
+    iiter = 3
+
+    IF (.NOT.ASSOCIATED(this%obs_masks_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "Observation mask is missing.", 1)
+       RETURN
+    END IF
+
+    IF (this%ls_niter_minor_prm <= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "ls_niter_minor_prm undefined.", 1)
+       RETURN       
+    END IF
+
+    IF (this%ls_niter_major_min_prm <= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "ls_niter_major_min_prm undefined.", 1)
+       RETURN       
+    END IF
+
+    IF (this%ls_niter_major_max_prm <= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "ls_niter_major_max_prm undefined.", 1)
+       RETURN       
+    END IF
+
+    ! Allocate memory:
+    nobs = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    ALLOCATE(observed(nobs,6), computed(nobs,6), residuals(nobs,6), &
+         design_mat(6,nobs,6), elements_iter_arr(iiter,8), &
+         rmss_iter_arr(iiter,6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    orb = copy(preliminary_orbit)
+
+    ! Inversion epoch is equal to epoch of initial orbit:
+    t = getTime(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+
+    ! Find parameters of the peliminary orbit:
+    CALL getParameters(orb, dyn_model=dyn_model)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    IF (dyn_model /= this%dyn_model_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Inconsistent propagation schemes: " // &
+            "orb=" // TRIM(dyn_model) // " and storb=" // &
+            TRIM(this%dyn_model_prm) // ".", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    dyn_model_ = dyn_model
+
+    ! Initialize elements:
+    frame = getFrame(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (15)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    element_type = this%element_type_prm
+    CALL locase(element_type, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "The element type string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    SELECT CASE (TRIM(element_type))
+    CASE ("cartesian")
+       CALL toCartesian(orb, frame=frame)
+    CASE ("keplerian")
+       CALL toKeplerian(orb)
+    CASE default
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / leastSquares", &
+            "Can not use elements of type: " // TRIM(element_type), 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END SELECT
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (25)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    elements_pre(1:6) = getElements(orb, element_type)
+    DO i=1,iiter
+       elements_iter_arr(i,1:6) = elements_pre(1:6)
+    END DO
+    element_type_ls = element_type
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (27)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(1X,3(1X,A,1X,A))") "Using", TRIM(element_type), &
+            "elements."
+    END IF
+
+    ! Observations and observers:
+    obs_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (30)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    ALLOCATE(obs_masks_(SIZE(this%obs_masks_prm,dim=1),SIZE(this%obs_masks_prm,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Could not allocate memory.", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(obs_masks_, stat=err)
+       RETURN
+    END IF
+    obs_masks_ = this%obs_masks_prm
+    DO i=1,6
+       nobs_arr(i) = COUNT(obs_masks_(:,i))
+    END DO
+    obsy_codes => getObservatoryCodes(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (45)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+    obsy_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (45)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+    DO i=1,nobs
+       observed(i,:) = getCoordinates(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "TRACE BACK (50)", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+    END DO
+    observed(:,2) = observed(:,2)*COS(observed(:,3))
+    DEALLOCATE(obs_scoords, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Could not deallocate memory (5).", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+
+    ! Covariance matrix for observations:
+    stdev_arr_obs => getStandardDeviations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (51)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+    stdev_max(2) = MAXVAL(stdev_arr_obs(:,2))
+    stdev_max(3) = MAXVAL(stdev_arr_obs(:,3))
+
+    inform_mat_obs_bd => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (53)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(inform_mat_obs_bd, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+
+    ! Compute positions and partial derivatives:
+    CALL getEphemerides(orb, obsy_ccoords, ephemerides, &
+         partials_arr=partials_arr)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (55)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(inform_mat_obs_bd, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+    CALL propagate(orb, t)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "TRACE BACK (56)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(inform_mat_obs_bd, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+
+    ! Write design matrix and add cosine term to it and the computed positions:
+    design_mat = 0.0_bp
+    DO j=1,nobs
+       computed(j,:) = getCoordinates(ephemerides(j))
+       computed(j,2) = computed(j,2)*COS(observed(j,3))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "TRACE BACK (60)", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(inform_mat_obs_bd, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+       design_mat(2,j,:) = partials_arr(2,:,j)*COS(observed(j,3))
+       design_mat(3,j,:) = partials_arr(3,:,j)
+    END DO
+    DEALLOCATE(ephemerides, partials_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Could not deallocate memory (10).", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(ephemerides, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       DEALLOCATE(cov_mat_obs, stat=err)
+       DEALLOCATE(design_mat, stat=err) 
+       DEALLOCATE(stdev_arr_obs, stat=err) 
+       DEALLOCATE(elements_iter_arr, stat=err)
+       DEALLOCATE(rmss_iter_arr, stat=err) 
+       DEALLOCATE(inform_mat_obs_bd, stat=err) 
+       DEALLOCATE(observed, stat=err)
+       DEALLOCATE(computed, stat=err) 
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(obs_masks_, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       RETURN
+    END IF
+
+
+    ! Output orbital elements and sky-plane residuals and rms if needed:
+    IF (info_verb >= 2) THEN
+       t_ = getTime(orb)
+       WRITE(stdout,"(2X,A,I0,A)") "Initial elements, residuals, and rms:"
+       str = getCalendarDateString(t_, "TT")
+       SELECT CASE (element_type)
+       CASE ("keplerian")
+          elements = getElements(orb, element_type)
+          WRITE(stdout,"(2X,A,6(1X,F20.13),1X,A)") "Kep: ", &
+               elements(1:2), elements(3:6)/rad_deg, &
+               TRIM(str)
+       CASE ("cartesian")
+          elements = getElements(orb, element_type, frame=frame)
+          WRITE(stdout,'(2X,A,6(1X,F20.13),1X,A)') "Car: ", &
+               elements(1:6),TRIM(str)
+       END SELECT
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "TRACE BACK (65)", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(inform_mat_obs_bd, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+       CALL NULLIFY(t_)
+       WRITE(stdout,"(2X,A)") "Residuals RA & Dec [as]:"
+    END IF
+    DO j=1,nobs
+       residuals(j,1:6) = observed(j,1:6) - computed(j,1:6)
+       IF (ABS(residuals(j,2)) > pi) THEN
+          obs_ = observed(j,2)
+          comp_ = computed(j,2)
+          IF (obs_ < comp_) THEN
+             obs_ = obs_ + two_pi
+          ELSE
+             comp_ = comp_ + two_pi
+          END IF
+          residuals(j,2) = obs_ - comp_
+       END IF
+       IF (info_verb >= 2) THEN
+          IF (ALL(obs_masks_(j,2:3))) THEN
+             WRITE(stdout,"(2X,A,2(F20.7,1X),A,1X,A)") " ", &
+                  residuals(j,2:3)/rad_asec, " ", TRIM(obsy_codes(j))
+          ELSE
+             WRITE(stdout,"(2X,A,2(F15.7,1X),A,1X,A)") "(", &
+                  residuals(j,2:3)/rad_asec, ")", TRIM(obsy_codes(j))
+          END IF
+       END IF
+    END DO
+    rmss_iter_arr = 0.0_bp
+    rms_pre = 0.0_bp
+    rms_pre(2) = SQRT(SUM(residuals(:,2)**2.0_bp,mask=obs_masks_(:,2))/nobs_arr(2))
+    rms_pre(3) = SQRT(SUM(residuals(:,3)**2.0_bp,mask=obs_masks_(:,3))/nobs_arr(3))
+    DO i=1,iiter
+       rmss_iter_arr(i,:) = rms_pre
+    END DO
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,2(1X,F15.7))") "RA & Dec RMS [as]: ", &
+            rmss_iter_arr(iiter,2)/rad_asec, rmss_iter_arr(iiter,3)/rad_asec
+       WRITE(stdout,"(2X,A)") ""
+    END IF
+
+    final_iterations = 0
+    approach = 11
+    approach_direction(1:3) = 1
+    correction_factor = this%ls_corr_fac_prm
+    element_mask(1:6) = this%ls_elem_mask_prm
+
+    ! Main LSL loop
+    ls_i: DO i=1,this%ls_niter_major_max_prm
+
+       ! Perform linear least-squares fit:
+       elements_converge = .FALSE.
+!!$       rmss_converge = .FALSE.
+       rmss_converge = .TRUE.
+       ! "Correction factor" loop
+       ls_j: DO j=1,this%ls_niter_minor_prm
+
+          ! Save results from last two rounds for convergence checks
+          elements_iter_arr(1:iiter-1,1:6) = elements_iter_arr(2:iiter,1:6)
+          rmss_iter_arr(1:iiter-1,1:6) = rmss_iter_arr(2:iiter,1:6)
+          rmss_iter_arr(iiter,1:6) = 0.0_bp
+
+          ! Perform least squares fit:
+          CALL leastSquares(observed(1:nobs,1:6), &
+               inform_mat_obs_bd(1:nobs,1:6,1:6), &
+               obs_masks_(1:nobs,1:6), &
+               computed(1:nobs,1:6), &
+               design_mat(1:6,1:nobs,1:6), &
+               correction_factor, &
+               element_mask(1:6), &
+               cov(1:6,1:6), &
+               elements_iter_arr(iiter,1:6), &
+               errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "Could not find a linear least-squares solution. " // &
+                  TRIM(errstr), 1)
+             errstr = ""
+             elements_converge = .FALSE.
+             elements_iter_arr(iiter,1:6) = elements_iter_arr(iiter-1,1:6)
+             EXIT ls_j
+          END IF
+
+          ! Update orbit:
+          CALL getParameters(orb, &
+               integration_step=orb_integration_step, &
+               integrator=orb_integrator, &
+               finite_diff=orb_finite_diff, &
+               additional_perturbers=orb_additional_perturbers)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "TRACE BACK (69)", 1)
+             RETURN
+          END IF
+          CALL NULLIFY(orb)
+          err_verb_ = err_verb
+          err_verb = err_verb! + 1
+          IF (element_type_ls == "keplerian") THEN
+             elements_iter_arr(iiter,4:6) = &
+                  MODULO(elements_iter_arr(iiter,4:6), two_pi)
+          ELSE IF (element_type_ls == "cometary") THEN
+             elements_iter_arr(iiter,4:5) = &
+                  MODULO(elements_iter_arr(iiter,4:5), two_pi)
+          ELSE IF (element_type_ls == "cartesian" .AND. &
+               SQRT(DOT_PRODUCT(elements_iter_arr(iiter,4:6), &
+               elements_iter_arr(iiter,4:6))) > sol) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "Speed of object is larger than speed of light.", 1)
+             elements_converge = .FALSE.
+             elements_iter_arr(iiter,1:6) = elements_iter_arr(iiter-1,1:6)
+             EXIT ls_j
+          END IF
+          CALL NEW(orb, elements_iter_arr(iiter,1:6), &
+               TRIM(element_type_ls), TRIM(frame), copy(t))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "TRACE BACK (70)", 1)
+             error = .FALSE.
+             elements_converge = .FALSE.
+             rmss_converge = .FALSE.
+             elements_exist = .FALSE.
+             elements_iter_arr(iiter,1:6) = elements_iter_arr(iiter-1,1:6)
+             err_verb = err_verb_
+             EXIT ls_j
+          END IF
+          elements_exist = .TRUE.
+          err_verb = err_verb_
+          CALL setParameters(orb, &
+               dyn_model=dyn_model_, &
+               perturbers=this%perturbers_prm, &
+               integration_step=orb_integration_step, &
+               integrator=orb_integrator, &
+               finite_diff=orb_finite_diff, &
+               additional_perturbers=orb_additional_perturbers)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "TRACE BACK (75)", 1)
+             DEALLOCATE(obs_scoords, stat=err) 
+             DEALLOCATE(ephemerides, stat=err) 
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             DEALLOCATE(design_mat, stat=err) 
+             DEALLOCATE(stdev_arr_obs, stat=err) 
+             DEALLOCATE(elements_iter_arr, stat=err)
+             DEALLOCATE(rmss_iter_arr, stat=err) 
+             DEALLOCATE(inform_mat_obs_bd, stat=err) 
+             DEALLOCATE(observed, stat=err)
+             DEALLOCATE(computed, stat=err) 
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(obs_masks_, stat=err)
+             DEALLOCATE(obsy_codes, stat=err)
+             RETURN
+          END IF
+
+          ! Compute positions and partial derivatives:
+          CALL getEphemerides(orb, obsy_ccoords, ephemerides, &
+               partials_arr=partials_arr)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "TRACE BACK (80)", 1)
+             error = .FALSE.
+             elements_converge = .FALSE.
+             elements_iter_arr(iiter,1:6) = elements_iter_arr(iiter-1,1:6)
+             DEALLOCATE(ephemerides, partials_arr, stat=err)
+             EXIT ls_j
+          END IF
+          CALL propagate(orb, t)
+
+          ! Write design matrix and add cosine term to it and the computed positions:
+          design_mat = 0.0_bp
+          DO k=1,nobs
+             computed(k,:) = getCoordinates(ephemerides(k))
+             computed(k,2) = computed(k,2)*COS(observed(k,3))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / " // &
+                     "leastSquares", &
+                     "TRACE BACK (85)", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+             design_mat(2,k,:) = partials_arr(2,:,k)*COS(observed(k,3))
+             design_mat(3,k,:) = partials_arr(3,:,k)
+          END DO
+          DEALLOCATE(ephemerides, partials_arr, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / " // &
+                  "leastSquares", &
+                  "Could not deallocate memory (15).", 1)
+             DEALLOCATE(obs_scoords, stat=err) 
+             DEALLOCATE(ephemerides, stat=err) 
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             DEALLOCATE(cov_mat_obs, stat=err)
+             DEALLOCATE(design_mat, stat=err) 
+             DEALLOCATE(stdev_arr_obs, stat=err) 
+             DEALLOCATE(elements_iter_arr, stat=err)
+             DEALLOCATE(rmss_iter_arr, stat=err) 
+             DEALLOCATE(inform_mat_obs_bd, stat=err) 
+             DEALLOCATE(observed, stat=err)
+             DEALLOCATE(computed, stat=err) 
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(obs_masks_, stat=err)
+             DEALLOCATE(obsy_codes, stat=err)
+             RETURN
+          END IF
+
+          ! Output orbital elements if needed:
+          IF (info_verb >= 3) THEN
+             t_ = getTime(orb)
+             WRITE(stdout,"(1X,A,2(1X,I0,1X,A))") &
+                  "Elements, residuals, and rms after major iteration", i, &
+                  "and minor iteration", j, ":"
+             SELECT CASE (element_type)
+             CASE ("keplerian")
+                elements = getElements(orb, element_type)
+                WRITE(stdout,"(2X,A,6(1X,F20.13),1X,A)") "Kep: ", &
+                     elements(1:2), elements(3:6)/rad_deg, &
+                     getCalendarDateString(t_, "tdt")
+             CASE ("cartesian")
+                elements = getElements(orb, element_type, frame=frame)
+                WRITE(stdout,"(2X,A,6(1X,F20.13),1X,A)") "Car: ", &
+                     elements(1:6), &
+                     getCalendarDateString(t_, "tdt")
+             END SELECT
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / " // &
+                     "leastSquares", &
+                     "TRACE BACK (90)", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+             CALL NULLIFY(t_)
+          END IF
+          IF (info_verb >= 4) THEN 
+             WRITE(stdout,"(2X,A)") "Covariance matrix:"
+             CALL matrix_print(cov, stdout, errstr)
+             errstr = ""
+             WRITE(stdout,"(2X,A)") "Residuals RA & Dec [as]:"
+          END IF
+
+          ! Compute sky-plane residuals and rmss, and output them if needed:
+          DO k=1,nobs
+             residuals(k,1:6) = observed(k,1:6) - computed(k,1:6)
+             IF (ABS(residuals(k,2)) > pi) THEN
+                obs_ = observed(k,2)
+                comp_ = computed(k,2)
+                IF (obs_ < comp_) THEN
+                   obs_ = obs_ + two_pi
+                ELSE
+                   comp_ = comp_ + two_pi
+                END IF
+                residuals(k,2) = obs_ - comp_
+             END IF
+             IF (info_verb >= 4) THEN
+                WRITE(stdout,"(2X,2(F15.7,1X),A)") residuals(k,2:3)/rad_asec, TRIM(obsy_codes(k))
+             END IF
+          END DO
+          rmss_iter_arr(iiter,2) = SQRT(SUM(residuals(:,2)**2.0_bp,mask=obs_masks_(:,2))/nobs_arr(2))
+          rmss_iter_arr(iiter,3) = SQRT(SUM(residuals(:,3)**2.0_bp,mask=obs_masks_(:,3))/nobs_arr(3))
+          IF (info_verb >= 3) THEN
+             WRITE(stdout,"(2X,A,2(1X,F15.7))") "RA & Dec RMS [as]: ", &
+                  rmss_iter_arr(iiter,2)/rad_asec, rmss_iter_arr(iiter,3)/rad_asec
+          END IF
+
+          ! Exit iteration loop if the difference between the elements of
+          ! the new and the old orbit are sufficiently small:
+          DO k=1,SIZE(cov,dim=1)
+             IF (cov(k,k) < 0.0_bp) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / " // &
+                     "leastSquares", &
+                     "Negative diagonal in covariance matrix:", 1)
+                IF (err_verb >= 1) THEN
+                   CALL matrix_print(cov,stderr,errstr)
+                   errstr = ""
+                   WRITE(stderr,*) "Orbital elements:"
+                   WRITE(stderr,*) elements_iter_arr(iiter,1:6)                  
+                END IF
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+             stdev(k) = SQRT(cov(k,k))
+          END DO
+          elem_diff = ABS(elements_iter_arr(iiter,1:6) - &
+               elements_iter_arr(iiter-1,1:6)) / correction_factor
+          IF (ALL(elem_diff < stdev) .AND. j >= 3) THEN
+             elements_converge = .TRUE.
+          END IF
+
+          IF (elements_converge .AND. approach == 11 .AND. &
+               ((ALL(rmss_iter_arr(iiter,2:3) < &
+               sigma_multiplier_rms*stdev_max(2:3))) .OR. &
+               (j > 1 .AND. ALL(ABS(rmss_iter_arr(iiter,2:3) - &
+               rmss_iter_arr(iiter-1,2:3)) < &
+               1000.0_bp*EPSILON(rmss_iter_arr(iiter,2:3)))))) THEN
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(1X,A,I0)") "Exiting @", j
+             END IF
+             EXIT ls_j
+          ELSE IF (elements_converge .AND. approach /= 11) THEN
+             IF (info_verb >= 3) THEN
+                WRITE(stdout,"(1X,A,I0)") "Exiting @", j
+             END IF
+             EXIT ls_j
+          END IF
+
+       END DO ls_j
+
+!!$       IF (iiter >= 3) THEN
+!!$          IF (elements_exist .AND. &
+!!$               ((SQRT(SUM((rmss_iter_arr(iiter-2,:) - rmss_iter_arr(iiter-1,:))**2.0_bp)) >= &
+!!$               SQRT(SUM((rmss_iter_arr(iiter-1,:) - rmss_iter_arr(iiter,:))**2.0_bp)) .OR. &
+!!$               SQRT(SUM((rmss_iter_arr(iiter-1,:) - rmss_iter_arr(iiter,:))**2.0_bp)) < &
+!!$               0.000001_bp*SQRT(SUM((rmss_iter_arr(iiter,:))**2.0_bp))) )) THEN
+!!$             rmss_converge = .TRUE.
+!!$          ELSE
+!!$             rmss_converge = .FALSE.                
+!!$          END IF
+!!$       END IF
+
+       IF (elements_converge .AND. rmss_converge .AND. &
+            final_iterations == this%ls_niter_major_min_prm) THEN
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,*) "LS solution found (1)."
+          END IF
+          IF (this%outlier_rejection_prm) THEN
+             DO k=1,6
+                nobs_arr(k) = COUNT(obs_masks_(:,k))
+             END DO
+             IF (ANY(nobs_arr(2:3) < 0.2_bp*nobs)) THEN
+                IF (info_verb >= 2) THEN
+                   WRITE(*,*) "WARNING from LS: More than 20% of the observations excluded!", &
+                        " Check the assumptions used for outlier rejection (e.g., noise)."
+                END IF
+             END IF
+             IF (ALL(nobs_arr < 4)) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / leastSquares", &
+                     "Least squares approach not suitable when " // &
+                     "possible outliers have been excluded.", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+             IF (ANY(rmss_iter_arr(iiter,2:3) > sigma_multiplier_rms*stdev_max(2:3))) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / leastSquares", &
+                     "Least squares solution not reliable when " // &
+                     "rms values are so large as compared to assumed " // &
+                     "observational uncertainty. (Check noise assumption!)", 1)
+                RETURN
+             END IF
+          END IF
+          EXIT ls_i
+       ELSE IF (elements_converge .AND. rmss_converge .AND. approach == 11) THEN
+          final_iterations = final_iterations + 1
+          IF (this%outlier_rejection_prm .AND. &
+               ALL(rmss_iter_arr(iiter,2:3) <= sigma_multiplier_rms*stdev_max(2:3))) THEN
+             obs_masks_ = this%obs_masks_prm
+             DO k=1,nobs
+                ! The following assumes that the stdevs are equal for
+                ! both coordinates:
+                IF (SQRT(SUM(residuals(k,2:3)**2)) > &
+                     this%outlier_multiplier_prm*MAXVAL(stdev_arr_obs(k,2:3))) THEN
+                   obs_masks_(k,:) = .FALSE.
+                END IF
+             END DO
+             DO k=1,6
+                nobs_arr(k) = COUNT(obs_masks_(:,k))
+             END DO
+             IF (ANY(nobs_arr(2:3) < 0.2*nobs)) THEN
+                IF (info_verb >= 2) THEN
+                   WRITE(stdout,*) "More than 20% of the observations excluded! Keeping all."
+                END IF
+                obs_masks_ = this%obs_masks_prm
+                DO k=1,6
+                   nobs_arr(k) = COUNT(obs_masks_(:,k))
+                END DO
+             END IF
+             IF (ALL(nobs_arr < 4)) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / leastSquares", &
+                     "Least squares approach not suitable when " // &
+                     "possible outliers have been excluded.", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+          END IF
+       ELSE IF (elements_converge .AND. rmss_converge .AND. approach /= 11) THEN
+          final_iterations = 0
+          approach_direction(1:2) = approach_direction(2:3)
+          approach_direction(3) = -1
+          approach = approach - 1
+          IF (approach == 40) THEN
+             approach = 12
+          END IF
+       ELSE IF (elements_converge .AND. .NOT.rmss_converge) THEN
+          final_iterations = 0
+          approach_direction(1:2) = approach_direction(2:3)
+          approach_direction(3) = 1
+          IF (approach < 21) THEN
+             approach = 21
+          ELSE
+             approach = approach + 1
+          END IF
+       ELSE IF (.NOT.elements_converge .AND. rmss_converge) THEN
+          final_iterations = 0
+          approach_direction(1:2) = approach_direction(2:3)
+          approach_direction(3) = 1
+          approach = approach + 1
+       ELSE IF (.NOT.elements_converge .AND. .NOT.rmss_converge) THEN
+          final_iterations = 0
+          CALL NULLIFY(orb)
+          orb = copy(preliminary_orbit)
+          DO k=1,iiter
+             elements_iter_arr(k,1:6) = elements_pre(1:6)
+          END DO
+          DO k=1,iiter
+             rmss_iter_arr(k,1:6) = rms_pre(1:6)
+          END DO
+          IF (approach >= 41) THEN
+             approach_direction(1:2) = approach_direction(2:3)
+             approach_direction(3) = 1
+             approach = approach + 1
+          ELSE IF (approach == 11) THEN
+             approach = 12
+          ELSE IF (approach < 41) THEN
+             approach = 41
+          END IF
+       END IF
+       !IF (approach > 48) THEN
+       IF (approach >= 43) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / leastSquares", &
+               "No converging solution found (5).", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(inform_mat_obs_bd, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+       IF (approach_direction(3) < 0 .AND. &
+            i > 25 .AND. approach < 44) THEN
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,*) "LS solution found (2)."
+          END IF
+          EXIT ls_i
+       END IF
+
+       DO
+          SELECT CASE (approach)
+          CASE (11)
+             dyn_model_ = dyn_model
+             correction_factor = this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (12)
+             dyn_model_ = dyn_model
+             correction_factor = this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (21)
+             dyn_model_ = dyn_model
+             correction_factor = this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (41)
+             dyn_model_ = dyn_model
+             correction_factor = 0.1_bp*this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (42)
+             dyn_model_ = dyn_model
+             correction_factor = 0.01_bp*this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (43)
+             dyn_model_ = dyn_model
+             correction_factor = 0.001_bp*this%ls_corr_fac_prm
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (44)
+             dyn_model_ = dyn_model
+             correction_factor = 0.0001_bp*this%ls_corr_fac_prm
+             IF (element_type_ls /= element_type) THEN
+                element_type_ls = element_type
+                IF (element_type_ls == "keplerian") THEN
+                   CALL toKeplerian(orb)
+                ELSE IF (element_type_ls == "cartesian") THEN
+                   CALL toCartesian(orb, frame=frame)
+                END IF
+                elements_iter_arr(iiter,1:6) = getElements(orb, element_type_ls, frame=frame)
+             END IF
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / " // &
+                     "leastSquares", &
+                     "TRACE BACK (105)", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                RETURN
+             END IF
+             element_mask(1:6) = this%ls_elem_mask_prm
+             EXIT
+          CASE (45)
+             dyn_model_ = dyn_model
+             correction_factor = 0.001_bp*this%ls_corr_fac_prm
+             IF (element_type_ls == "keplerian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1) = .FALSE.
+             ELSE IF (element_type_ls == "cartesian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1) = .FALSE.
+             END IF
+             EXIT
+          CASE (46)
+             dyn_model_ = dyn_model
+             correction_factor = 0.001_bp*this%ls_corr_fac_prm
+             IF (element_type_ls == "keplerian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(2) = .FALSE.
+             ELSE IF (element_type_ls == "cartesian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1) = .FALSE.
+                element_mask(4) = .FALSE.
+             END IF
+             EXIT
+          CASE (47)
+             dyn_model_ = dyn_model
+             correction_factor = 0.001_bp*this%ls_corr_fac_prm
+             IF (element_type_ls == "keplerian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1:2) = .FALSE.
+             ELSE IF (element_type_ls == "cartesian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1) = .FALSE.
+                element_mask(4:5) = .FALSE.
+             END IF
+             EXIT
+          CASE (48)
+             dyn_model_ = dyn_model
+             correction_factor = 0.0001_bp*this%ls_corr_fac_prm
+             IF (element_type_ls == "keplerian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1:2) = .FALSE.
+             ELSE IF (element_type_ls == "cartesian") THEN
+                element_mask(1:6) = .TRUE.
+                element_mask(1) = .FALSE.
+                element_mask(4:5) = .FALSE.
+             END IF
+             EXIT
+          CASE default
+             IF (approach > 48) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / leastSquares", &
+                     "No converging solution found (10).", 1)
+                DEALLOCATE(obs_scoords, stat=err) 
+                DEALLOCATE(ephemerides, stat=err) 
+                DEALLOCATE(obsy_ccoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                DEALLOCATE(cov_mat_obs, stat=err)
+                DEALLOCATE(design_mat, stat=err) 
+                DEALLOCATE(stdev_arr_obs, stat=err) 
+                DEALLOCATE(elements_iter_arr, stat=err)
+                DEALLOCATE(rmss_iter_arr, stat=err) 
+                DEALLOCATE(inform_mat_obs_bd, stat=err) 
+                DEALLOCATE(observed, stat=err)
+                DEALLOCATE(computed, stat=err) 
+                DEALLOCATE(residuals, stat=err) 
+                DEALLOCATE(obs_masks_, stat=err)
+                DEALLOCATE(obsy_codes, stat=err)
+                WRITE(stderr,*) "Returning from leastSquares"
+                RETURN
+             ELSE
+                approach = approach + approach_direction(3)
+             END IF
+          END SELECT
+       END DO
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,L1)") "Elements converge: ", elements_converge
+          WRITE(stdout,"(2X,A,L1)") "RMSs converge: ", rmss_converge
+          WRITE(stdout,"(2X,A,I0)") "Approach to be used: ", approach
+          WRITE(stdout,"(2X,A,3(I0,1X))") "Approach directions: ", approach_direction
+          WRITE(stdout,"(2X,A,6(I0,1X))") "Observation included: ",nobs_arr 
+       END IF
+
+    END DO ls_i
+
+    ! Orbital elements and sky-plane residuals and rms":
+    IF (info_verb >= 2) THEN
+       t_ = getTime(orb)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "TRACE BACK (130)", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(inform_mat_obs_bd, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+       WRITE(stdout,"(2X,A)") "# Final results:"
+       err_verb_ = err_verb
+       err_verb = 0
+       elements = getElements(orb, "keplerian")
+       err_verb = err_verb_
+       IF (error) THEN
+          error = .FALSE.
+       ELSE
+          str = getCalendarDateString(t_, "TT")
+          WRITE(stdout,"(2X,A,2X,A,6(1X,F20.13),1X,A)") "#", "Kep: ", &
+               elements(1:2), elements(3:6)/rad_deg, &
+               TRIM(str)
+       END IF
+       elements = getElements(orb, "cartesian", frame="ecliptic")
+       IF (error) THEN
+          error = .FALSE.
+       ELSE
+          str = getCalendarDateString(t_, "TT")
+          WRITE(stdout,"(2X,A,2X,A,6(1X,F20.13),1X,A)") "#", "Car: ", &
+               elements(1:6), TRIM(str)
+       END IF
+       CALL NULLIFY(t_)
+       WRITE(stdout,"(2X,A,2X,A)") "#", "Residuals RA & Dec [as]:"
+       DO j=1,nobs
+          IF (ALL(obs_masks_(j,2:3))) THEN
+             WRITE(stdout,"(2X,A,2X,A,2(F15.7,1X),A,1X,A)") "#", " ", &
+                  residuals(j,2:3)/rad_asec, " ", TRIM(obsy_codes(j))
+          ELSE
+             WRITE(stdout,"(2X,A,2X,A,2(F15.7,1X),A,1X,A)") "#", "(", &
+                  residuals(j,2:3)/rad_asec, ")", TRIM(obsy_codes(j))
+          END IF
+       END DO
+       WRITE(stdout,"(2X,A,2X,A,2(1X,F15.7))") "#", "RA & Dec RMS [as]: ", &
+            rmss_iter_arr(iiter,2)/rad_asec, rmss_iter_arr(iiter,3)/rad_asec
+    END IF
+
+    CALL NULLIFY(this%orb_ml_cmp)
+    this%orb_ml_cmp = copy(orb)
+    IF (.NOT.ASSOCIATED(this%cov_ml_cmp)) THEN
+       ALLOCATE(this%cov_ml_cmp(6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(ephemerides, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          DEALLOCATE(cov_mat_obs, stat=err)
+          DEALLOCATE(design_mat, stat=err) 
+          DEALLOCATE(stdev_arr_obs, stat=err) 
+          DEALLOCATE(elements_iter_arr, stat=err)
+          DEALLOCATE(rmss_iter_arr, stat=err) 
+          DEALLOCATE(inform_mat_obs_bd, stat=err) 
+          DEALLOCATE(observed, stat=err)
+          DEALLOCATE(computed, stat=err) 
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(obs_masks_, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          RETURN
+       END IF
+    END IF
+    this%cov_ml_cmp = cov
+    this%cov_type_prm = element_type_ls
+    this%obs_masks_prm = obs_masks_
+
+    CALL NULLIFY(orb)
+    CALL NULLIFY(t)
+    CALL NULLIFY(t_)
+    DEALLOCATE(obs_scoords, stat=err) 
+    DEALLOCATE(ephemerides, stat=err) 
+    DEALLOCATE(obsy_ccoords, stat=err)
+    DEALLOCATE(partials_arr, stat=err)
+    DEALLOCATE(cov_mat_obs, stat=err)
+    DEALLOCATE(design_mat, stat=err) 
+    DEALLOCATE(stdev_arr_obs, stat=err) 
+    DEALLOCATE(elements_iter_arr, stat=err)
+    DEALLOCATE(rmss_iter_arr, stat=err) 
+    DEALLOCATE(inform_mat_obs_bd, stat=err) 
+    DEALLOCATE(observed, stat=err)
+    DEALLOCATE(computed, stat=err) 
+    DEALLOCATE(residuals, stat=err)
+    DEALLOCATE(obs_masks_, stat=err)
+    DEALLOCATE(obsy_codes, stat=err)
+
+    IF (final_iterations /= this%ls_niter_major_min_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "leastSquares", &
+            "Could not reach final iteration rounds.", 1)
+    END IF
+
+  END SUBROUTINE leastSquares_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computation of the least-squares orbital elements (Cartesian or
+  !! Keplerian) and their covariances in the two-body or full
+  !! many-body approaches using the Levenberg-Marquardt algorithm.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE levenbergMarquardt_SO(this, preliminary_orbit)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Orbit), INTENT(in)              :: preliminary_orbit    
+
+    INTEGER, PARAMETER :: niter_size = 3
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: obs_scoords
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (Time) :: t, t_
+    TYPE (Orbit) :: orb
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), POINTER :: obsy_codes
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: element_type_
+    CHARACTER(len=FRAME_LEN) :: frame_
+    CHARACTER(len=DYN_MODEL_LEN) :: dyn_model_
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator_
+    CHARACTER(len=32) :: str
+    REAL(bp), DIMENSION(:,:,:), POINTER :: information_matrix_measur
+    REAL(bp), DIMENSION(:,:), POINTER :: stdev_arr_measur
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE :: jacobians
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: measur, & ! incl. cos(dec)
+         residuals, &
+         alpha
+    REAL(bp), DIMENSION(6,6) :: cov_mat_param
+    REAL(bp), DIMENSION(niter_size,6) :: elements_iter_arr
+    REAL(bp), DIMENSION(6) :: params, finite_diff_
+    REAL(bp) :: rchi2, integration_step_, rchi2_previous, rchi2_old, lambda
+    INTEGER :: i, j, k, err, ndata, nparam, nmultidata
+    LOGICAL, DIMENSION(:,:), ALLOCATABLE :: mask_measur
+    LOGICAL, DIMENSION(6) :: mask_param
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "LEAST SQUARES"
+    END IF
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.exist(preliminary_orbit)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "Preliminary orbit has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%outlier_rejection_prm) THEN
+       IF (this%outlier_multiplier_prm < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+               "Outlier criterion has not been defined.", 1)
+          RETURN
+       END IF
+    END IF
+
+    IF (.NOT.ASSOCIATED(this%obs_masks_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "Observation mask is missing.", 1)
+       RETURN
+    END IF
+
+    IF (this%ls_niter_minor_prm <= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "ls_niter_minor_prm undefined.", 1)
+       RETURN       
+    END IF
+
+    IF (this%ls_niter_major_max_prm <= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "ls_niter_major_max_prm undefined.", 1)
+       RETURN       
+    END IF
+
+    ! Allocate memory:
+    ndata = SIZE(this%obs_masks_prm,dim=1)
+    nmultidata = SIZE(this%obs_masks_prm,dim=2)
+    nparam = 6
+    ALLOCATE(measur(ndata,nmultidata), residuals(ndata,nmultidata), &
+         alpha(nparam,nparam), jacobians(nmultidata,nparam,ndata), &
+         mask_measur(ndata,nmultidata), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Could not allocate memory (5).", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    orb = copy(preliminary_orbit)
+
+    ! Inversion epoch is equal to epoch of initial orbit:
+    t = getTime(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+
+    ! Find parameters of the peliminary orbit:
+    CALL getParameters(orb, dyn_model=dyn_model_)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    IF (dyn_model_ /= this%dyn_model_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Inconsistent propagation schemes: " // &
+            "orb=" // TRIM(dyn_model_) // " and storb=" // &
+            TRIM(this%dyn_model_prm) // ".", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    CALL getParameters(orb, &
+         integration_step=integration_step_, &
+         integrator=integrator_, &
+         finite_diff=finite_diff_)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (15)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+
+    ! Initialize elements:
+    frame_ = getFrame(orb)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (20)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    element_type_ = this%element_type_prm
+    CALL locase(element_type_, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "The element type string contains forbidden characters.", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    SELECT CASE (TRIM(element_type_))
+    CASE ("cartesian")
+       CALL toCartesian(orb, frame=frame_)
+    CASE ("keplerian")
+       CALL toKeplerian(orb)
+    CASE ("cometary")
+       CALL toCometary(orb)
+    CASE default
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / levenbergMarquardt", &
+            "Can not use elements of type: " // TRIM(element_type_), 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END SELECT
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (25)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    params(1:6) = getElements(orb, element_type_)
+    DO i=1,niter_size
+       elements_iter_arr(i,1:6) = params(1:6)
+    END DO
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (30)", 1)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(1X,3(1X,A,1X,A))") "Using", TRIM(element_type_), &
+            "elements."
+    END IF
+
+    ! Observations and observers:
+    obs_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (35)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    mask_measur = this%obs_masks_prm
+    obsy_codes => getObservatoryCodes(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (40)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    obsy_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (45)", 1)
+       DEALLOCATE(obs_scoords, stat=err) 
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    DO i=1,ndata
+       measur(i,:) = getCoordinates(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / " // &
+               "levenbergMarquardt", &
+               "TRACE BACK (50)", 1)
+          DEALLOCATE(obs_scoords, stat=err) 
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(obsy_codes, stat=err)
+          DEALLOCATE(measur, stat=err)
+          DEALLOCATE(residuals, stat=err) 
+          DEALLOCATE(mask_measur, stat=err)
+          DEALLOCATE(alpha, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          RETURN
+       END IF
+    END DO
+    measur(:,2) = measur(:,2)*COS(measur(:,3))
+    DEALLOCATE(obs_scoords, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Could not deallocate memory (5).", 1)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    information_matrix_measur => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (55)", 1)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(information_matrix_measur, stat=err) 
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    stdev_arr_measur => getStandardDeviations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (60)", 1)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(information_matrix_measur, stat=err) 
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(stdev_arr_measur, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+    mask_param = this%ls_elem_mask_prm
+
+    rchi2_old = HUGE(rchi2_old)
+    rchi2_previous = HUGE(rchi2_previous)
+    lambda = -1.0_bp
+    DO i=1,this%ls_niter_major_max_prm
+
+       DO j=1,this%ls_niter_minor_prm
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X,I0,A,I0,A)") j, "th minor and ", i, &
+                  "th major call to 'LevenbergMarquardt_private'" // &
+                  " from loop in 'levenbergMarquardt_SO'."
+          END IF
+          CALL LevenbergMarquardt_private
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / " // &
+                  "levenbergMarquardt", &
+                  "Could not find a least-squares solution (1).", 1)
+             DEALLOCATE(obsy_ccoords, stat=err)
+             DEALLOCATE(information_matrix_measur, stat=err) 
+             DEALLOCATE(obsy_codes, stat=err)
+             DEALLOCATE(stdev_arr_measur, stat=err)
+             DEALLOCATE(measur, stat=err)
+             DEALLOCATE(residuals, stat=err) 
+             DEALLOCATE(mask_measur, stat=err)
+             DEALLOCATE(alpha, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             RETURN
+          END IF
+          IF (ABS(rchi2 - rchi2_previous) < this%ls_rchi2_diff_tresh_prm .AND. &
+               rchi2 <= rchi2_previous) THEN
+             EXIT
+          END IF
+       END DO
+
+       ! Outlier rejection
+       IF (this%outlier_rejection_prm .AND. ABS(rchi2 - rchi2_old) > this%ls_rchi2_diff_tresh_prm) THEN
+          mask_measur = this%obs_masks_prm
+          DO k=1,ndata
+             IF (ANY(ABS(residuals(k,2:3)) > &
+                  this%outlier_multiplier_prm*stdev_arr_measur(k,2:3))) THEN
+                mask_measur(k,:) = .FALSE.
+             END IF
+          END DO
+          rchi2_old = rchi2
+       ELSE ! IF (.NOT.this%outlier_rejection_prm) THEN
+          EXIT
+       END IF
+
+    END DO
+
+    lambda = 0.0_bp
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "Final call to 'LevenbergMarquardt_private' from " // &
+            "'levenbergMarquardt_SO'."
+    END IF
+    CALL levenbergMarquardt_private
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Could not find a least-squares solution (2).", 1)
+       DEALLOCATE(obsy_ccoords, stat=err)
+       DEALLOCATE(information_matrix_measur, stat=err) 
+       DEALLOCATE(obsy_codes, stat=err)
+       DEALLOCATE(stdev_arr_measur, stat=err)
+       DEALLOCATE(measur, stat=err)
+       DEALLOCATE(residuals, stat=err) 
+       DEALLOCATE(mask_measur, stat=err)
+       DEALLOCATE(alpha, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       RETURN
+    END IF
+
+    IF (element_type_ == "keplerian") THEN
+       params(4:6) = MODULO(params(4:6), two_pi)
+    ELSE IF (element_type_ == "cometary") THEN
+       params(4:5) = MODULO(params(4:5), two_pi)
+    ELSE IF (element_type_ == "cartesian" .AND. &
+         SQRT(DOT_PRODUCT(params(4:6),params(4:6))) > sol) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Speed of object is larger than speed of light.", 1)
+       DEALLOCATE(mask_measur, stat=err)
+       RETURN
+    END IF
+
+    ! Output final orbital elements and sky-plane residuals and rms if needed:
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "Call to 'ephemeris_lsl' from " // &
+            "'levenbergMarquardt_SO'."
+    END IF
+    CALL ephemeris_lsl(params, residuals, jacobians, rchi2)
+
+    DEALLOCATE(obsy_ccoords, stat=err)
+    DEALLOCATE(information_matrix_measur, stat=err) 
+    DEALLOCATE(obsy_codes, stat=err)
+    DEALLOCATE(stdev_arr_measur, stat=err)
+    DEALLOCATE(measur, stat=err)
+    DEALLOCATE(residuals, stat=err) 
+    DEALLOCATE(alpha, stat=err)
+    DEALLOCATE(jacobians, stat=err)
+
+    CALL NULLIFY(this%orb_ml_cmp)
+    CALL NEW(this%orb_ml_cmp, params, TRIM(element_type_), TRIM(frame_), copy(t))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (65)", 1)
+       DEALLOCATE(mask_measur, stat=err)
+       RETURN
+    END IF
+    CALL setParameters(this%orb_ml_cmp, &
+         dyn_model=dyn_model_, &
+         perturbers=this%perturbers_prm, &
+         integration_step=integration_step_, &
+         integrator=integrator_, &
+         finite_diff=finite_diff_)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "TRACE BACK (70)", 1)
+       DEALLOCATE(mask_measur, stat=err)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%cov_ml_cmp)) THEN
+       ALLOCATE(this%cov_ml_cmp(6,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / " // &
+               "leastSquares", &
+               "Could not allocate memory (10).", 1)
+          DEALLOCATE(mask_measur, stat=err)
+          RETURN
+       END IF
+    END IF
+    DO i=1,nparam
+       IF (.NOT.mask_param(i)) THEN
+          cov_mat_param(i,i) = 0.0_bp
+       END IF
+    END DO
+    this%cov_ml_cmp = cov_mat_param
+    this%cov_type_prm = element_type_
+    this%obs_masks_prm = mask_measur
+    DEALLOCATE(mask_measur, stat=err)
+
+    ! Check whether acceptable solution based on rchi2
+
+    IF (rchi2 > this%ls_rchi2_acceptable_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / " // &
+            "levenbergMarquardt", &
+            "Could not find an acceptable least-squares solution.", 1)
+       RETURN
+    END IF
+
+  CONTAINS
+
+    ! LevenbergMarquardt_private and coefficients are essentially
+    ! identical to the subroutines found in estimators.f90.
+
+    SUBROUTINE levenbergMarquardt_private
+
+      !      REAL(bp), SAVE :: rchi2_
+      REAL(bp), DIMENSION(:), ALLOCATABLE, SAVE :: params_, beta
+      REAL(bp), DIMENSION(:,:), ALLOCATABLE, SAVE :: param_corrections
+
+      IF (lambda < 0.0_bp) THEN
+         ALLOCATE(params_(nparam),beta(nparam),param_corrections(nparam,1))
+         !lambda = 0.001_bp
+         lambda = 0.000001_bp
+         params_ = params
+         IF (info_verb >= 2) THEN
+            WRITE(stdout,"(2X,A)") "First call to 'coefficients' from " // &
+                 "'levenbergMarquardt_private' when lambda < 0."
+         END IF
+         CALL coefficients(params_, alpha, beta)
+         IF (error) THEN
+            CALL errorMessage("StochasticOrbit / " // &
+                 "levenbergMarquardt / levenbergMarquardt_private", &
+                 "TRACE BACK (5)", 1)
+            DEALLOCATE(params_, beta, param_corrections)
+            RETURN
+         END IF
+         !         rchi2_ = rchi2
+         rchi2_previous = rchi2
+      ELSE
+         rchi2_previous = rchi2         
+      END IF
+      cov_mat_param = alpha
+      cov_mat_param = diagonal_multiplication(cov_mat_param, 1.0_bp+lambda, errstr, mask_param)
+      IF (LEN_TRIM(errstr) /= 0) THEN
+         error = .TRUE.
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / levenbergMarquardt_private", &
+              TRIM(errstr), 1)
+         errstr = ""
+         DEALLOCATE(params_, beta, param_corrections)
+         RETURN
+      END IF
+      param_corrections(:,1) = beta
+      CALL gauss_jordan(cov_mat_param, param_corrections, errstr)
+      IF (LEN_TRIM(errstr) /= 0) THEN
+         error = .TRUE.
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / levenbergMarquardt_private", &
+              TRIM(errstr), 1)
+         errstr = ""
+         DEALLOCATE(params_, beta, param_corrections)
+         RETURN
+      END IF
+      IF (ABS(lambda) < EPSILON(lambda)) THEN
+         DEALLOCATE(params_, beta, param_corrections)
+         RETURN
+      END IF
+      params_ = params + param_corrections(:,1)
+      IF (info_verb >= 2) THEN
+         WRITE(stdout,"(2X,A)") "Second call to 'coefficients' from " // &
+              "'levenbergMarquardt_private' when lambda > 0."
+      END IF
+      CALL coefficients(params_, cov_mat_param, param_corrections(:,1))
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / levenbergMarquardt_private", &
+              "TRACE BACK (10)", 1)
+         DEALLOCATE(params_, beta, param_corrections)
+         RETURN
+      END IF
+      !      IF (rchi2 < rchi2_) THEN
+      IF (rchi2 < rchi2_previous) THEN
+         lambda = 0.5_bp*lambda
+         !         rchi2_ = rchi2
+         alpha = cov_mat_param
+         beta = param_corrections(:,1)
+         params = params_
+      ELSE
+         !lambda = 10.0_bp*lambda
+         lambda = 10.0_bp*lambda
+         !         rchi2 = rchi2_
+      END IF
+      IF (lambda < EPSILON(lambda)) THEN
+         lambda = EPSILON(lambda)
+      END IF
+
+    END SUBROUTINE levenbergMarquardt_private
+
+
+    SUBROUTINE coefficients(params, alpha, beta)
+
+      !IMPLICIT NONE
+      REAL(bp), DIMENSION(:), INTENT(inout) :: params
+      REAL(bp), DIMENSION(:), INTENT(out) :: beta
+      REAL(bp), DIMENSION(:,:), INTENT(out) :: alpha
+
+      REAL(bp), DIMENSION(nparam,nmultidata) :: tmp
+      INTEGER :: i
+
+      IF (info_verb >= 2) THEN
+         WRITE(stdout,"(2X,A)") "Call to 'ephemeris_lsl' from " // &
+              "'coefficients'."
+      END IF
+      CALL ephemeris_lsl(params, residuals, jacobians, rchi2)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / coefficients", &
+              "TRACE BACK (5)", 1)
+         RETURN
+      END IF
+      ! Approximate Hessian by multiplying Jacobians
+      ! alpha = cov_param^(-1) = J^T Sigma_obs^(-1) J:
+      ! beta = J^T Sigma_obs^(-1) y:
+      alpha = 0.0_bp
+      beta = 0.0_bp
+      DO i=1,ndata
+         tmp = MATMUL(TRANSPOSE(jacobians(1:nmultidata,1:nparam,i)), &
+              information_matrix_measur(i,1:nmultidata,1:nmultidata))
+         alpha = alpha + MATMUL(tmp, jacobians(1:nmultidata,1:nparam,i))
+         beta = beta + MATMUL(tmp, residuals(i,1:nmultidata))
+      END DO
+      DO i=1,nparam
+         IF (.NOT.mask_param(i)) THEN
+            alpha(i,:) = 0.0_bp
+            alpha(:,i) = 0.0_bp
+            alpha(i,i) = 1.0_bp
+            beta(i) = 0.0_bp
+         END IF
+      END DO
+
+    END SUBROUTINE coefficients
+
+
+    SUBROUTINE ephemeris_lsl(elements, residuals, jacobians, rchi2)
+
+      !implicit none
+      REAL(bp), DIMENSION(:), INTENT(inout) :: elements ! nparam
+      REAL(bp), DIMENSION(:,:), INTENT(out) :: residuals ! ndata,nmultidata
+      REAL(bp), DIMENSION(:,:,:), INTENT(out) :: jacobians ! nmultidata,nparam,ndata
+      REAL(bp), INTENT(out) :: rchi2
+
+      TYPE (Orbit) :: orb
+      TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: ephemerides
+      REAL(bp), DIMENSION(:,:,:), POINTER :: partials_arr
+      REAL(bp), DIMENSION(SIZE(residuals,dim=1),SIZE(residuals,dim=2)) :: computed
+      INTEGER :: j
+
+      IF (element_type_ == "keplerian") THEN
+         elements(4:6) = MODULO(elements(4:6), two_pi)
+      ELSE IF (element_type_ == "cometary") THEN
+         elements(4:5) = MODULO(elements(4:5), two_pi)
+      ELSE IF (element_type_ == "cartesian" .AND. &
+           SQRT(DOT_PRODUCT(elements(4:6),elements(4:6))) > sol) THEN
+         error = .TRUE.
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / ephemeris_lsl", &
+              "Speed of object is larger than speed of light.", 1)
+         RETURN
+      END IF
+      CALL NEW(orb, elements, TRIM(element_type_), TRIM(frame_), copy(t))
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / ephemeris_lsl", &
+              "TRACE BACK (5)", 1)
+         RETURN
+      END IF
+      CALL setParameters(orb, &
+           dyn_model=dyn_model_, &
+           perturbers=this%perturbers_prm, &
+           integration_step=integration_step_, &
+           integrator=integrator_, &
+           finite_diff=finite_diff_)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / ephemeris_lsl", &
+              "TRACE BACK (10)", 1)
+         RETURN
+      END IF
+
+      ! Compute positions and partial derivatives:
+      CALL getEphemerides(orb, obsy_ccoords, ephemerides, &
+           partials_arr=partials_arr)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / ephemeris_lsl", &
+              "TRACE BACK (15)", 1)
+         RETURN
+      END IF
+
+      ! Write design matrix and add cosine term to it and the computed positions:
+      jacobians = 0.0_bp
+      DO j=1,ndata
+         computed(j,:) = getCoordinates(ephemerides(j))
+         computed(j,2) = computed(j,2)*COS(measur(j,3))
+         IF (error) THEN
+            CALL errorMessage("StochasticOrbit / " // &
+                 "levenbergMarquardt / ephemeris_lsl", &
+                 "TRACE BACK (20)", 1)
+            RETURN
+         END IF
+         jacobians(:,:,j) = partials_arr(:,:,j)
+         jacobians(2,:,j) = jacobians(2,:,j)*COS(measur(j,3))
+      END DO
+      DEALLOCATE(ephemerides, partials_arr, stat=err)
+      IF (err /= 0) THEN
+         error = .TRUE.
+         CALL errorMessage("StochasticOrbit / " // &
+              "levenbergMarquardt / ephemeris_lsl", &
+              "Could not deallocate memory.", 1)
+         RETURN
+      END IF
+      ! Output orbital elements and sky-plane residuals and rms if needed:
+      IF (info_verb >= 2) THEN
+         t_ = getTime(orb)
+         WRITE(stdout,"(2X,A,I0,A)") "Elements, residuals, RMS, and reduced chi2:"
+         str = getCalendarDateString(t_, "TT")
+         SELECT CASE (element_type_)
+         CASE ("keplerian")
+            elements = getElements(orb, element_type_)
+            WRITE(stdout,"(2X,A,6(1X,F20.13),1X,A)") "Kep: ", &
+                 elements(1:2), elements(3:6)/rad_deg, &
+                 TRIM(str)
+         CASE ("cartesian")
+            elements = getElements(orb, element_type_, frame=frame_)
+            WRITE(stdout,'(2X,A,6(1X,F20.13),1X,A)') "Car: ", &
+                 elements(1:6),TRIM(str)
+         END SELECT
+         IF (error) THEN
+            CALL errorMessage("StochasticOrbit / " // &
+                 "levenbergMarquardt / ephemeris_lsl", &
+                 "TRACE BACK (25)", 1)
+            RETURN
+         END IF
+         CALL NULLIFY(t_)
+         WRITE(stdout,"(2X,A)") "Residuals RA & Dec [as]:"
+      END IF
+      CALL NULLIFY(orb)
+      residuals = 0.0_bp
+      DO j=1,ndata
+         residuals(j,1:6) = measur(j,1:6) - computed(j,1:6)
+         IF (ABS(residuals(j,2)) > pi) THEN
+            residuals(j,2) = two_pi - residuals(j,2)
+         END IF
+         IF (info_verb >= 2) THEN
+            IF (ALL(mask_measur(j,2:3))) THEN
+               t_ = getTime(obsy_ccoords(j))
+               WRITE(stdout,"(2X,A,2(F20.7,1X),A,1X,A)") &
+                    " ", &
+                    residuals(j,2:3)/rad_asec, " ", &
+                    TRIM(obsy_codes(j))
+            ELSE
+               WRITE(stdout,"(2X,A,2(F15.7,1X),A,1X,A)") "(", &
+                    residuals(j,2:3)/rad_asec, ")", TRIM(obsy_codes(j))
+            END IF
+         END IF
+      END DO
+
+      ! Compute reduced chi2:
+      rchi2 = chi_square(residuals, information_matrix_measur, mask_measur, errstr) / &
+           REAL(COUNT(mask_measur)-COUNT(mask_param),bp)
+
+      IF (info_verb >= 2) THEN
+         WRITE(stdout,"(2X,A,2(1X,F15.7))") "RMS RA & Dec [arcsec]: ", &
+              SQRT(SUM(residuals(:,2)**2,mask=mask_measur(:,2))/COUNT(mask_measur(:,2)))/rad_asec, &
+              SQRT(SUM(residuals(:,3)**2,mask=mask_measur(:,3))/COUNT(mask_measur(:,3)))/rad_asec
+         WRITE(stdout,"(2X,A,1X,F20.5)") "Reduced chi2: ", &
+              rchi2
+         WRITE(stdout,"(2X,A,1X,F20.15)") "Lambda: ", lambda
+         WRITE(stdout,"(2X,A)") ""
+      END IF
+
+    END SUBROUTINE ephemeris_lsl
+
+  END SUBROUTINE levenbergMarquardt_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Arrange observations in pairs. Observation mask used.
+  !!
+  !! Returns error.
+  !!
+  !! Modifications needed:
+  !! To make ranging more efficient, too close pairs should be avoided.
+  !! Also, it might be useful to use only observations from the far ends of
+  !! the data set. Where should this filtering be done?
+  !!
+  SUBROUTINE makePairsOfObservations(this, idx_pair)
+
+    IMPLICIT NONE
+    TYPE(StochasticOrbit), INTENT(inout) :: this
+    INTEGER, DIMENSION(:,:), POINTER     :: idx_pair
+    INTEGER, DIMENSION(:,:), ALLOCATABLE :: idx_pair_
+    REAL(bp)                             :: x
+    INTEGER                              :: nobs, nobs_orig, n1, n2, ncomb
+    INTEGER                              :: i1, i2, nomit, k, err
+    INTEGER, DIMENSION(:), ALLOCATABLE   :: ip, ip2
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / makePairsOfObservations", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nomit = 0
+    nobs_orig = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / makePairsOfObservations", &
+            "TRACE BACK (1", 1)
+       RETURN
+    END IF
+
+    nobs = COUNT(this%obs_masks_prm(:,2))
+    IF (nobs < 2) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / makePairsOfObservations", &
+            "Too few observations for pairing.",1)
+       RETURN
+    END IF
+    nomit = nobs_orig - nobs
+
+    ncomb = INT(0.5_bp*nobs*(nobs-1))
+    ALLOCATE(idx_pair(ncomb,2),idx_pair_(ncomb,2))
+
+    ALLOCATE(ip(nobs_orig),ip2(nobs))
+    ip = (/ (k,k = 1,nobs_orig) /)
+    ip2 = PACK(ip,this%obs_masks_prm(:,2))
+    x = 1.0_bp*(ncomb-nobs)/nobs
+    n1 = 1+INT(x)
+    n2 = nobs*(x-INT(x))
+    DO k = 1,n1 
+       idx_pair(((k-1)*nobs+1):k*nobs,1) = ip2
+    END DO
+    i1 = 1
+    i2 = nobs
+    DO k = 1,n1
+       idx_pair(i1:i2,2) = CSHIFT(ip2,k)
+       i1 = i1+nobs
+       i2 = i2+nobs
+    END DO
+
+    IF (n2 /= 0) THEN
+       idx_pair(i1:i1+n2-1,1) = ip2(1:n2)
+       ip = CSHIFT(ip2,n1+1)
+       idx_pair(i1:i1+n2-1,2) = CSHIFT(ip(1:n2),n1+1)
+    END IF
+
+    ! Order so that first observation number in the pair is always
+    ! smaller than the second.
+    idx_pair_ = idx_pair
+    WHERE(idx_pair(:,2) < idx_pair(:,1))
+       idx_pair(:,1) = idx_pair_(:,2)
+       idx_pair(:,2) = idx_pair_(:,1)
+    END WHERE
+
+    DEALLOCATE(idx_pair_, ip, ip2, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / makePairsOfObservations", &
+            "Could not deallocate memory.",1)
+       DEALLOCATE(idx_pair, stat=err)
+       DEALLOCATE(ip, stat=err)
+       DEALLOCATE(ip2, stat=err)       
+       RETURN
+    END IF
+
+  END SUBROUTINE makePairsOfObservations
+
+
+
+
+
+  !! *Description*:
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE propagate_SO(this, t, encounters)
+
+    IMPLICIT NONE
+    TYPE(StochasticOrbit), INTENT(inout)          :: this
+    TYPE (Time), INTENT(inout)                    :: t
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: encounters 
+
+    REAL(bp), DIMENSION(:,:,:), POINTER    :: jacobians
+    REAL(bp), DIMENSION(6,6)               :: jacobian, cov
+    REAL(bp)                               :: det
+    INTEGER                                :: i, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / propagate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       !CALL propagate(this%orb_arr_cmp, t)
+       IF (PRESENT(encounters)) THEN
+          CALL propagate(this%orb_arr_cmp, t, jacobian=jacobians, encounters=encounters)
+       ELSE
+          CALL propagate(this%orb_arr_cmp, t, jacobian=jacobians)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / propagate", &
+               "TRACE BACK (5)", 1)
+          DEALLOCATE(jacobians, stat=err)
+          RETURN
+       END IF
+       ! Propagation of pdf
+       DO i=1,SIZE(this%orb_arr_cmp)
+          det = determinant(jacobians(i,:,:), errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / propagate", &
+                  "TRACE BACK (10) " // TRIM(errstr), 1)
+             errstr = ""
+             DEALLOCATE(jacobians, stat=err)
+             RETURN
+          END IF
+          ! Changed 2008-12-14
+          !this%pdf_arr_cmp(i) = this%pdf_arr_cmp(i) / det
+          !this%jac_arr_cmp(i,1) = this%jac_arr_cmp(i,1) / det
+          this%pdf_arr_cmp(i) = this%pdf_arr_cmp(i) * det
+          this%jac_arr_cmp(i,1) = this%jac_arr_cmp(i,1) * det
+       END DO
+       DEALLOCATE(jacobians,stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / propagate", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (exist(this%orb_ml_cmp)) THEN
+       cov = getCovarianceMatrix(this, & 
+            getElementType(this%orb_ml_cmp), & 
+            getFrame(this%orb_ml_cmp))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / propagate", &
+               "Missing covariances.", 1)
+          RETURN
+       END IF
+       IF (PRESENT(encounters)) THEN
+          CALL propagate(this%orb_ml_cmp, t, jacobian=jacobian, encounters=encounters)
+       ELSE
+          CALL propagate(this%orb_ml_cmp, t, jacobian=jacobian)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / propagate", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       this%cov_ml_cmp = MATMUL(MATMUL(jacobian, cov), &
+            TRANSPOSE(jacobian))
+    END IF
+
+  END SUBROUTINE propagate_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The default values for the angular deviations ("generation window")
+  !! and the maximum residuals ("acceptance window") are adjusted
+  !! according to the given factor. These values can be overridden
+  !! with the appropriate routine if needed.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setAcceptanceWindow_sigma(this, accept_multiplier)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), INTENT(in), OPTIONAL :: accept_multiplier
+    REAL(bp), DIMENSION(:,:), POINTER :: stdevs
+    REAL(bp) :: accept_multiplier_
+    INTEGER :: nobs, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+    IF (PRESENT(accept_multiplier)) THEN
+       IF (accept_multiplier < 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+               "Acceptance multiplier not accepted.", 1)
+          RETURN
+       END IF
+       accept_multiplier_ = accept_multiplier
+       this%accept_multiplier_prm = accept_multiplier
+    ELSE IF (this%accept_multiplier_prm > 0) THEN
+       accept_multiplier_ = this%accept_multiplier_prm
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+            "Acceptance multiplier not available.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (ASSOCIATED(this%res_accept_prm)) THEN
+       IF (SIZE(this%res_accept_prm,dim=1) /= nobs) THEN
+          DEALLOCATE(this%res_accept_prm, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+                  "Could not deallocate memory (5).", 1)
+             RETURN
+          END IF
+       END IF
+    END IF
+    IF (.NOT.ASSOCIATED(this%res_accept_prm)) THEN    
+       ALLOCATE(this%res_accept_prm(nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+    stdevs => getStandardDeviations(this%obss)
+    ! Acceptance windows for residuals:
+    this%res_accept_prm(1:nobs,1:6) = accept_multiplier_*stdevs(1:nobs,1:6)
+    DEALLOCATE(stdevs, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setAcceptanceWindow", &
+            "Could not deallocate memory (10).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setAcceptanceWindow_sigma
+
+
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The default values for the angular deviations ("generation window")
+  !! and the maximum residuals ("acceptance window") are adjusted
+  !! according to the given factor. These values can be overridden
+  !! with the appropriate routine if needed.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setGenerationWindow(this, offset)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), DIMENSION(:), INTENT(in), OPTIONAL :: offset
+    REAL(bp), DIMENSION(:,:), POINTER :: stdevs
+    REAL(bp) :: mean
+    INTEGER :: i, j, nobs, err
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%generat_multiplier_prm < 0.0_bp) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+            "Generation multiplier not acceptable.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (ASSOCIATED(this%sor_deviates_prm)) THEN
+       IF (SIZE(this%sor_deviates_prm,dim=1) /= nobs) THEN
+          DEALLOCATE(this%sor_deviates_prm, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+                  "Could not deallocate memory (5).", 1)
+             RETURN
+          END IF
+       END IF
+    END IF
+    IF (.NOT.ASSOCIATED(this%sor_deviates_prm)) THEN
+       ALLOCATE(this%sor_deviates_prm(nobs,6,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+
+    this%sor_deviates_prm = 0.0_bp
+    ! Angular deviates:
+    IF (ASSOCIATED(this%res_arr_cmp)) THEN
+       ! Use knowledge of previous results, i.e., move the center of
+       ! the sampling window to the mean of the previous residuals:
+       IF (SIZE(this%res_arr_cmp,dim=1) /= SIZE(this%orb_arr_cmp,dim=1) .OR. &
+            SIZE(this%res_arr_cmp,dim=2) /= nobs) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+               "Inconsistencies in array dimensions", 1)
+          RETURN
+       END IF
+       DO i=1,nobs
+          DO j=1,6
+             CALL moments(this%res_arr_cmp(:,i,j), mean=mean, errstr=errstr)!, std_dev=stdev)!, pdf=this%pdf_arr_cmp)
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+                     "Could not compute moments. " // TRIM(errstr), 1)
+                errstr = ""
+                RETURN
+             END IF
+             this%sor_deviates_prm(i,j,1) = mean
+             !this%sor_deviates_prm(i,j,2) = this%generat_multiplier_prm*stdev
+          END DO
+       END DO
+    ELSE
+       stdevs => getStandardDeviations(this%obss)
+       this%sor_deviates_prm(1:nobs,1:6,1) = 0.0_bp          
+       IF (PRESENT(offset)) THEN
+          this%sor_deviates_prm(1,2:3,1) = offset(1:2)
+          this%sor_deviates_prm(nobs,2:3,1) = offset(3:4)
+       END IF
+       this%sor_deviates_prm(1:nobs,1:6,2) = this%generat_multiplier_prm*stdevs(1:nobs,1:6)
+       DEALLOCATE(stdevs, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setGenerationWindow", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE setGenerationWindow
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Set parameters.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setParameters_SO(this, &
+       dyn_model, perturbers, integration_step, integrator, &
+       finite_diff, &
+       t_inv, element_type, multiple_objects, outlier_rejection, &
+       dchi2_rejection, dchi2_max, regularized_pdf, jacobians_pdf, &
+       accept_multiplier, outlier_multiplier, &
+       gaussian_pdf, chi2_min, chi2_min_init, &
+       apriori_a_max, apriori_a_min, apriori_periapsis_max, apriori_periapsis_min, &
+       apriori_apoapsis_max, apriori_apoapsis_min, apriori_rho_max, apriori_rho_min, &
+       sor_norb, sor_norb_sw, sor_ntrial, sor_ntrial_sw, &
+       sor_rho1_l, sor_rho1_u, sor_rho2_l, sor_rho2_u, &
+       sor_random_obs_selection, sor_niter, generat_multiplier, &
+       sor_generat_offset, sor_2point_method, sor_2point_method_sw, &
+       sor_iterate_bounds, &
+       vov_norb, vov_ntrial, vov_norb_iter, vov_ntrial_iter, &
+       vov_nmap, vov_niter, vov_scaling, vov_mapping_mask, &
+       vomcmc_norb, vomcmc_ntrial, vomcmc_norb_iter, vomcmc_ntrial_iter, &
+       vomcmc_nmap, vomcmc_niter, vomcmc_scaling, vomcmc_mapping_mask, &
+       ls_correction_factor, ls_niter_major_max, ls_niter_major_min, ls_niter_minor, &
+       ls_element_mask, ls_rchi2_acceptable, &
+       cos_nsigma, cos_norb, cos_ntrial, cos_gaussian, &
+       smplx_tol, smplx_niter, smplx_force, smplx_similarity_tol, &
+       os_norb, os_ntrial, os_sampling_type, generat_gaussian_deviates, &
+       set_acceptance_window)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Time), INTENT(in), OPTIONAL :: t_inv
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: &
+         dyn_model, &
+         integrator, &
+         element_type, &
+         sor_2point_method, &
+         sor_2point_method_sw
+    REAL(bp), DIMENSION(6,2), INTENT(in), OPTIONAL :: &
+         vov_scaling, &
+         vomcmc_scaling
+    REAL(bp), DIMENSION(6), INTENT(in), OPTIONAL :: &
+         finite_diff
+    REAL(bp), DIMENSION(4), INTENT(in), OPTIONAL :: &
+         sor_generat_offset
+    REAL(bp), INTENT(in), OPTIONAL :: &
+         integration_step, &
+         accept_multiplier, &
+         outlier_multiplier, &
+         chi2_min, &
+         chi2_min_init, &
+         dchi2_max, &
+         apriori_a_max, &
+         apriori_a_min, &
+         apriori_periapsis_max, &
+         apriori_periapsis_min, &
+         apriori_apoapsis_max, &
+         apriori_apoapsis_min, &
+         apriori_rho_max, &
+         apriori_rho_min, &
+         sor_rho1_l, &
+         sor_rho1_u, &
+         sor_rho2_l, &
+         sor_rho2_u, &
+         generat_multiplier, &
+         ls_correction_factor, &
+         ls_rchi2_acceptable, &
+         cos_nsigma, &
+         smplx_tol, &
+         smplx_similarity_tol
+    INTEGER, INTENT(in), OPTIONAL :: &
+         sor_norb, &
+         sor_norb_sw, &
+         sor_ntrial, &
+         sor_ntrial_sw, &
+         sor_niter, &
+         vov_norb, &
+         vov_ntrial, &
+         vov_norb_iter, &
+         vov_ntrial_iter, &
+         vov_nmap, &
+         vov_niter, &
+         vomcmc_norb, &
+         vomcmc_ntrial, &
+         vomcmc_norb_iter, &
+         vomcmc_ntrial_iter, &
+         vomcmc_nmap, &
+         vomcmc_niter, &
+         ls_niter_major_max, &
+         ls_niter_major_min, &
+         ls_niter_minor, &
+         cos_norb, &
+         cos_ntrial, &
+         smplx_niter, &
+         os_norb, &
+         os_ntrial, &
+         os_sampling_type
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: &
+         perturbers, &
+         sor_iterate_bounds, &
+         vov_mapping_mask, &
+         vomcmc_mapping_mask, &
+         ls_element_mask
+    LOGICAL, INTENT(in), OPTIONAL :: &
+         multiple_objects, &
+         regularized_pdf, &
+         dchi2_rejection, &
+         jacobians_pdf, &
+         sor_random_obs_selection, &
+         gaussian_pdf, &
+         outlier_rejection, &
+         cos_gaussian, &
+         smplx_force, &
+         generat_gaussian_deviates, &
+         set_acceptance_window
+
+    CHARACTER(len=256) :: str
+    INTEGER :: i, err
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setParameters", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(dyn_model)) THEN
+       IF (LEN_TRIM(dyn_model) > DYN_MODEL_LEN) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Parameter 'dyn_model' too long.", 1)
+          RETURN
+       END IF
+       str = dyn_model
+       CALL locase(str, error)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "The dynamical model string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       IF (str /= "2-body" .AND. &
+            str /= "n-body" .AND. str /= "pseudo-n-body") THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Option " // TRIM(dyn_model) // " not available.", 1)
+          RETURN
+       END IF
+       this%dyn_model_prm = TRIM(str)
+       IF (str == "2-body" .OR. str == "n-body") THEN
+          IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+             DO i=1,SIZE(this%orb_arr_cmp)
+                CALL setParameters(this%orb_arr_cmp(i), dyn_model=this%dyn_model_prm)
+             END DO
+          END IF
+          IF (exist(this%orb_ml_cmp)) THEN
+             CALL setParameters(this%orb_ml_cmp, dyn_model=this%dyn_model_prm)
+          END IF
+       END IF
+    END IF
+    IF (PRESENT(perturbers)) THEN
+       IF (SIZE(perturbers) > SIZE(this%perturbers_prm)) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Perturber array too small.", 1)
+          RETURN                       
+       END IF
+       this%perturbers_prm = perturbers
+       IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL setParameters(this%orb_arr_cmp(i), perturbers=this%perturbers_prm)
+          END DO
+       END IF
+       IF (exist(this%orb_ml_cmp)) THEN
+          CALL setParameters(this%orb_ml_cmp, perturbers=this%perturbers_prm)
+       END IF
+    END IF
+    IF (PRESENT(integration_step)) THEN
+       this%integration_step_prm = integration_step
+       IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL setParameters(this%orb_arr_cmp(i), integration_step=this%integration_step_prm)
+          END DO
+       END IF
+       IF (exist(this%orb_ml_cmp)) THEN
+          CALL setParameters(this%orb_ml_cmp, integration_step=this%integration_step_prm)
+       END IF
+    END IF
+    IF (PRESENT(integrator)) THEN
+       str = integrator
+       CALL locase(str, error)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "The integrator string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       this%integrator_prm = TRIM(str)
+       IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL setParameters(this%orb_arr_cmp(i), integrator=this%integrator_prm)
+          END DO
+       END IF
+       IF (exist(this%orb_ml_cmp)) THEN
+          CALL setParameters(this%orb_ml_cmp, integrator=this%integrator_prm)
+       END IF
+    END IF
+    IF (PRESENT(finite_diff)) THEN
+       IF (ALL(finite_diff > 0.0_bp)) THEN
+          IF (.NOT.ASSOCIATED(this%finite_diff_prm)) THEN
+             ALLOCATE(this%finite_diff_prm(6), stat=err)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / setParameters", &
+                     "Could not allocate memory.", 1)
+                RETURN
+             END IF
+          END IF
+          this%finite_diff_prm = finite_diff
+          IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+             DO i=1,SIZE(this%orb_arr_cmp)
+                CALL setParameters(this%orb_arr_cmp(i), finite_diff=this%finite_diff_prm)
+             END DO
+          END IF
+          IF (exist(this%orb_ml_cmp)) THEN
+             CALL setParameters(this%orb_ml_cmp, finite_diff=this%finite_diff_prm)
+          END IF
+       ENDIF
+    END IF
+    IF (PRESENT(t_inv)) THEN
+       this%t_inv_prm = copy(t_inv)
+    END IF
+    IF (PRESENT(element_type)) THEN
+       this%element_type_prm = element_type
+       DO i=1,LEN(this%element_type_prm)
+          IF (IACHAR(this%element_type_prm(i:i)) > 127) THEN
+             error = .TRUE.
+             EXIT
+          END IF
+       END DO
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "The element type string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       CALL locase(this%element_type_prm, error)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "The element type string contains forbidden characters.", 1)
+          RETURN
+       END IF
+       IF (this%element_type_prm /= "keplerian" .AND. &
+            this%element_type_prm /= "cartesian" .AND. &
+            this%element_type_prm /= "cometary") THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Orbital element type is not recognized: " // &
+               TRIM(element_type) // ".", 1)
+          RETURN          
+       END IF
+    END IF
+    IF (PRESENT(multiple_objects)) THEN
+       this%multiple_obj_prm = multiple_objects
+    END IF
+    IF (PRESENT(outlier_rejection)) THEN
+       this%outlier_rejection_prm = outlier_rejection
+    END IF
+    IF (PRESENT(outlier_multiplier)) THEN
+       IF (outlier_multiplier <= 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Multiplier for the outlier criterion is zero or negative.", 1)
+          RETURN
+       END IF
+       this%outlier_multiplier_prm = outlier_multiplier
+    END IF
+    IF (PRESENT(dchi2_rejection)) THEN
+       this%dchi2_rejection_prm = dchi2_rejection
+    END IF
+    IF (PRESENT(dchi2_max)) THEN
+       this%dchi2_prm = dchi2_max
+    END IF
+    IF (PRESENT(regularized_pdf)) THEN
+       this%regularization_prm = regularized_pdf
+    END IF
+    IF (PRESENT(jacobians_pdf)) THEN
+       this%jacobians_prm = jacobians_pdf
+    END IF
+    IF (PRESENT(accept_multiplier)) THEN
+       IF (accept_multiplier <= 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Scaling of acceptance window is zero or negative.", 1)
+          RETURN
+       END IF
+       this%accept_multiplier_prm = accept_multiplier
+       IF (PRESENT(set_acceptance_window)) THEN
+          IF (set_acceptance_window) THEN
+             CALL setAcceptanceWindow(this)
+          END IF
+       ELSE
+          CALL setAcceptanceWindow(this)          
+       END IF
+    END IF
+    IF (PRESENT(chi2_min)) THEN
+       this%chi2_min_prm = chi2_min
+    END IF
+    IF (PRESENT(chi2_min_init)) THEN
+       this%chi2_min_init_prm = chi2_min_init
+    END IF
+    IF (PRESENT(apriori_a_max)) THEN
+       this%apriori_a_max_prm = apriori_a_max
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_a_min)) THEN
+       this%apriori_a_min_prm = apriori_a_min
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_periapsis_max)) THEN
+       this%apriori_periapsis_max_prm = apriori_periapsis_max
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_periapsis_min)) THEN
+       this%apriori_periapsis_min_prm = apriori_periapsis_min
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_apoapsis_max)) THEN
+       this%apriori_apoapsis_max_prm = apriori_apoapsis_max
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_apoapsis_min)) THEN
+       this%apriori_apoapsis_min_prm = apriori_apoapsis_min
+       this%informative_apriori_prm = .TRUE.
+    END IF
+    IF (PRESENT(apriori_rho_max)) THEN
+       this%apriori_rho_max_prm = apriori_rho_max
+    END IF
+    IF (PRESENT(apriori_rho_min)) THEN
+       this%apriori_rho_min_prm = apriori_rho_min
+    END IF
+    IF (PRESENT(sor_norb)) THEN
+       IF (sor_norb < 0 .OR. sor_norb > 100000) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Number of sample orbits must be positive and " // &
+               "less than 100001.", 1)
+          RETURN
+       ELSE
+          this%sor_norb_prm = sor_norb
+       END IF
+    END IF
+    IF (PRESENT(sor_norb_sw)) THEN
+       IF (sor_norb_sw < 0 .OR. sor_norb_sw > 10000) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Number of sample orbits for the stepwise " // &
+               "approach must be positive and " // &
+               "less than 10001.", 1)
+          RETURN
+       ELSE
+          this%sor_norb_sw_prm = sor_norb_sw
+       END IF
+    END IF
+    IF (PRESENT(sor_ntrial)) THEN
+       IF (sor_ntrial < 0 .OR. sor_ntrial > 100000000) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Number of trial orbits must be positive and " // &
+               "less than 100,000,001.", 1)
+          RETURN
+       ELSE
+          this%sor_ntrial_prm = sor_ntrial
+       END IF
+    END IF
+    IF (PRESENT(sor_ntrial_sw)) THEN
+       IF (sor_ntrial_sw < 0 .OR. sor_ntrial_sw > 1000000) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Number of trial orbits for the stepwise " // & 
+               "must be positive and less than 1,000,001.", 1)
+          RETURN
+       ELSE
+          this%sor_ntrial_sw_prm = sor_ntrial_sw
+       END IF
+    END IF
+    IF (PRESENT(sor_rho1_l)) THEN
+       this%sor_rho_prm(1,1) = sor_rho1_l
+    END IF
+    IF (PRESENT(sor_rho1_u)) THEN
+       this%sor_rho_prm(1,2) = sor_rho1_u
+    END IF
+    IF (PRESENT(sor_rho2_l)) THEN
+       this%sor_rho_prm(2,1) = sor_rho2_l
+    END IF
+    IF (PRESENT(sor_rho2_u)) THEN
+       this%sor_rho_prm(2,2) = sor_rho2_u
+    END IF
+    IF (PRESENT(sor_random_obs_selection)) THEN
+       IF (sor_random_obs_selection) THEN
+          CALL setRandomObservationSelection(this)
+       END IF
+    END IF
+    IF (PRESENT(sor_niter)) THEN
+       this%sor_niter_prm = sor_niter
+    END IF
+    IF (PRESENT(gaussian_pdf)) THEN
+       IF (gaussian_pdf) THEN
+          this%sor_gaussian_pdf_prm = .TRUE.
+       ELSE
+          this%sor_gaussian_pdf_prm = .FALSE.
+       END IF
+       !this%sor_gaussian_pdf_prm = gaussian_pdf
+    END IF
+    IF (PRESENT(generat_multiplier) .AND. PRESENT(sor_generat_offset)) THEN
+       IF (generat_multiplier <= 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Scaling of generation window is zero or negative.", 1)
+          RETURN
+       END IF
+       this%generat_multiplier_prm = generat_multiplier
+       CALL setGenerationWindow(this, sor_generat_offset)
+    ELSE IF (PRESENT(generat_multiplier)) THEN
+       IF (generat_multiplier <= 0.0_bp) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setParameters", &
+               "Scaling of generation window is zero or negative.", 1)
+          RETURN
+       END IF
+       this%generat_multiplier_prm = generat_multiplier
+       CALL setGenerationWindow(this)
+    END IF
+    IF (PRESENT(sor_2point_method)) THEN
+       this%sor_2point_method_prm = sor_2point_method
+    END IF
+    IF (PRESENT(sor_2point_method_sw)) THEN
+       this%sor_2point_method_sw_prm = sor_2point_method_sw
+    END IF
+    IF (PRESENT(sor_iterate_bounds)) THEN
+       this%sor_iterate_bounds_prm = sor_iterate_bounds
+    END IF
+
+    IF (PRESENT(vov_norb)) THEN
+       this%vov_norb_prm = vov_norb
+    END IF
+    IF (PRESENT(vov_ntrial)) THEN
+       this%vov_ntrial_prm = vov_ntrial
+    END IF
+    IF (PRESENT(vov_norb_iter)) THEN
+       this%vov_norb_iter_prm = vov_norb_iter
+    END IF
+    IF (PRESENT(vov_ntrial_iter)) THEN
+       this%vov_ntrial_iter_prm = vov_ntrial_iter
+    END IF
+    IF (PRESENT(vov_nmap)) THEN
+       this%vov_nmap_prm = vov_nmap
+    END IF
+    IF (PRESENT(vov_niter)) THEN
+       this%vov_niter_prm = vov_niter
+    END IF
+    IF (PRESENT(vov_scaling)) THEN
+       this%vov_scaling_prm = vov_scaling
+    END IF
+    IF (PRESENT(vov_mapping_mask)) THEN
+       this%vov_mapping_mask_prm = vov_mapping_mask
+    END IF
+    IF (PRESENT(vomcmc_norb)) THEN
+       this%vomcmc_norb_prm = vomcmc_norb
+    END IF
+    IF (PRESENT(vomcmc_ntrial)) THEN
+       this%vomcmc_ntrial_prm = vomcmc_ntrial
+    END IF
+    IF (PRESENT(vomcmc_norb_iter)) THEN
+       this%vomcmc_norb_iter_prm = vomcmc_norb_iter
+    END IF
+    IF (PRESENT(vomcmc_ntrial_iter)) THEN
+       this%vomcmc_ntrial_iter_prm = vomcmc_ntrial_iter
+    END IF
+    IF (PRESENT(vomcmc_nmap)) THEN
+       this%vomcmc_nmap_prm = vomcmc_nmap
+    END IF
+    IF (PRESENT(vomcmc_niter)) THEN
+       this%vomcmc_niter_prm = vomcmc_niter
+    END IF
+    IF (PRESENT(vomcmc_scaling)) THEN
+       this%vomcmc_scaling_prm = vomcmc_scaling
+    END IF
+    IF (PRESENT(vomcmc_mapping_mask)) THEN
+       this%vomcmc_mapping_mask_prm = vomcmc_mapping_mask
+    END IF
+    IF (PRESENT(ls_correction_factor)) THEN
+       this%ls_corr_fac_prm = ls_correction_factor
+    END IF
+    IF (PRESENT(ls_rchi2_acceptable)) THEN
+       this%ls_rchi2_acceptable_prm = ls_rchi2_acceptable
+    END IF
+    IF (PRESENT(ls_niter_major_max)) THEN
+       this%ls_niter_major_max_prm = ls_niter_major_max
+    END IF
+    IF (PRESENT(ls_niter_major_min)) THEN
+       this%ls_niter_major_min_prm = ls_niter_major_min
+    END IF
+    IF (PRESENT(ls_niter_minor)) THEN
+       this%ls_niter_minor_prm = ls_niter_minor
+    END IF
+    IF (PRESENT(ls_element_mask)) THEN
+       this%ls_elem_mask_prm = ls_element_mask
+    END IF
+    IF (PRESENT(cos_nsigma)) THEN
+       this%cos_nsigma_prm = cos_nsigma
+    END IF
+    IF (PRESENT(cos_norb)) THEN
+       this%cos_norb_prm = cos_norb
+    END IF
+    IF (PRESENT(cos_ntrial)) THEN
+       this%cos_ntrial_prm = cos_ntrial
+    END IF
+    IF (PRESENT(cos_gaussian)) THEN
+       this%cos_gaussian_prm = cos_gaussian
+    END IF
+    IF (PRESENT(smplx_tol)) THEN
+       this%smplx_tol_prm = smplx_tol
+    END IF
+    IF (PRESENT(smplx_similarity_tol)) THEN
+       this%smplx_similarity_tol_prm = smplx_similarity_tol
+    END IF
+    IF (PRESENT(smplx_niter)) THEN
+       this%smplx_niter_prm = smplx_niter
+    END IF
+    IF (PRESENT(smplx_force)) THEN
+       this%smplx_force_prm = smplx_force
+    END IF
+    IF (PRESENT(os_norb)) THEN
+       this%os_norb_prm = os_norb
+    END IF
+    IF (PRESENT(os_ntrial)) THEN
+       this%os_ntrial_prm = os_ntrial
+    END IF
+    IF (PRESENT(os_sampling_type)) THEN
+       this%os_sampling_type_prm = os_sampling_type
+    END IF
+    IF (PRESENT(generat_gaussian_deviates)) THEN
+       this%generat_gaussian_deviates_prm = generat_gaussian_deviates
+    END IF
+
+  END SUBROUTINE setParameters_SO
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the ranging parameters that are suitable for NEOs.
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setNEORanging(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setNEORanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL setRangeBounds(this, 0.1_bp, 6.0_bp, -1.0_bp, 1.0_bp)
+    CALL setParameters(this, sor_norb=2000, sor_ntrial=1000000)
+
+  END SUBROUTINE setNEORanging
+
+
+
+  !! *Description*:
+  !!
+  !! Updates the observation mask of the observation specified, i.e.,
+  !! the inclusion or omission of observations in orbit inversion is
+  !! changed.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationMask_one(this, i, obs_mask)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    LOGICAL, DIMENSION(6), INTENT(in)     :: obs_mask
+    INTEGER, INTENT(in)                   :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationMask", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (i > getNrOfObservations(this%obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationMask", &
+            "Unrealistic input values.", 1)
+       RETURN
+    END IF
+
+    this%obs_masks_prm(i,:) = obs_mask
+
+  END SUBROUTINE setObservationMask_one
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Updates the observation mask of the observations, i.e.,
+  !! the inclusion or omission of observations in orbit inversion is
+  !! changed.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationMask_all(this, obs_masks)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    LOGICAL, DIMENSION(:,:), INTENT(in)   :: obs_masks
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationMask", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%obs_masks_prm = obs_masks
+
+  END SUBROUTINE setObservationMask_all
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Updates the observation mask of the observation specified using
+  !! user-specified information from observation notes, i.e.,
+  !! the inclusion or omission of observations in orbit inversion is
+  !! changed.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationMask_all_notes(this, use_notes)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    LOGICAL, INTENT(in)                   :: use_notes
+    INTEGER :: err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationMask", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    IF(.NOT. exist(this%obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationMask", &
+            "Observations not intialized.", 1)
+       RETURN
+    END IF
+
+    IF (ASSOCIATED(this%obs_masks_prm)) THEN
+       DEALLOCATE(this%obs_masks_prm, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setObservationMask", &
+               "Could not deallocate memory.", 1)
+          RETURN          
+       END IF
+    END IF
+    this%obs_masks_prm => getObservationMasks(this%obss, use_notes)
+
+  END SUBROUTINE setObservationMask_all_notes
+
+
+
+
+  !! Description:
+  !!
+  !! Sets observation pair to default values:
+  !! 1) if none excluded, first and last observation of the set
+  !! 2) if some excluded, first and last observation NOT excluded
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationPair_default(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    INTEGER                               :: nobs, i, err, iobs1, iobs2 
+    INTEGER, DIMENSION(:), ALLOCATABLE    :: intarr
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (ASSOCIATED(this%sor_pair_arr_prm)) THEN
+       DEALLOCATE(this%sor_pair_arr_prm, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setObservationPair", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+    END IF
+    ALLOCATE(intarr(nobs), this%sor_pair_arr_prm(1,2), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    DO i=1,nobs
+       intarr(i) = i
+    END DO
+    iobs1 = MINLOC(intarr, dim=1,mask=(this%obs_masks_prm(:,2) .AND. &
+         this%obs_masks_prm(:,3)))
+    iobs2 = MAXLOC(intarr, dim=1,mask=(this%obs_masks_prm(:,2) .AND. &
+         this%obs_masks_prm(:,3)))
+    this%sor_pair_arr_prm(1,1) = iobs1
+    this%sor_pair_arr_prm(1,2) = iobs2
+    IF (this%sor_pair_arr_prm(1,1) == this%sor_pair_arr_prm(1,2)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Only one observation available.", 1)
+       RETURN
+    END IF
+    DEALLOCATE(intarr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Could not deallocate memory (10).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setObservationPair_default
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets observation pair as given.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setObservationPair_pair(this, iobs1, iobs2)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    INTEGER, INTENT(in)                   :: iobs1, iobs2
+    INTEGER                               :: nobs, err
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (iobs1 <= 0 .OR. iobs2 <= 0 .OR. iobs1 > nobs .OR. iobs2 > nobs &
+         .OR. iobs1 == iobs2) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Unrealistic input values.", 1)
+       RETURN
+    END IF
+    IF (.NOT. this%obs_masks_prm(iobs1,2) .OR. .NOT. this%obs_masks_prm(iobs2,2)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "One or both observations excluded.", 1)
+       RETURN
+    END IF
+    IF (ASSOCIATED(this%sor_pair_arr_prm)) THEN
+       DEALLOCATE(this%sor_pair_arr_prm, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setObservationPair", &
+               "Could not deallocate memory.", 1)
+          RETURN
+       END IF
+    END IF
+    ALLOCATE(this%sor_pair_arr_prm(1,2), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setObservationPair", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    this%sor_pair_arr_prm(1,1) = iobs1
+    this%sor_pair_arr_prm(1,2) = iobs2
+
+  END SUBROUTINE setObservationPair_pair
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets observation pair selection to random selection.
+  !! Constructs a list of possible pairs
+  !! (number of pairs = number of combinations of two).
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setRandomObservationSelection(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    INTEGER, DIMENSION(:,:), POINTER      :: idx_pair
+    INTEGER                               :: err
+
+    IF (.NOT.this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRandomObservationSelection", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%sor_random_obs_prm = .TRUE.
+    CALL makePairsOfObservations(this,idx_pair)
+    DEALLOCATE(this%sor_pair_arr_prm, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRandomObservationSelection", &
+            "Could not deallocate memory (5).", 1)
+       RETURN
+    END IF
+    ALLOCATE(this%sor_pair_arr_prm(SIZE(idx_pair,dim=1), SIZE(idx_pair,dim=2)), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRandomObservationSelection", &
+            "Could not allocate memory.", 1)
+       RETURN
+    END IF
+    this%sor_pair_arr_prm = idx_pair
+    DEALLOCATE(idx_pair, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRandomObservationSelection", &
+            "Could not deallocate memory (10).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setRandomObservationSelection
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Determines the new range bounds from the 3-sigma cutoff values of
+  !! the a posteriori range probability density.
+  !! 
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setRangeBounds_3sigma(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)    :: this
+    REAL(bp), DIMENSION(2)                   :: mean, stdev
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE    :: histo
+    REAL(bp), DIMENSION(:), ALLOCATABLE      :: topo_range
+    REAL(bp), DIMENSION(2,2)                 :: rho_
+    REAL(bp)                                 :: rhomin1, rhomax1, &
+         rhomin2, rhomax2
+    INTEGER                                  :: grid_num, err
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRangeBounds", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    rho_ = this%sor_rho_prm
+    this%sor_rho_histo_cmp = 0
+    grid_num   = 40
+
+    IF (ANY(this%sor_iterate_bounds_prm(1:2))) THEN
+
+       ! Compute mean and std for first topocentric range,
+       ! create histogram:
+       CALL moments(this%sor_rho_arr_cmp(:,1), mean=mean(1), &
+            std_dev=stdev(1), errstr=errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not compute moments (5). " // TRIM(errstr), 1)
+          errstr = ""
+          RETURN
+       END IF
+       rhomin1 = MINVAL(this%sor_rho_arr_cmp(:,1))
+       rhomax1 = MAXVAL(this%sor_rho_arr_cmp(:,1))
+       ALLOCATE(histo(grid_num,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not allocate memory.", 1)
+          RETURN
+       END IF
+       CALL histogram(this%sor_rho_arr_cmp(:,1), histo)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "TRACE BACK", 1)
+          RETURN
+       END IF
+       histo(:,2) = histo(:,2)/MAXVAL(histo(:,2),dim=1)
+       ! Check the end points of the histogram, raise flag if the wings do not
+       ! fall off as expected. Typically, histo_end = 0.3_bp
+       IF (histo(1,2) > histo_end) THEN ! .OR. histo(grid_num,2) > histo_end) THEN
+          this%sor_rho_histo_cmp = 1
+       END IF
+       IF (histo(grid_num,2) > histo_end) THEN
+          this%sor_rho_histo_cmp = this%sor_rho_histo_cmp + 2
+       END IF
+       DEALLOCATE(histo, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+       ! 3-sigma bounds for topocentric ranges:
+       IF (this%sor_iterate_bounds_prm(1)) THEN
+          rho_(1,1) = mean(1) - 3*stdev(1)
+       END IF
+       IF (this%sor_iterate_bounds_prm(2)) THEN
+          rho_(1,2) = mean(1) + 3*stdev(1)
+       END IF
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,2(1X,F10.5))") &
+               "rho1 mean and standard deviation: ", &
+               mean(1), stdev(1)
+       END IF
+
+    END IF
+
+    IF (ANY(this%sor_iterate_bounds_prm(3:4))) THEN
+
+       ! Second topocentric range (with respect to the first)
+       ALLOCATE(topo_range(SIZE(this%sor_rho_arr_cmp,dim=1)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not allocate memory for arrays.", 1)
+          RETURN
+       END IF
+       topo_range = this%sor_rho_arr_cmp(:,2) - this%sor_rho_arr_cmp(:,1)
+       rhomin2 = MINVAL(topo_range)
+       rhomax2 = MAXVAL(topo_range)
+       CALL moments(topo_range, mean=mean(2), std_dev=stdev(2), &
+            errstr=errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not compute moments (10). " // TRIM(errstr), 1)
+          errstr = ""
+          RETURN
+       END IF
+       DEALLOCATE(topo_range, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / setRangeBounds", &
+               "Could not deallocate memory (10).", 1)
+          RETURN
+       END IF
+       ! 3-sigma bounds for topocentric ranges:
+       IF (this%sor_iterate_bounds_prm(3)) THEN
+          rho_(2,1) = mean(2) - 3*stdev(2)
+       END IF
+       IF (this%sor_iterate_bounds_prm(4)) THEN
+          rho_(2,2) = mean(2) + 3*stdev(2)
+       END IF
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,2(1X,F10.5))") &
+               "rho2-rho1 mean and standard deviation: ", &
+               mean(2), stdev(2)
+       END IF
+
+    END IF
+
+    IF (rho_(1,1) < MAX(0.0_bp,this%apriori_rho_min_prm)) THEN
+       rho_(1,1) = MAX(0.0_bp,this%apriori_rho_min_prm)
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,4(1X,F10.5))") &
+            "Updated rho bounds: ", rho_(1,:), rho_(2,:)
+    END IF
+    this%sor_rho_prm = rho_
+
+  END SUBROUTINE setRangeBounds_3sigma
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets new range bounds given the lower and upper values for rho1 and rho2.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setRangeBounds_values(this, rho1_lower, rho1_upper, &
+       rho2_lower, rho2_upper)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    REAL(bp), INTENT(in)                             :: rho1_lower, rho1_upper, &
+         rho2_lower, rho2_upper
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRangeBounds", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%sor_rho_prm(1,1) = rho1_lower
+    this%sor_rho_prm(1,2) = rho1_upper
+    this%sor_rho_prm(2,1) = rho2_lower
+    this%sor_rho_prm(2,2) = rho2_upper
+
+  END SUBROUTINE setRangeBounds_values
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the regularization of the statistical treatment:
+  !! ON (.true.), OFF (.false.). By default, should always
+  !! be ON.
+  !!
+  !!
+  !! Returns error.
+  !!
+
+  SUBROUTINE setRegularization(this,regularization)
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    LOGICAL, INTENT(in)                   :: regularization
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setRegularizationOff", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    this%regularization_prm = regularization
+
+  END SUBROUTINE setRegularization
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the ranging parameters are suitable for TNOs.
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE setTNORanging(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / setTNORanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL setRangeBounds(this, 20.0_bp, 60.0_bp, -1.0_bp, 1.0_bp)
+    CALL setParameters(this, sor_norb=2000, sor_ntrial=1000000)
+    CALL setAcceptanceWindow(this, 4.0_bp)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / setTNORanging", &
+            "TRACE BACK (1", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE setTNORanging
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Minimization of the function func in N dimensions by the
+  !! downhill simplex method of Nelder and Mead. The (N + 1) Ã N
+  !! matrix p is input. Its N + 1 rows are N-dimensional vectors that
+  !! are the vertices of the starting simplex. Also input is the
+  !! vector y of length N + 1, whose components must be preinitialized
+  !! to the values of func evaluated at the N + 1 vertices (rows) of
+  !! p and ftol the fractional convergence tolerance to be achieved in
+  !! the function value (n.b.!). The input value of iter is the
+  !! maximum number of function evaluations, while on output the same
+  !! parameter gives the actual number of function evaluations
+  !! perfomed. Also on output, p and y will have been reset to N+1 new
+  !! points all within this%smplx_tol_prm of a minimum function value.
+  !!
+  !! Parameters: The maximum allowed number of function evaluations,
+  !! and a small number.
+  !!
+  SUBROUTINE simplexOrbits(this, orb_arr)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: this
+    TYPE (Orbit), DIMENSION(:), INTENT(inout) :: orb_arr
+
+    REAL(bp), PARAMETER :: TINY = 1.0e-10_bp
+
+    CHARACTER(len=FRAME_LEN) :: frame
+    REAL(bp), DIMENSION(7,6) :: p, p_init
+    REAL(bp), DIMENSION(7) :: y
+    REAL(bp), DIMENSION(6) :: psum, p_best
+    REAL(bp) :: y_best
+    INTEGER(ibp) :: ihi, ilo, ndim ! Global variables (within this subroutine).  
+    INTEGER :: err, i
+
+    IF (info_verb >= 3) THEN
+       WRITE(stdout,"(2X,A)") "SIMPLEX OPTIMIZATION"
+       WRITE(stdout,"(1X)")
+       WRITE(stdout,"(2X,A)") "Parameters:"
+       WRITE(stdout,"(2X,A,1X,F10.5)") "smplx_tol_prm", this%smplx_tol_prm
+       WRITE(stdout,"(2X,A,1X,L1)") "smplx_force_prm", this%smplx_force_prm
+       WRITE(stdout,"(2X,A,1X,F10.8)") "smplx_similarity_tol_prm", this%smplx_similarity_tol_prm
+       WRITE(stdout,"(2X,A,1X,I0)") "smplx_niter_prm", this%smplx_niter_prm
+    END IF
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / simplexOrbits", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL NULLIFY(this%orb_ml_cmp)
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DO i=1,SIZE(this%orb_arr_cmp)
+          CALL NULLIFY(this%orb_arr_cmp(i))
+       END DO
+       DEALLOCATE(this%orb_arr_cmp, stat=err)
+    END IF
+    IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+    END IF
+
+    frame = getFrame(orb_arr(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / simplexOrbits", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    CALL propagate(orb_arr, this%t_inv_prm)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / simplexOrbits", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    DO i=1,7
+       p(i,1:6) = getElements(orb_arr(i), this%element_type_prm, &
+            frame=frame)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / simplexOrbits", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       p_init(i,1:6) = p(i,1:6)
+       y(i) = getChi2(this, orb_arr(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / simplexOrbits", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+    END DO
+    p_best = p(MINLOC(y,dim=1),:)
+    y_best = MINVAL(y)
+    CALL simplex_private
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / simplexOrbits", &
+            "TRACE BACK (25)", 1)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       DO i=1,7
+          IF (i == ilo) THEN
+             WRITE(stdout,"('ILO:',1X,6(F20.15,1X),1(F25.5,1X))") &
+                  p(i,:), y(i)
+          ELSE IF (i == ihi) THEN
+             WRITE(stdout,"('IHI:',1X,6(F20.15,1X),1(F25.5,1X))") &
+                  p(i,:), y(i)
+          ELSE
+             WRITE(stdout,"(5X,6(F20.15,1X),1(F25.5,1X))") &
+                  p(i,:), y(i)
+          END IF
+       END DO
+       WRITE(stdout,"(1X)")
+    END IF
+    IF (this%smplx_niter_cmp >= this%smplx_niter_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / simplexOrbits", &
+            "Maximum number of iterations exceeded.", 1)
+       RETURN
+    END IF
+    ALLOCATE(this%orb_arr_cmp(7), this%rchi2_arr_cmp(7), stat=err)
+    DO i=1,7
+       CALL NEW(this%orb_arr_cmp(i), p(i,:), this%element_type_prm, &
+            frame, this%t_inv_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / simplexOrbits", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       CALL setParameters(this%orb_arr_cmp(i), &
+            dyn_model=this%dyn_model_prm, &
+            perturbers=this%perturbers_prm, &
+            integrator=this%integrator_prm, &
+            integration_step=this%integration_step_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / simplexOrbits", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       this%rchi2_arr_cmp(i) = y(i) - REAL(COUNT(this%obs_masks_prm),bp)
+    END DO
+    this%orb_ml_cmp = copy(this%orb_arr_cmp(1))
+
+  CONTAINS 
+
+    SUBROUTINE simplex_private 
+
+      IMPLICIT NONE
+      TYPE (Orbit) :: orb
+      REAL(bp), DIMENSION(6) :: ptry_ref, ptry_exp, ptry_co
+      REAL(bp) :: rtol, ytry_ref, ytry_exp, ytry_co, ytmp
+      INTEGER(ibp) :: i, j, inhi
+      LOGICAL :: contraction_successful
+
+      ndim = SIZE(p,dim=2)
+      this%smplx_niter_cmp = 0 
+      psum(:) = SUM(p(:,:),dim=1) 
+      DO !Iteration loop.  
+         ! Determine which point is the highest (worst),
+         ! next-highest, and lowest (best)
+         ilo = iminloc(y(:))
+         ihi = imaxloc(y(:))
+         ytmp = y(ihi) 
+         y(ihi) = y(ilo)
+         inhi = imaxloc(y(:))
+         y(ihi) = ytmp
+         IF (y_best > y(ilo)) THEN
+            p_best = p(ilo,:)
+            y_best = y(ilo)
+         END IF
+         ! Compute the fractional range from highest to lowest and
+         ! reinitialize if very similar values
+         IF (2.0_bp*ABS(y(ihi)-y(ilo))/(ABS(y(ihi))+ABS(y(ilo))+TINY) &
+              < this%smplx_similarity_tol_prm) THEN
+            IF (this%smplx_force_prm) THEN 
+               j = 0
+               DO i=1,ndim+1
+                  IF (i == ilo) THEN
+                     CYCLE
+                  END IF
+                  j = j + 1
+                  CALL NULLIFY(orb_arr(i))
+                  p(i,:) = p(ilo,:)
+                  p(i,j) = p(i,j)*1.1_bp
+                  CALL NEW(orb_arr(i), p(i,:), this%element_type_prm, &
+                       frame, this%t_inv_prm)
+                  CALL setParameters(orb_arr(i), &
+                       dyn_model=this%dyn_model_prm, &
+                       perturbers=this%perturbers_prm, &
+                       integrator=this%integrator_prm, &
+                       integration_step=this%integration_step_prm)
+                  y(i) = getChi2(this, orb_arr(i))
+               END DO
+               IF (error) THEN
+                  CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                       "TRACE BACK (20)", 1)
+                  RETURN
+               END IF
+               ilo = iminloc(y(:))
+               ihi = imaxloc(y(:))
+               ytmp = y(ihi) 
+               y(ihi) = y(ilo)
+               inhi = imaxloc(y(:))
+               y(ihi) = ytmp
+               IF (info_verb >= 2) THEN
+                  WRITE(stdout,"(5X,A)") "Reinitialization performed."
+               END IF
+            ELSE
+               ! If returning, put best point and value in slot 1. 
+               CALL swap(y(1),y(ilo))
+               CALL swap(p(1,:),p(ilo,:)) 
+               ilo = 1
+               RETURN 
+            END IF
+         END IF
+         IF (info_verb >= 4) THEN
+            DO i=1,7
+               IF (i == ilo) THEN
+                  WRITE(stdout,"('ILO:',1X,6(F20.15,1X),1(F15.3,1X))") &
+                       p(i,:), y(i)
+               ELSE IF (i == ihi) THEN
+                  WRITE(stdout,"('IHI:',1X,6(F20.15,1X),1(F15.3,1X))") &
+                       p(i,:), y(i)
+               ELSE
+                  WRITE(stdout,"(5X,6(F20.15,1X),1(F15.3,1X))") &
+                       p(i,:), y(i)
+               END IF
+            END DO
+            WRITE(stdout,"(1X)")
+         END IF
+         rtol = y(ihi)
+         ! return if satisfactory.  
+         IF (this%smplx_force_prm .AND. rtol < this%smplx_tol_prm) THEN 
+            ! If returning, put best point and value in slot 1. 
+            CALL swap(y(1),y(ilo))
+            CALL swap(p(1,:),p(ilo,:)) 
+            ilo = 1
+            RETURN 
+         END IF
+         IF (this%smplx_niter_cmp >= this%smplx_niter_prm) THEN
+            RETURN
+         END IF
+         ! Begin a new iteration. First extrapolate by a factor -1
+         ! through the face of the simplex across from the high
+         ! point, i.e., reflect the simplex from the high point.
+         CALL simtry(this, 1.0_bp, ptry_ref, ytry_ref) ! Reflect
+         IF (error) THEN
+            CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                 "TRACE BACK (30)", 1)
+            RETURN
+         END IF
+         this%smplx_niter_cmp = this%smplx_niter_cmp + 1 
+         IF (ytry_ref >= y(ilo) .AND. ytry_ref < y(inhi)) THEN
+            ! If it's better than the highest, then replace
+            ! the highest.
+            y(ihi) = ytry_ref
+            psum(:) = psum(:) - p(ihi,:) + ptry_ref(:)
+            p(ihi,:) = ptry_ref(:)
+         ELSE IF (ytry_ref < y(ilo)) THEN
+            ! Gives a result better than the best point, so try an
+            ! additional extrapolation by a factor of 2.  
+            CALL simtry(this, 2.0_bp, ptry_exp, ytry_exp) ! Expand
+            IF (error) THEN
+               CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                    "TRACE BACK (35)", 1)
+               RETURN
+            END IF
+            this%smplx_niter_cmp = this%smplx_niter_cmp + 1
+            IF (ytry_exp < ytry_ref) THEN
+               y(ihi) = ytry_exp
+               psum(:) = psum(:) - p(ihi,:) + ptry_exp(:)
+               p(ihi,:) = ptry_exp(:)
+            ELSE
+               y(ihi) = ytry_ref
+               psum(:) = psum(:) - p(ihi,:) + ptry_ref(:)
+               p(ihi,:) = ptry_ref(:)
+            END IF
+         ELSE IF (ytry_ref >= y(inhi)) THEN 
+            ! The reflected point is worse than the second highest,
+            ! so look for an intermediate lower point, i.e., do a
+            ! one-dimensional contraction.
+            contraction_successful = .FALSE.
+            IF (ytry_ref >= y(inhi) .AND. ytry_ref < y(ihi)) THEN
+               CALL simtry(this, 0.5_bp, ptry_co, ytry_co) ! Outside contraction
+               IF (error) THEN
+                  CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                       "TRACE BACK (40)", 1)
+                  RETURN
+               END IF
+               IF (ytry_co < ytry_ref) THEN
+                  y(ihi) = ytry_co
+                  psum(:) = psum(:) - p(ihi,:) + ptry_co(:)
+                  p(ihi,:) = ptry_co(:)
+                  contraction_successful = .TRUE. 
+               END IF
+            ELSE ! ytry_ref >= y(ihi) 
+               CALL simtry(this, -0.5_bp, ptry_co, ytry_co) ! Inside contraction
+               IF (error) THEN
+                  CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                       "TRACE BACK (40)", 1)
+                  RETURN
+               END IF
+               IF (ytry_co < y(ihi)) THEN
+                  y(ihi) = ytry_co
+                  psum(:) = psum(:) - p(ihi,:) + ptry_co(:)
+                  p(ihi,:) = ptry_co(:)
+                  contraction_successful = .TRUE. 
+               END IF
+            END IF
+            this%smplx_niter_cmp = this%smplx_niter_cmp + 1
+            IF (.NOT.contraction_successful) THEN
+               ! Can't seem to get rid of that high point. Better
+               ! contract around the lowest (best) point.
+               p(:,:) = 0.5_bp*(p(:,:) + SPREAD(p(ilo,:),1,SIZE(p,dim=1)))
+               DO i=1,ndim+1
+                  IF (i /= ilo) THEN
+                     IF (this%element_type_prm == "keplerian") THEN
+                        IF (p(i,1) < this%apriori_a_min_prm .OR. &
+                             p(i,1) > this%apriori_a_max_prm .OR. &
+                             p(i,2) < 0.0_bp .OR. &
+                             p(i,2) > 1.0_bp .OR. &
+                             p(i,3) < 0.0_bp .OR. &
+                             p(i,3) > pi) THEN
+                           p(i,:) = p_init(i,:)
+                        END IF
+                        p(i,4:6) = MODULO(p(i,4:6), two_pi)
+                     ELSE IF (this%element_type_prm == "cartesian") THEN
+!!!$                        IF (SQRT(SUM(p(i,1:3)**2)) > this%apriori_hcentric_dist_max_prm .or. &
+!!!$                             SQRT(SUM(p(i,4:6)**2)) > this%apriori_velocity_max_prm) THEN
+!!!$                           p(i,:) = p_init(i,:)
+!!!$                        END IF
+                     END IF
+                     CALL NEW(orb, p(i,:), this%element_type_prm, &
+                          frame, this%t_inv_prm)
+                     IF (error) THEN
+                        CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     CALL setParameters(orb, &
+                          dyn_model=this%dyn_model_prm, &
+                          perturbers=this%perturbers_prm, &
+                          integrator=this%integrator_prm, &
+                          integration_step=this%integration_step_prm)
+                     IF (error) THEN
+                        CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                             "TRACE BACK (45)", 1)
+                        RETURN
+                     END IF
+                     y(i) = getChi2(this, orb)
+                     IF (error) THEN
+                        CALL errorMessage("StochasticOrbit / simplexOrbits / simplex_private", &
+                             "TRACE BACK (50)", 1)
+                        RETURN
+                     END IF
+                     CALL NULLIFY(orb)
+                  END IF
+               END DO
+               this%smplx_niter_cmp = this%smplx_niter_cmp + ndim ! Keep track of function evaluations.
+               psum(:) = SUM(p(:,:),dim=1)
+            END IF
+         END IF
+      END DO ! Go back for the test of doneness and the next iteration.
+
+    END SUBROUTINE simplex_private
+
+
+    !! *Description*:
+    !!
+    !! Extrapolates by a factor fac through the face of the
+    !! simplex across from the high point, tries it, and replaces
+    !! the high point if the new point is better.
+    !!
+    SUBROUTINE simtry(this, fac, ptry, ytry)
+
+      IMPLICIT NONE
+      TYPE (StochasticOrbit), INTENT(in) :: this
+      REAL(bp), INTENT(IN) :: fac
+      REAL(bp), DIMENSION(ndim), INTENT(out) :: ptry 
+      REAL(bp), INTENT(out) :: ytry
+
+      TYPE (Orbit) :: orb
+      REAL(bp) :: ran
+
+      ptry(:) = (1.0_bp+fac)*(psum(:)-p(ihi,:))/ndim - fac*p(ihi,:)
+      ! Evaluate the function at the trial point.
+      IF (this%element_type_prm == "keplerian") THEN
+         IF (ptry(1) < this%apriori_a_min_prm .OR. &
+              ptry(1) > this%apriori_a_max_prm .OR. &
+              ptry(2) < 0.0_bp .OR. &
+              ptry(2) > 1.0_bp .OR. &
+              ptry(3) < 0.0_bp .OR. &
+              ptry(3) > pi) THEN
+            CALL randomNumber(ran)
+            ptry = p_init(1+NINT(6*ran),:)
+         END IF
+         ptry(4:6) = MODULO(ptry(4:6), two_pi)
+      ELSE IF (this%element_type_prm == "cartesian") THEN
+!!$         IF (SQRT(SUM(ptry(1:3)**2)) > this%apriori_hcentric_dist_max_prm .or. &
+!!$              SQRT(SUM(ptry(4:6)**2)) > this%apriori_velocity_max_prm) THEN
+!!$            CALL randomNumber(ran)
+!!$            ptry = p_init(1+NINT(6*(ran)),:)            
+!!$         END IF
+      END IF
+      CALL NEW(orb, ptry, this%element_type_prm, &
+           frame, this%t_inv_prm)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / simplexOrbits / simtry", &
+              "TRACE BACK (55)", 1)
+         RETURN
+      END IF
+      CALL setParameters(orb, &
+           dyn_model=this%dyn_model_prm, &
+           perturbers=this%perturbers_prm, &
+           integrator=this%integrator_prm, &
+           integration_step=this%integration_step_prm)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / simplexOrbits / simtry", &
+              "TRACE BACK (45)", 1)
+         RETURN
+      END IF
+      ytry = getChi2(this, orb)
+      IF (error) THEN
+         CALL errorMessage("StochasticOrbit / simplexOrbits / simtry", &
+              "TRACE BACK (60)", 1)
+         RETURN
+      END IF
+      CALL NULLIFY(orb)
+
+    END SUBROUTINE simtry
+
+  END SUBROUTINE simplexOrbits
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Statistical orbital ranging using two astrometric observations.
+  !! Make use of the multiple orbit propagation scheme. CONTINUE TESTING!
+  !! 
+  !! Output: Probability density function for Cartesian position and
+  !!         velocity at specified epoch in two-body approximation.
+  !!
+  !! Simplified:
+  !!             - No random observation selection
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE statisticalRanging(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)                :: this
+    TYPE (Orbit), DIMENSION(:), POINTER                  :: orb_arr_
+    TYPE (Orbit), DIMENSION(:), POINTER                  :: orb_arr
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER   :: obsies_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: scoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER   :: obs_scoords
+    TYPE (CartesianCoordinates)                          :: obs_ccoord_topo1, &
+         obs_ccoord_helio1, obs_ccoord_topo2, obs_ccoord_helio2
+    TYPE (SphericalCoordinates)                          :: obs_scoord1, &
+         obs_scoord2, obs_scoord_
+    TYPE (Time)                                          :: t1, t2
+    CHARACTER(len=DYN_MODEL_LEN)                         :: dyn_model
+    CHARACTER(len=INTEGRATOR_LEN)                        :: integrator
+    REAL(bp), DIMENSION(:,:,:,:), POINTER                :: partials_arr
+    REAL(bp), DIMENSION(:,:,:), POINTER                  :: cov_matrices, &
+         sphdev
+    REAL(bp), DIMENSION(:,:,:), ALLOCATABLE              :: residuals
+    REAL(bp), DIMENSION(:,:,:), POINTER                  :: information_matrix_obs
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE                :: rms, &
+         rho_distribution, jacobians
+    REAL(bp), DIMENSION(:), POINTER                      :: rho1, rho2, mjd_lt
+    REAL(bp), DIMENSION(:), ALLOCATABLE                  :: cosdec0_arr, &
+         pdf_arr, reg_apriori_arr, rchi2_arr, residual_vector
+    REAL(bp), DIMENSION(6,6)                             :: information_matrix_elem, &
+         jacobian_matrix
+    REAL(bp), DIMENSION(6,2)                             :: bounds
+    REAL(bp), DIMENSION(6)                               :: observed_coord, &
+         computed_coord, elements
+    REAL(bp), DIMENSION(3)                               :: position1, &
+         position2, acc, r_ra_dec
+    REAL(bp)                                             :: pdf_val, &
+         apriori, jac_sph_inv, rho_comp1, rho_comp2, tdt, &
+         rho_mid, a, ran, tmp, chi2, dchi2, integration_step, &
+         trials_per_orb, jac_car_kep, jac_equ_kep, obs_arc, &
+         rang, distance, q, ftol
+    INTEGER, DIMENSION(:,:), POINTER                     :: obs_pair_arr
+    INTEGER, DIMENSION(:), ALLOCATABLE                   :: pair_histogram
+    INTEGER, DIMENSION(6)                                :: n0, n0_
+    INTEGER, DIMENSION(7)                                :: failed_flag
+    INTEGER                                              :: err, i, j, k, &
+         nobs, iorb, itrial, nobj, ncomb, ipair, err_verb_, &
+         naccepted, norb
+    LOGICAL, DIMENSION(:,:), ALLOCATABLE                 :: maskarr
+    LOGICAL                                              :: first
+    CHARACTER(len=DESIGNATION_LEN)                       :: object_id
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nobj = getNrOfObjects(this%obss)
+    IF (nobj > 1 .AND. .NOT.this%multiple_obj_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "More than one object!", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    IF (nobs < 2) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Less than two observations available.", 1)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%sor_deviates_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Generation window not set.", 1)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%res_accept_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Window for accepted residuals not set.", 1)
+       RETURN
+    END IF
+    IF (ALL(this%sor_rho_prm < 0.0_bp)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Topocentric range intervals not set.", 1)
+       RETURN
+    END IF
+    IF (.NOT.ASSOCIATED(this%sor_pair_arr_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Observation pair not set.", 1)
+       RETURN
+    END IF
+    IF (this%sor_norb_prm < 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Required number of sample orbits not set.", 1)
+       RETURN
+    END IF
+
+    IF (this%chi2_min_prm < 0.0_bp) THEN
+       first = .TRUE.
+       IF (this%chi2_min_init_prm <= 0.0_bp) THEN
+          this%chi2_min_prm = REAL(COUNT(this%obs_masks_prm),bp)
+       ELSE
+          this%chi2_min_prm = this%chi2_min_init_prm
+       END IF
+    ELSE
+       first = .FALSE.
+    END IF
+    IF (.NOT.exist(this%t_inv_prm)) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Inversion epoch not set.", 1)
+       RETURN
+    END IF
+
+    CALL getParameters(this, &
+         dyn_model=dyn_model, &
+         integration_step=integration_step, &
+         integrator=integrator)!, &
+    !         finite_diff=finite_diff)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+
+    IF (integrator == "gauss-radau" .AND. dyn_model /= "2-body") THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Cannot use variational-equations approach for "//TRIM(integrator), 1)
+       RETURN
+    END IF
+
+    object_id = getID(this%obss)
+    obs_arc   = getObservationalTimespan(this%obss)
+
+    ! ------------
+    ! Initializing
+    ! ------------
+
+    ALLOCATE(orb_arr_(this%sor_norb_prm), &
+         rho_distribution(this%sor_norb_prm,2), &
+         residuals(this%sor_norb_prm,nobs,6), &
+         pdf_arr(this%sor_norb_prm), &
+         reg_apriori_arr(this%sor_norb_prm), &
+         jacobians(this%sor_norb_prm,3), &
+         rchi2_arr(this%sor_norb_prm), &
+         rms(this%sor_norb_prm,6), &
+         pair_histogram(SIZE(this%sor_pair_arr_prm,1)), &
+         cosdec0_arr(nobs), &
+         residual_vector(nobs*6), &
+         maskarr(nobs,6), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "Could not allocate memory (1).", 1)
+       RETURN
+    END IF
+    pdf_arr              = 0.0_bp
+    rho_distribution = 0.0_bp
+    residuals        = 0.0_bp
+    reg_apriori_arr      = 0.0_bp
+    jacobians        = 0.0_bp
+    rms              = 0.0_bp
+    rchi2_arr           = 0.0_bp
+    pair_histogram   = 0
+    acc              = 0.0_bp
+
+    this%sor_rho_cmp(:,1) = HUGE(this%sor_rho_cmp)
+    this%sor_rho_cmp(:,2) = -HUGE(this%sor_rho_cmp)
+
+    ! Spherical toposentric observation coordinates:
+    obs_scoords => getObservationSCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (20)", 1)
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       RETURN
+    END IF
+
+    information_matrix_obs => getBlockDiagInformationMatrix(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (30)", 1)
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       RETURN
+    END IF
+
+    cov_matrices => getCovarianceMatrices(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (35)", 1)
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(cov_matrices, stat=err)
+       RETURN
+    END IF
+
+    ! Observation number counter (observation mask must be up-to-date!), 
+    ! construct cosine array:
+    DO i=1,6
+       n0(i) = COUNT(this%obs_masks_prm(:,i))
+    END DO
+
+    DO i=1,nobs
+       CALL rotateToEquatorial(obs_scoords(i))
+       r_ra_dec = getPosition(obs_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / statisticalRanging", &
+               "TRACE BACK (40)", 1) 
+          DO j=1,SIZE(orb_arr_)
+             CALL NULLIFY(orb_arr_(j))
+          END DO
+          DEALLOCATE(orb_arr_, stat=err)
+          DEALLOCATE(rho_distribution, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms, stat=err)
+          DEALLOCATE(pair_histogram, stat=err)
+          DEALLOCATE(cosdec0_arr, stat=err)
+          DEALLOCATE(residual_vector, stat=err)
+          DEALLOCATE(maskarr, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(cov_matrices, stat=err)
+          RETURN
+       END IF
+       cosdec0_arr(i) = COS(r_ra_dec(3))
+    END DO
+
+    ! Extract equatorial observatory coordinates
+    obsies_ccoords => getObservatoryCCoords(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "TRACE BACK (45)", 1)
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(cov_matrices, stat=err)
+       DEALLOCATE(obsies_ccoords, stat=err)
+       RETURN
+    END IF
+
+    IF (info_verb >= 1) THEN
+       IF (.NOT.this%dchi2_rejection_prm) THEN
+          WRITE(stdout,"(2X,A)") "WARNING: NOT using dchi2 in acceptance!"
+       END IF
+       IF (.NOT.this%regularization_prm) THEN
+          WRITE(stdout,"(2X,A)") "WARNING: REGULARIZATION is OFF!"
+       END IF
+       IF (.NOT.this%jacobians_prm) THEN
+          WRITE(stdout,"(2X,A)") "WARNING: JACOBIANS are NOT USED!"
+       END IF
+    END IF
+
+    IF (first .AND. info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "- - - - - - - - - - - - ------------"
+       WRITE(stdout,"(2X,A)") "STARTING MULTI-ORBIT RANGING . . . ."
+       WRITE(stdout,"(2X,A)") "- - - - - - - - - - - - ------------"
+       WRITE(stdout,"(1X)")
+       WRITE(stdout,"(2X,A,A)")     "ID                      : ", &
+            TRIM(object_id)
+       !WRITE(stdout,"(2X,A,1X,I0)") "Nr of observations     :", &
+       !     nobs
+       WRITE(stdout,"(2X,A,1X,I0,A,I0,A,I0)") "Nr of incl. observations :", &
+            n0(2),'+',n0(3),'/',nobs
+       WRITE(stdout,"(2X,A,1X,F10.4,A)") "Observational time arc   :", &
+            obs_arc," days"
+       WRITE(stdout,"(2X,A)") "OPTIONS:"
+       IF (.NOT. this%sor_random_obs_prm) THEN
+          WRITE(stdout,"(2X,A,2(1X,I0))") "Observation pair used    :", &
+               this%sor_pair_arr_prm
+       ELSE 
+          WRITE(stdout,"(2X,A)") "Random observation selection is used."
+       END IF
+       WRITE(stdout,"(2X,A,1X,I0)") "Nr of sample orbits      :", &
+            this%sor_norb_prm
+       WRITE(stdout,"(2X,A)") "Stdevs (R.A. & Dec. [arcsec]) and correlation :"
+       DO i=1,nobs
+          WRITE(stdout,"(4X,3(3X,F12.7))") &
+               SQRT(cov_matrices(i,2,2))/rad_asec, &
+               SQRT(cov_matrices(i,3,3))/rad_asec, &
+               cov_matrices(i,2,3) / &
+               SQRT(cov_matrices(i,2,2))*SQRT(cov_matrices(i,3,3))
+
+       END DO
+       WRITE(stdout,"(2X,A,A,A)") "PDF evaluated in ", &
+            TRIM(this%element_type_prm)," elements"
+       IF (.NOT.this%dchi2_rejection_prm) THEN
+          WRITE(stdout,"(2X,A)") "NOT using dchi2 in acceptance!"
+       ENDIF
+       IF (.NOT. this%regularization_prm) WRITE(stdout,"(2X,A)",advance="no") "NOT"
+       WRITE(stdout,"(2X,A,L2)") "Using regularization by Jeffreys"
+       WRITE(stdout,"(2X,A,A)") "Epoch                   : ", &
+            TRIM(getCalendarDateString(this%t_inv_prm,"tdt"))
+       WRITE(stdout,'(2X,A,E10.4)') "Initial minimum chi2     : ", &
+            this%chi2_min_prm
+       WRITE(stdout,"(2X,A,A,A)") "Using ",TRIM(dyn_model)," dynamical model"
+       WRITE(stdout,"(2X,A,A,A)") "Using ", &
+            TRIM(this%sor_2point_method_prm), " method"
+       IF (this%sor_gaussian_pdf_prm) THEN
+          WRITE(stdout,"(2X,A)") "Using Gaussian deviate for rho!"
+       END IF
+       WRITE(stdout,"(2X,A,4(1X,E10.4))") "Initial rho bounds (AU) :", &
+            this%sor_rho_prm(1,1:2), this%sor_rho_prm(2,1:2)
+
+       WRITE(stdout,"(1X)")
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A)") "Observations in MPC format: "
+          CALL writeObservationFile(this%obss, stdout, "mpc")
+          WRITE(stdout,"(2X,A)") "Generation window for each observation in seconds of arc"
+          WRITE(stdout,"(2X,A)") "(RA_mean, RA_abs, Dec_mean, Dec_abs):"
+          IF (.NOT. this%sor_random_obs_prm) THEN
+             DO i=1,2
+                j = this%sor_pair_arr_prm(1,i)
+                WRITE(stdout,"(2X,A,I0,A,4(1X,F10.5))") "", j, ". obs:", &
+                     this%sor_deviates_prm(j,2,1)/rad_asec, &
+                     this%sor_deviates_prm(j,2,2)/rad_asec, &
+                     this%sor_deviates_prm(j,3,1)/rad_asec, &
+                     this%sor_deviates_prm(j,3,2)/rad_asec
+             END DO
+          ELSE
+             DO i=1,nobs
+                WRITE(stdout,"(2X,A,I0,A,4(1X,F10.5))") "", i, ". obs:", &
+                     this%sor_deviates_prm(i,2,1)/rad_asec, &
+                     this%sor_deviates_prm(i,2,2)/rad_asec, &
+                     this%sor_deviates_prm(i,3,1)/rad_asec, &
+                     this%sor_deviates_prm(i,3,2)/rad_asec
+             END DO
+          ENDIF
+          WRITE(stdout,"(2X,A)") "Accepted residual window for each observation in seconds of arc"
+          WRITE(stdout,"(2X,A)") "(RA_min, RA_max, Dec_min, Dec_max):"
+          DO i=1,nobs
+             WRITE(stdout,"(2X,A,I0,A,4(1X,F10.5))") "", i, ". obs:", &
+                  -this%res_accept_prm(i,2)/rad_asec, &
+                  this%res_accept_prm(i,2)/rad_asec, &
+                  -this%res_accept_prm(i,3)/rad_asec, &
+                  this%res_accept_prm(i,3)/rad_asec
+          END DO
+          DO i=1,nobs
+             WRITE(stdout,"(2X,A,I0,A)") "Covariance matrix for ", i, &
+                  ". observation: "
+             CALL matrix_print(cov_matrices(i,:,:)/rad_asec**2.0_bp, &
+                  stdout, errstr)
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "Could not print covariance matrix " // &
+                     TRIM(errstr), 1) 
+                RETURN
+             END IF
+          END DO
+          WRITE(stdout,"(2X,A,6(I0,1X))") "Number of included observations " // &
+               "(r,ra,dec,dr,dra,ddec): ", n0(1:6)
+       END IF
+    END IF
+
+    !------------------------
+    ! Monte Carlo selection :
+    !------------------------
+
+    iorb        = 0
+    itrial      = 0
+    trials_per_orb = 1.0_bp
+    failed_flag = 0
+    norb = 10*this%sor_norb_prm
+    IF (norb > norb_simult_max) THEN
+       norb = norb_simult_max
+    END IF
+
+    sor_main: DO WHILE (iorb < this%sor_norb_prm .AND. itrial < this%sor_ntrial_prm)
+
+       naccepted = 0
+       IF (.NOT.ASSOCIATED(orb_arr)) THEN
+          ALLOCATE(orb_arr(norb), obs_pair_arr(norb,2), rho1(norb), &
+               rho2(norb), sphdev(norb,2,3), mjd_lt(norb), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "Could not allocate memory (10).", 1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             RETURN
+          END IF
+       END IF
+
+       i = 0
+       sor_orb_gen: DO WHILE (i < norb .AND. itrial < this%sor_ntrial_prm)
+
+          itrial = itrial + 1
+          CALL NULLIFY(orb_arr(i+1))
+          CALL NULLIFY(obs_ccoord_topo1)
+          CALL NULLIFY(obs_ccoord_helio1)
+          CALL NULLIFY(obs_ccoord_topo2)
+          CALL NULLIFY(obs_ccoord_helio2)
+          CALL NULLIFY(obs_scoord1)
+
+          ! Random selection of observation pair
+          IF (this%sor_random_obs_prm) THEN
+             ncomb = SIZE(this%sor_pair_arr_prm,1)
+             CALL randomNumber(ran)
+             ipair = INT(ran*ncomb)+1
+             obs_pair_arr(i+1,1:2) = this%sor_pair_arr_prm(ipair,1:2)
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,2(1X,I0))") &
+                     "Random observation pair used:", obs_pair_arr(i+1,1:2)
+             END IF
+             ! Use predefined observation pair if not using random selection
+          ELSE
+             obs_pair_arr(i+1,1:2) = RESHAPE(this%sor_pair_arr_prm, (/ 2/))
+          END IF
+          obs_scoord1 = copy(obs_scoords(obs_pair_arr(i+1,1)))
+          sphdev(i+1,1,:) = getPosition(obs_scoord1)
+
+          ! Generate topocentric ranges and add deviates 
+          ! to angular coordinates:
+          bounds = 0.0_bp
+          bounds(1,1) = 0.5_bp*(this%sor_rho_prm(1,1) + this%sor_rho_prm(1,2))
+          bounds(1,2) = 0.5_bp*ABS(this%sor_rho_prm(1,2) - this%sor_rho_prm(1,1))
+          bounds(2:3,1:2) = this%sor_deviates_prm(obs_pair_arr(i+1,1),2:3,1:2)
+          CALL addUniformDeviate(obs_scoord1, bounds)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (50)", 1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             RETURN
+          END IF
+          IF (this%sor_gaussian_pdf_prm) THEN
+             obs_scoord_ = copy(obs_scoord1)
+             CALL randomGaussian(rang)
+             distance = this%sor_rho_prm(1,1) + rang*this%sor_rho_prm(1,2)
+             CALL NULLIFY(obs_scoord1)
+             CALL NEW(obs_scoord1, distance, getLongitude(obs_scoord_), &
+                  getLatitude(obs_scoord_), getTime(obs_scoord_))
+             CALL NULLIFY(obs_scoord_)
+          END IF
+
+          ! addUniformDeviate does not return the actual deviations,
+          ! accuracies computed in the end ar wrong!
+          sphdev(i+1,1,:) = getPosition(obs_scoord1) - sphdev(i+1,1,:)
+          sphdev(i+1,1,2) = sphdev(i+1,1,2)*cosdec0_arr(obs_pair_arr(i+1,1))
+          rho1(i+1) = getDistance(obs_scoord1)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (55)", 1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             RETURN
+          END IF
+          IF (rho1(i+1) <= planetary_radii(3)) THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,F10.7,A)") &
+                     "Failed (rho1 smaller than the Earth radius: ", &
+                     rho1(i+1), " AU)"
+             END IF
+             CYCLE
+          END IF
+          rho_mid = 0.5_bp*(this%sor_rho_prm(2,1) + this%sor_rho_prm(2,2))
+          bounds(1,1) = rho1(i+1) + rho_mid 
+          IF (bounds(1,1) <= planetary_radii(3)) THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,F10.7,A)") &
+                     "Failed (Mean of rho2 smaller than the Earth radius: ", &
+                     bounds(1,1), " AU)"
+             END IF
+             CYCLE sor_orb_gen
+          END IF
+          bounds(2:3,1:2) = this%sor_deviates_prm(obs_pair_arr(i+1,2),2:3,1:2)
+          rho2(i+1) = 0.0_bp
+          ! Make sure rho2 is larger than zero length units
+          DO WHILE (rho2(i+1) <= EPSILON(rho2(i+1)))
+             bounds(1,2) = 0.5_bp*ABS(this%sor_rho_prm(2,2) - this%sor_rho_prm(2,1))
+             CALL NULLIFY(obs_scoord2)
+             obs_scoord2 = copy(obs_scoords(obs_pair_arr(i+1,2)))
+             sphdev(i+1,2,:) = getPosition(obs_scoord2)
+             CALL addUniformDeviate(obs_scoord2, bounds)
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (60)", 1)
+                DO i=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(i))
+                END DO
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                CALL NULLIFY(obs_scoord1)
+                CALL NULLIFY(obs_scoord2)
+                RETURN
+             END IF
+
+             IF (this%sor_gaussian_pdf_prm) THEN
+                obs_scoord_ = copy(obs_scoord2)
+                CALL randomGaussian(rang)
+                distance = rho1(i+1) + rang*this%sor_rho_prm(2,2)
+                CALL NULLIFY(obs_scoord2)
+                CALL NEW(obs_scoord2, distance, getLongitude(obs_scoord_), &
+                     getLatitude(obs_scoord_), getTime(obs_scoord_))
+             END IF
+
+             rho2(i+1) = getDistance(obs_scoord2)
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (65)", 1)
+                DO i=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(i))
+                END DO
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                CALL NULLIFY(obs_scoord1)
+                CALL NULLIFY(obs_scoord2)
+                RETURN
+             END IF
+          END DO
+          sphdev(i+1,2,:) = getPosition(obs_scoord2) - sphdev(i+1,2,:)
+          sphdev(i+1,2,2) = sphdev(i+1,2,2)*cosdec0_arr(obs_pair_arr(i+1,2))
+          IF (info_verb >= 5) THEN
+             WRITE(stdout,"(2X,A,1X,2(F15.10,1X))") &
+                  "Generated ranges are ", rho1(i+1), rho2(i+1)
+          END IF
+
+          CALL NEW(obs_ccoord_topo1, obs_scoord1)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (70)",1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             CALL NULLIFY(obs_scoord2)
+             CALL NULLIFY(obs_ccoord_topo1)
+             RETURN
+          END IF
+
+          CALL rotateToEcliptic(obs_ccoord_topo1)
+          IF (info_verb >= 5) THEN
+             position1 = getPosition(obs_scoord1)
+             position2 = getPosition(obs_scoords(obs_pair_arr(i+1,1)))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (75)",1)
+                DO i=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(i))
+                END DO
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                CALL NULLIFY(obs_scoord1)
+                CALL NULLIFY(obs_scoord2)
+                CALL NULLIFY(obs_ccoord_topo1)
+                RETURN
+             END IF
+             WRITE(stdout,"(2X,A,1X,2(F15.10,1X))") &
+                  "Spurious coordinates - Original observation 1:", & 
+                  (position1(2:3)-position2(2:3))/rad_asec * &
+                  cosdec0_arr(obs_pair_arr(i+1,1))
+          END IF
+
+          CALL NEW(obs_ccoord_topo2, obs_scoord2)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (80)",1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             CALL NULLIFY(obs_scoord2)
+             CALL NULLIFY(obs_ccoord_topo1)
+             CALL NULLIFY(obs_ccoord_topo2)
+             RETURN
+          END IF
+          CALL rotateToEcliptic(obs_ccoord_topo2)
+          IF (info_verb >= 5) THEN
+             position1 = getPosition(obs_scoord2)
+             position2 = getPosition(obs_scoords(obs_pair_arr(i+1,2)))
+             WRITE(stdout,"(2X,A,1X,2(F15.10,1X))") &
+                  "Spurious coordinates - Original observation 2:", &
+                  (position1(2:3)-position2(2:3))/rad_asec * &
+                  cosdec0_arr(obs_pair_arr(i+1,1))
+             position1 = getPosition(obs_ccoord_topo2)
+             WRITE(stdout,"(2X,A,1X,3(F15.10,1X))") &
+                  "Cartesian coordinates, topocentric ecliptic 2:", position1
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (85)",1)
+                DO i=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(i))
+                END DO
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                CALL NULLIFY(obs_scoord1)
+                CALL NULLIFY(obs_scoord2)
+                CALL NULLIFY(obs_ccoord_topo1)
+                CALL NULLIFY(obs_ccoord_topo2)
+                RETURN
+             END IF
+          END IF
+
+          ! Ecliptic observatory coordinates
+          CALL rotateToEcliptic(obsies_ccoords(obs_pair_arr(i+1,1)))
+          CALL rotateToEcliptic(obsies_ccoords(obs_pair_arr(i+1,2)))
+
+          ! Cartesian heliocentric coordinates:
+          obs_ccoord_helio1 = &
+               copy(obsies_ccoords(obs_pair_arr(i+1,1)) + obs_ccoord_topo1)
+          obs_ccoord_helio2 = &
+               copy(obsies_ccoords(obs_pair_arr(i+1,2)) + obs_ccoord_topo2)
+
+          IF (info_verb >= 5) THEN
+             t1 = getTime(obsies_ccoords(obs_pair_arr(i+1,1)))
+             t2 = getTime(obs_ccoord_topo1)
+             WRITE(stdout,"(2X,A,2(1X,F15.7))") &
+                  "Heliocentric times 1:", &
+                  getMJD(t1,"tdt"), getMJD(t2,"tdt")
+             position1 = getPosition(obs_ccoord_helio1)
+             position2 = getPosition(obsies_ccoords(obs_pair_arr(i+1,1)))
+             WRITE(stdout,"(2X,A,1X,3(F15.10,1X))") &
+                  "Heliocentric coordinates for observatory 1", position2
+             CALL NULLIFY(t1)
+             CALL NULLIFY(t2)
+          END IF
+
+          ! ------------------------------------------------
+          ! Cartesian ecliptic position and velocity from 
+          ! two cartesian ecliptic coordinates. P-iteration.
+          ! ------------------------------------------------
+
+          CALL estimateLightTime(obs_ccoord_helio1, rho1(i+1))
+          CALL estimateLightTime(obs_ccoord_helio2, rho2(i+1))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (90)",1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             CALL NULLIFY(obs_scoord2)
+             CALL NULLIFY(obs_ccoord_topo1)
+             CALL NULLIFY(obs_ccoord_topo2)
+             CALL NULLIFY(obs_ccoord_helio1)
+             CALL NULLIFY(obs_ccoord_helio2)
+             RETURN
+          END IF
+          t1 = getTime(obs_ccoord_helio1)
+          mjd_lt(i+1) = getMJD(t1,"TDT")
+          CALL NULLIFY(t1)
+          t1 = getTime(obs_scoords(obs_pair_arr(i+1,1)))
+
+          IF (info_verb >= 5) THEN
+             !             t2 = getTime(obs_ccoord_helio2)
+             !             tdt = getMJD(t2,"TDT")
+             WRITE(stdout,"(2X,A,1X,F15.7)") "lt-time 1", mjd_lt(i+1)
+             !             t1 = getTime(obs_scoords(obs_pair_arr(i+1,2)))
+             !             t1 = getTime(obs_scoords(obs_pair_arr(i+1,1)))
+             tdt = getMJD(t1,"TDT")
+             WRITE(stdout,"(2X,A,1X,F15.7)") "original time 1", tdt
+          END IF
+
+          IF (this%sor_2point_method_prm == "n-body amoeba") THEN
+             ! The tolerance is equal to one tenth of the tranverse
+             ! uncertainty bounds (assuming that the transverse
+             ! uncertainty is very small as compared to the
+             ! topocentric distance of the object):
+             position1 = getPosition(obs_scoord1)
+             ftol = 0.05_bp * position1(1) * &
+                  SQRT(SUM(ABS(bounds(2,1:2)))**2 + SUM(ABS(bounds(3,1:2)))**2)
+          END IF
+
+          ! Do not show errors:
+          err_verb_ = err_verb
+          err_verb = 0
+          ! Find orbit candidate at the epoch of the first observation by
+          ! using the chosen method to solve the 2-point boundary value
+          ! problem:
+          CALL NEW(orb_arr(i+1), obs_ccoord_helio1, obs_ccoord_helio2, &
+               this%sor_2point_method_prm, this%apriori_a_max_prm, &
+               ftol=ftol, perturbers=this%perturbers_prm, &
+               integrator=this%integrator_prm, &
+               integration_step=this%integration_step_prm)
+          err_verb = err_verb_
+          IF (error) THEN
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A)") "Failed solving 2-point boundary value problem." 
+             END IF
+             failed_flag(1) = failed_flag(1) + 1
+             error = .FALSE.
+             CYCLE sor_orb_gen
+          END IF
+
+          IF (this%informative_apriori_prm) THEN
+             ! Semimajor axis:
+             a = -1.0_bp
+             IF (this%apriori_a_min_prm >= 0.0_bp .OR. &
+                  this%apriori_a_max_prm >= 0.0_bp) THEN
+                a = getSemimajorAxis(orb_arr(i+1))
+                IF (this%apriori_a_min_prm >= 0.0_bp .AND. &
+                     a < this%apriori_a_min_prm) THEN
+                   ! Semimajor axis too small
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F13.7,A)") &
+                           "Failed (semimajor axis too small: ", a, " AU)"
+                   END IF
+                   failed_flag(2) = failed_flag(2) + 1
+                   CYCLE sor_orb_gen
+                END IF
+                IF (this%apriori_a_max_prm >= 0.0_bp .AND. &
+                     a > this%apriori_a_max_prm) THEN
+                   ! Semimajor axis too large
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F10.7,A)") &
+                           "Failed (semimajor axis too large: ", a, " AU)"
+                   END IF
+                   failed_flag(3) = failed_flag(3) + 1
+                   CYCLE sor_orb_gen
+                END IF
+             END IF
+             ! Periapsis distance:
+             IF (this%apriori_periapsis_min_prm >= 0.0_bp .OR. &
+                  this%apriori_periapsis_max_prm >= 0.0_bp) THEN
+                IF (a >= 0.0_bp) THEN
+                   CALL getPeriapsisDistance(orb_arr(i+1), q, a)
+                ELSE
+                   CALL getPeriapsisDistance(orb_arr(i+1), q)
+                END IF
+                IF (error) THEN
+                   !call errorMessage("StochasticOrbit / statisticalRanging", &
+                   !     "Error when computing periapsis distance.", 1)
+                   !return
+                   ! q not computed as orbit is hyperbolic
+                   error = .FALSE.
+                   CYCLE sor_orb_gen
+                END IF
+                ! Periapsis distance too small:
+                IF (this%apriori_periapsis_min_prm >= 0.0_bp .AND. &
+                     q < this%apriori_periapsis_min_prm) THEN
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F13.7,A)") &
+                           "Failed (periapsis distance too small: ", a, " AU)"
+                   END IF
+                   failed_flag(4) = failed_flag(4) + 1
+                   CYCLE sor_orb_gen
+                END IF
+                ! Periapsis distance too large:
+                IF (this%apriori_periapsis_max_prm >= 0.0_bp .AND. &
+                     q > this%apriori_periapsis_max_prm) THEN
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F10.7,A)") &
+                           "Failed (periapsis distance too large: ", a, " AU)"
+                   END IF
+                   failed_flag(5) = failed_flag(5) + 1
+                   CYCLE sor_orb_gen
+                END IF
+             END IF
+             ! Apoapsis distance:
+             IF (this%apriori_apoapsis_min_prm >= 0.0_bp .OR. &
+                  this%apriori_apoapsis_max_prm >= 0.0_bp) THEN
+                IF (a >= 0.0_bp) THEN
+                   CALL getApoapsisDistance(orb_arr(i+1), Q, a)
+                ELSE
+                   CALL getApoapsisDistance(orb_arr(i+1), Q)
+                END IF
+                ! Apoapsis distance too small:
+                IF (this%apriori_apoapsis_min_prm >= 0.0_bp .AND. &
+                     Q < this%apriori_apoapsis_min_prm) THEN
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F13.7,A)") &
+                           "Failed (apoapsis distance too small: ", a, " AU)"
+                   END IF
+                   failed_flag(4) = failed_flag(4) + 1
+                   CYCLE sor_orb_gen
+                END IF
+                ! Apoapsis distance too large:
+                IF (this%apriori_apoapsis_max_prm >= 0.0_bp .AND. &
+                     Q > this%apriori_apoapsis_max_prm) THEN
+                   IF (info_verb >= 5) THEN
+                      WRITE(stdout,"(2X,A,F10.7,A)") &
+                           "Failed (apoapsis distance too large: ", a, " AU)"
+                   END IF
+                   failed_flag(5) = failed_flag(5) + 1
+                   CYCLE sor_orb_gen
+                END IF
+             END IF
+          END IF
+
+          ! Propagate orbits first individually to a close-by joint epoch.
+          CALL setParameters(orb_arr(i+1), &
+               dyn_model=dyn_model, &
+               perturbers=this%perturbers_prm, &
+               integration_step=integration_step, &
+               integrator=integrator)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (101)",1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             CALL NULLIFY(obs_scoord1)
+             CALL NULLIFY(obs_scoord2)
+             CALL NULLIFY(obs_ccoord_topo1)
+             CALL NULLIFY(obs_ccoord_topo2)
+             CALL NULLIFY(obs_ccoord_helio1)
+             CALL NULLIFY(obs_ccoord_helio2)
+             RETURN
+          END IF
+          CALL propagate(orb_arr(i+1), t1)
+          IF (error) THEN 
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (95)",1)
+             error = .FALSE.
+             CYCLE sor_orb_gen
+          END IF
+
+          ! To allow comparison (e.g., derivatives) against the old code
+          IF (TRIM(this%element_type_prm) == "keplerian") THEN
+             CALL toKeplerian(orb_arr(i+1))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "Failed to change to Keplerian elements.",1)
+                DO i=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(i))
+                END DO
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                CALL NULLIFY(obs_scoord1)
+                CALL NULLIFY(obs_scoord2)
+                CALL NULLIFY(obs_ccoord_topo1)
+                CALL NULLIFY(obs_ccoord_topo2)
+                CALL NULLIFY(obs_ccoord_helio1)
+                CALL NULLIFY(obs_ccoord_helio2)
+                RETURN
+             END IF
+          ELSE
+             CALL rotateToEquatorial(orb_arr(i+1))
+          END IF
+          i = i + 1
+       END DO sor_orb_gen
+       CALL NULLIFY(obs_scoord1)
+       CALL NULLIFY(obs_scoord2)
+       CALL NULLIFY(obs_ccoord_topo1)
+       CALL NULLIFY(obs_ccoord_topo2)
+       CALL NULLIFY(obs_ccoord_helio1)
+       CALL NULLIFY(obs_ccoord_helio2)
+
+       IF (i < norb .AND. i /= 0) THEN
+          ! All trials used without finding required number of orbits: 
+          norb = i
+          orb_arr => reallocate(orb_arr,norb)
+          obs_pair_arr => reallocate(obs_pair_arr,norb,2)
+          rho1 => reallocate(rho1,norb)
+          rho2 => reallocate(rho2,norb)
+          sphdev => reallocate(sphdev,norb,2,3)
+          mjd_lt => reallocate(mjd_lt,norb)
+       ELSE IF (i == 0) THEN
+          ! All trials used and no orbits found:
+          EXIT sor_main
+       END IF
+
+       ! Orbital elements at the specified epoch:
+       ! DO THE MAIN PROPAGATION TO THE DESIRED EPOCH HERE
+       CALL propagate(orb_arr, this%t_inv_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / statisticalRanging", &
+               "TRACE BACK (105)",1)
+          DO i=1,SIZE(orb_arr_)
+             CALL NULLIFY(orb_arr_(i))
+          END DO
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr_, stat=err)
+          DEALLOCATE(rho_distribution, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms, stat=err)
+          DEALLOCATE(pair_histogram, stat=err)
+          DEALLOCATE(cosdec0_arr, stat=err)
+          DEALLOCATE(residual_vector, stat=err)
+          DEALLOCATE(maskarr, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(cov_matrices, stat=err)
+          DEALLOCATE(obsies_ccoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(obs_pair_arr, stat=err)
+          DEALLOCATE(rho1, stat=err)
+          DEALLOCATE(rho2,stat=err)
+          DEALLOCATE(sphdev, stat=err)
+          DEALLOCATE(mjd_lt, stat=err)
+          RETURN
+       END IF
+
+       ! ---------------------------------------------
+       ! Topocentric positions and partial derivatives
+       ! in two-body approximation.
+       ! ---------------------------------------------
+
+       ! Compute residuals and PDF value (via chi2) in order to either
+       ! accept the orbit or discard it:
+       IF (ASSOCIATED(scoords)) THEN
+          DEALLOCATE(scoords, stat=err)
+       END IF
+       IF (this%regularization_prm .OR. this%jacobians_prm) THEN
+          IF (ASSOCIATED(partials_arr)) THEN
+             DEALLOCATE(partials_arr, stat=err)
+          END IF
+          CALL getEphemerides(orb_arr, obsies_ccoords, scoords, &
+               partials_arr=partials_arr)
+       ELSE
+          CALL getEphemerides(orb_arr, obsies_ccoords, scoords)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / statisticalRanging", &
+               "TRACE BACK (110)", 1)
+          DO i=1,SIZE(orb_arr_)
+             CALL NULLIFY(orb_arr_(i))
+          END DO
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr_, stat=err)
+          DEALLOCATE(rho_distribution, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms, stat=err)
+          DEALLOCATE(pair_histogram, stat=err)
+          DEALLOCATE(cosdec0_arr, stat=err)
+          DEALLOCATE(residual_vector, stat=err)
+          DEALLOCATE(maskarr, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(cov_matrices, stat=err)
+          DEALLOCATE(obsies_ccoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(obs_pair_arr, stat=err)
+          DEALLOCATE(rho1, stat=err)
+          DEALLOCATE(rho2,stat=err)
+          DEALLOCATE(sphdev, stat=err)
+          DEALLOCATE(mjd_lt, stat=err)
+          DEALLOCATE(scoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          RETURN
+       END IF
+
+       sor_orb_acc: DO i=1,norb
+          ! Sky-plane residuals and chi-squares:
+          DO j=1,nobs
+             observed_coord = getCoordinates(obs_scoords(j))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (115)",1)
+                DO k=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(k))
+                END DO
+                DO k=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(k))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                DEALLOCATE(scoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                RETURN
+             END IF
+             computed_coord = getCoordinates(scoords(i,j))
+             IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "TRACE BACK (120)",1)
+                DO k=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(k))
+                END DO
+                DO k=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(k))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                DEALLOCATE(scoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                RETURN
+             END IF
+             residuals(iorb+1,j,1:6) = observed_coord(1:6) - computed_coord(1:6)
+             residuals(iorb+1,j,2) = residuals(iorb+1,j,2) * cosdec0_arr(j)
+
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,3(1X,F15.10))") "observed pos.", observed_coord(1:3)
+                WRITE(stdout,"(2X,A,3(1X,F15.10))") "computed pos.", computed_coord(1:3)
+             END IF
+             IF (this%regularization_prm .OR. this%jacobians_prm) THEN
+                ! Multiply RA partials with cosine of observed declination:
+                partials_arr(i,2,:,j) = partials_arr(i,2,:,j)*cosdec0_arr(j)
+             END IF
+          END DO
+
+          maskarr = .FALSE.
+          WHERE (this%obs_masks_prm .AND. ABS(residuals(iorb+1,:,:)) > this%res_accept_prm) 
+             maskarr = .TRUE.
+          END WHERE
+          IF (info_verb >= 5) THEN
+             DO j=1,nobs
+                WRITE(stdout,"(2X,A,2(1X,F10.5))") "O-C residuals (RA, Dec):", &
+                     residuals(iorb+1,j,2:3)/rad_asec
+             END DO
+             WRITE(stdout,"(2X,A,I0,A,I0)") &
+                  "No of omitted obs/included obs: ", &
+                  COUNT(maskarr),"/",n0(2)
+          END IF
+          IF (COUNT(maskarr) > 0) THEN
+             ! Residuals are too large for at least one observation.
+             failed_flag(6) = failed_flag(6) + 1
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A)") &
+                     "Failed (residuals are too large)"
+             END IF
+             CYCLE sor_orb_acc
+          END IF
+
+          ! Compute chi2:
+          chi2 = chi_square(residuals(iorb+1,:,:), information_matrix_obs, this%obs_masks_prm, errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "TRACE BACK (125)", 1)
+             DO j=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(j))
+             END DO
+             DO j=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(j))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             DEALLOCATE(scoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             RETURN          
+          END IF
+
+          ! Compute dchi2 wrt best fit orbit
+          dchi2 = chi2 - this%chi2_min_prm
+          IF (this%dchi2_rejection_prm .AND. &
+               dchi2 > this%dchi2_prm) THEN
+             ! The dchi2 is used and its value is not acceptable.
+             failed_flag(7) = failed_flag(7) + 1
+             IF (info_verb >= 5) THEN
+                WRITE(stdout,"(2X,A,1X,E10.5)") &
+                     "Failed (dchi2 too large)", dchi2
+             END IF
+             CYCLE sor_orb_acc
+          END IF
+
+          ! Jeffrey's apriori:
+          ! Monitor the matrix inversion?
+          IF (this%regularization_prm) THEN
+             ! Sigma_elements^(-1) = A^T Sigma_obs^(-1) A, where A is the
+             ! partial derivatives matrix of ephemerides wrt elements:
+             information_matrix_elem = 0.0_bp
+             DO j=1,nobs
+                information_matrix_elem = information_matrix_elem + &
+                     MATMUL(MATMUL(TRANSPOSE(partials_arr(i,1:6,1:6,j)), &
+                     information_matrix_obs(j,1:6,1:6)), &
+                     partials_arr(i,1:6,1:6,j))
+             END DO
+             apriori = SQRT(ABS(determinant(information_matrix_elem, errstr)))
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "Unsuccessful computation of determinant of orbital element " // &
+                     "information matrix " // TRIM(errstr), 1)
+                errstr = ""
+                IF (err_verb >= 1) THEN
+                   CALL matrix_print(information_matrix_elem, stderr, errstr)
+                END IF
+                errstr = ""
+                CYCLE
+             END IF
+          ELSE
+             apriori = 1.0_bp
+          END IF
+
+          IF (this%jacobians_prm) THEN
+             ! Determinant of Jacobian between topocentric
+             ! coordinates (inverse problem coordinates)
+             ! and orbital parameters required for output
+             ! ("Topocentric Wrt Cartesian/Keplerian"):
+             jacobian_matrix(1:3,:) = partials_arr(i,1:3,:,obs_pair_arr(i,1)) / &
+                  cosdec0_arr(obs_pair_arr(i,1))
+             jacobian_matrix(4:6,:) = partials_arr(i,1:3,:,obs_pair_arr(i,2)) / &
+                  cosdec0_arr(obs_pair_arr(i,2))
+             jac_sph_inv = ABS(determinant(jacobian_matrix, errstr))
+             IF (LEN_TRIM(errstr) /= 0) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "Unsuccessful computation of determinant of orbital element " // &
+                     "jacobian matrix " // TRIM(errstr), 1)
+                errstr = ""
+                IF (err_verb >= 1) THEN
+                   CALL matrix_print(jacobian_matrix, stderr, errstr)
+                END IF
+                errstr = ""
+                CYCLE
+             END IF
+
+             ! Determinant of Jacobian between Cartesian and Keplerian
+             ! orbital elements ("Cartesian Wrt Keplerian"):
+             CALL partialsCartesianWrtKeplerian(orb_arr(i), &
+                  jacobian_matrix, "equatorial")
+             IF (error .AND. TRIM(this%element_type_prm) /= "keplerian") THEN
+                error = .FALSE.
+                jac_car_kep = -1.0_bp
+             ELSE IF (error) THEN
+                CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                     "Unsuccessful computation of jacobian matrix " // &
+                     "between Cartesian and Keplerian elements.", 1)
+                DO j=1,SIZE(orb_arr_)
+                   CALL NULLIFY(orb_arr_(j))
+                END DO
+                DO j=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(j))
+                END DO
+                DEALLOCATE(orb_arr_, stat=err)
+                DEALLOCATE(rho_distribution, stat=err)
+                DEALLOCATE(residuals, stat=err)
+                DEALLOCATE(pdf_arr, stat=err)
+                DEALLOCATE(reg_apriori_arr, stat=err)
+                DEALLOCATE(jacobians, stat=err)
+                DEALLOCATE(rchi2_arr, stat=err)
+                DEALLOCATE(rms, stat=err)
+                DEALLOCATE(pair_histogram, stat=err)
+                DEALLOCATE(cosdec0_arr, stat=err)
+                DEALLOCATE(residual_vector, stat=err)
+                DEALLOCATE(maskarr, stat=err)
+                DEALLOCATE(obs_scoords, stat=err)
+                DEALLOCATE(information_matrix_obs, stat=err)
+                DEALLOCATE(cov_matrices, stat=err)
+                DEALLOCATE(obsies_ccoords, stat=err)
+                DEALLOCATE(orb_arr, stat=err)
+                DEALLOCATE(obs_pair_arr, stat=err)
+                DEALLOCATE(rho1, stat=err)
+                DEALLOCATE(rho2,stat=err)
+                DEALLOCATE(sphdev, stat=err)
+                DEALLOCATE(mjd_lt, stat=err)
+                DEALLOCATE(scoords, stat=err)
+                DEALLOCATE(partials_arr, stat=err)
+                RETURN
+             ELSE
+                jac_car_kep = ABS(determinant(jacobian_matrix, errstr)) 
+                IF (LEN_TRIM(errstr) /= 0) THEN
+                   CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                        "Unsuccessful computation of determinant of" // &
+                        " jacobian matrix between Cartesian and Keplerian" // &
+                        " elements:" // TRIM(errstr), 1)
+                   errstr = ""
+                   IF (err_verb >= 1) THEN
+                      CALL matrix_print(jacobian_matrix, stderr, errstr)
+                   END IF
+                   errstr = ""
+                   DO j=1,SIZE(orb_arr_)
+                      CALL NULLIFY(orb_arr_(j))
+                   END DO
+                   DO j=1,SIZE(orb_arr)
+                      CALL NULLIFY(orb_arr(j))
+                   END DO
+                   DEALLOCATE(orb_arr_, stat=err)
+                   DEALLOCATE(rho_distribution, stat=err)
+                   DEALLOCATE(residuals, stat=err)
+                   DEALLOCATE(pdf_arr, stat=err)
+                   DEALLOCATE(reg_apriori_arr, stat=err)
+                   DEALLOCATE(jacobians, stat=err)
+                   DEALLOCATE(rchi2_arr, stat=err)
+                   DEALLOCATE(rms, stat=err)
+                   DEALLOCATE(pair_histogram, stat=err)
+                   DEALLOCATE(cosdec0_arr, stat=err)
+                   DEALLOCATE(residual_vector, stat=err)
+                   DEALLOCATE(maskarr, stat=err)
+                   DEALLOCATE(obs_scoords, stat=err)
+                   DEALLOCATE(information_matrix_obs, stat=err)
+                   DEALLOCATE(cov_matrices, stat=err)
+                   DEALLOCATE(obsies_ccoords, stat=err)
+                   DEALLOCATE(orb_arr, stat=err)
+                   DEALLOCATE(obs_pair_arr, stat=err)
+                   DEALLOCATE(rho1, stat=err)
+                   DEALLOCATE(rho2,stat=err)
+                   DEALLOCATE(sphdev, stat=err)
+                   DEALLOCATE(mjd_lt, stat=err)
+                   DEALLOCATE(scoords, stat=err)
+                   DEALLOCATE(partials_arr, stat=err)
+                   RETURN
+                END IF
+             END IF
+
+             ! Determinant of Jacobian between equinoctial and
+             ! Keplerian orbital elements ("Equinoctial Wrt
+             ! Keplerian"):
+             elements = getElements(orb_arr(i), "keplerian")
+             jac_equ_kep = 0.5_bp*elements(2) * &
+                  SIN(0.5_bp*elements(3)) / COS(0.5_bp*elements(3))**3
+          ELSE
+             jac_sph_inv = 1.0_bp
+             jac_car_kep = 1.0_bp
+             jac_equ_kep = 1.0_bp
+          END IF
+
+          ! Probability density function (note that the '- nobs' term
+          ! is there for practical reasons):
+          pdf_val = apriori*EXP(-0.5_bp*(chi2 - COUNT(this%obs_masks_prm)))/jac_sph_inv
+
+          ! Update metrics for computational accuracy:
+          rho_comp1 = getDistance(scoords(i,obs_pair_arr(i,1)))
+          rho_comp2 = getDistance(scoords(i,obs_pair_arr(i,2)))
+
+          ! 1) Topocentric ranges
+          IF (ABS(rho_comp1 - rho1(i)) > acc(1)) THEN
+             acc(1) = ABS(rho_comp1 - rho1(i))
+          END IF
+          IF (ABS(rho_comp2 - rho2(i)) > acc(1)) THEN
+             acc(1) = ABS(rho_comp2 - rho2(i))
+          END IF
+
+          ! 2) R.A. and Dec.
+          tmp = ABS(residuals(iorb+1,obs_pair_arr(i,1),2) + sphdev(i,1,2))
+          IF (tmp > acc(2)) THEN
+             acc(2) = tmp
+          END IF
+          tmp = ABS(residuals(iorb+1,obs_pair_arr(i,2),2) + sphdev(i,2,2))
+          IF (tmp > acc(2)) THEN
+             acc(2) = tmp
+          END IF
+          tmp = ABS(residuals(iorb+1,obs_pair_arr(i,1),3) + sphdev(i,1,3))
+          IF (tmp > acc(3)) THEN
+             acc(3) = tmp
+          END IF
+          tmp = ABS(residuals(iorb+1,obs_pair_arr(i,2),3) + sphdev(i,2,3))
+          IF (tmp > acc(3)) THEN
+             acc(3) = tmp
+          END IF
+
+          ! Update topocentric distance bounds:
+          IF (rho1(i) < this%sor_rho_cmp(1,1)) THEN
+             this%sor_rho_cmp(1,1) = rho1(i)
+          END IF
+          IF (rho1(i) > this%sor_rho_cmp(1,2)) THEN
+             this%sor_rho_cmp(1,2) = rho1(i)
+          END IF
+          IF (rho2(i) - rho1(i) < this%sor_rho_cmp(2,1)) THEN
+             this%sor_rho_cmp(2,1) = rho2(i) - rho1(i)
+          END IF
+          IF (rho2(i) - rho1(i) > this%sor_rho_cmp(2,2)) THEN
+             this%sor_rho_cmp(2,2) = rho2(i) - rho1(i)
+          END IF
+
+          ! Orbital element storage:
+          iorb = iorb + 1
+          naccepted = naccepted + 1
+          ! - accepted sample orbit:
+          orb_arr_(iorb) = copy(orb_arr(i))
+          ! - p.d.f.:
+          pdf_arr(iorb) = pdf_val
+          ! - regularizing apriori:
+          reg_apriori_arr(iorb) = apriori
+          ! - determinant of jacobian between computed positions and
+          !   orbital elements:
+          jacobians(iorb,1) = jac_sph_inv
+          ! - determinant of jacobian between Cartesian and Keplerian
+          !   elements:
+          jacobians(iorb,2) = jac_car_kep
+          ! - determinant of jacobian between Equinoctial and Keplerian
+          !   elements:
+          jacobians(iorb,3) = jac_equ_kep
+          ! Nonlinear "reduced chi2" 
+          ! (note that usually rchi2 = chi2/(number of measurements - number of fitted parameters))
+          rchi2_arr(iorb) = chi2 - REAL(COUNT(this%obs_masks_prm),bp)
+
+          n0_ = n0
+          WHERE (n0_ == 0)
+             n0_ = 1
+          END WHERE
+          ! - rms:
+          rms(iorb,:) = SQRT(SUM(residuals(iorb,:,:)**2.0_bp,dim=1,mask=this%obs_masks_prm)/n0_)
+          ! - generated distance to object at first epoch 
+          rho_distribution(iorb,1) = rho_comp1
+          ! - generated distance to object at second epoch (NB! Relative
+          !   to the distance at the first epoch.)
+          rho_distribution(iorb,2) = rho_comp2
+          ! Update histogram of observation pairs used as boundary values
+          ! when solving the 2-point boundary value problem:
+          DO j=1,SIZE(this%sor_pair_arr_prm,dim=1)
+             IF (obs_pair_arr(i,1) == this%sor_pair_arr_prm(j,1) .AND. &
+                  obs_pair_arr(i,2) == this%sor_pair_arr_prm(j,2)) THEN
+                pair_histogram(j) = pair_histogram(j) + 1
+             END IF
+          END DO
+          IF (info_verb >= 5) THEN
+             WRITE(stdout,"(2X,A,I0)") "Sample orbit ", iorb
+          END IF
+          IF (iorb == this%sor_norb_prm) THEN
+             EXIT
+          END IF
+
+       END DO sor_orb_acc
+
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,2(1X,I0))") &
+               "Nr of accepted orbits and accepted trial orbits:", &
+               naccepted, norb
+       END IF
+       norb = NINT((this%sor_norb_prm - iorb)*(1.0_bp*itrial/MAX(REAL(iorb,bp),1.0_bp)))
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,1X,I0,A,I0)") "Number of sample orbits accepted so far:", iorb, "/", this%sor_norb_prm
+          WRITE(stdout,"(2X,A,1X,I0)") "Number of trial orbits generated so far:", itrial
+          WRITE(stdout,"(2X,A,1X,I0)") "Number of trial orbits expected to be required for completion:", norb
+       END IF
+       IF (norb > norb_simult_max) THEN
+          norb = norb_simult_max
+       END IF
+       IF (info_verb >= 3) THEN
+          WRITE(stdout,"(2X,A,1X,I0)") "Number of trial orbits to be generated for next batch:", norb
+          WRITE(stdout,*)
+       END IF
+       IF (norb /= SIZE(orb_arr,dim=1) .OR. &
+            iorb == this%sor_norb_prm .OR. &
+            itrial == this%sor_ntrial_prm) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+          DEALLOCATE(orb_arr, obs_pair_arr, rho1, rho2, sphdev, mjd_lt, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "Could not deallocate memory (10).", 1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             DEALLOCATE(scoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             RETURN
+          END IF
+       END IF
+       IF (this%regularization_prm .OR. this%jacobians_prm) THEN
+          DEALLOCATE(scoords, partials_arr, stat=err)
+       ELSE
+          DEALLOCATE(scoords, stat=err)
+       END IF
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / statisticalRanging", &
+               "Could not deallocate memory (12).", 1)
+          DO i=1,SIZE(orb_arr_)
+             CALL NULLIFY(orb_arr_(i))
+          END DO
+          IF (ASSOCIATED(orb_arr)) THEN
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+          END IF
+          DEALLOCATE(orb_arr_, stat=err)
+          DEALLOCATE(rho_distribution, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms, stat=err)
+          DEALLOCATE(pair_histogram, stat=err)
+          DEALLOCATE(cosdec0_arr, stat=err)
+          DEALLOCATE(residual_vector, stat=err)
+          DEALLOCATE(maskarr, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(cov_matrices, stat=err)
+          DEALLOCATE(obsies_ccoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(obs_pair_arr, stat=err)
+          DEALLOCATE(rho1, stat=err)
+          DEALLOCATE(rho2,stat=err)
+          DEALLOCATE(sphdev, stat=err)
+          DEALLOCATE(mjd_lt, stat=err)
+          DEALLOCATE(scoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          RETURN
+       END IF
+
+    END DO sor_main
+
+    ! Final number of orbits and unnormalized a posteriori 
+    ! probability density values:
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,I0)") "Final number of orbits : ", iorb
+       WRITE(stdout,"(2X,A,I0)") "Final number of trials : ", itrial
+       WRITE(stdout,"(2X,A,F6.2)") "Failed-%  - total       : ", &
+            SUM(failed_flag(1:5))/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - 2-point     : ", &
+            failed_flag(1)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - a too small : ", & 
+            failed_flag(2)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - a too large : ", &
+            failed_flag(3)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - q too small : ", & 
+            failed_flag(4)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - q too large : ", & 
+            failed_flag(5)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - residuals   : ", & 
+            failed_flag(6)/REAL(itrial)*100.0_bp
+       WRITE(stdout,"(2X,A,F6.2)") "          - p.d.f.      : ", & 
+            failed_flag(7)/REAL(itrial)*100.0_bp
+    END IF
+
+    this%sor_norb_cmp   = iorb
+    this%sor_ntrial_cmp = itrial
+    IF (this%sor_norb_cmp > 0) THEN
+       IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL NULLIFY(this%orb_arr_cmp(i))
+          END DO
+          DEALLOCATE(this%orb_arr_cmp, stat=err)
+       END IF
+       DEALLOCATE(this%sor_rho_arr_cmp, stat=err)
+       DEALLOCATE(this%res_arr_cmp, stat=err)
+       DEALLOCATE(this%pdf_arr_cmp, stat=err)
+       DEALLOCATE(this%reg_apr_arr_cmp, stat=err)
+       DEALLOCATE(this%jac_arr_cmp, stat=err)
+       DEALLOCATE(this%rchi2_arr_cmp, stat=err)
+       DEALLOCATE(this%rms_arr_cmp, stat=err)
+       DEALLOCATE(this%sor_pair_histo_prm, stat=err)
+       ALLOCATE(this%orb_arr_cmp(this%sor_norb_cmp), &
+            this%sor_rho_arr_cmp(this%sor_norb_cmp,2), &
+            this%res_arr_cmp(this%sor_norb_cmp,nobs,6), &
+            this%pdf_arr_cmp(this%sor_norb_cmp), &
+            this%reg_apr_arr_cmp(this%sor_norb_cmp), &
+            this%jac_arr_cmp(this%sor_norb_cmp,3), &
+            this%rchi2_arr_cmp(this%sor_norb_cmp), &
+            this%rms_arr_cmp(this%sor_norb_cmp,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / statisticalRanging", &
+               "Could not allocate memory (3).", 1)
+          DO i=1,SIZE(orb_arr_)
+             CALL NULLIFY(orb_arr_(i))
+          END DO
+          IF (ASSOCIATED(orb_arr)) THEN
+             DO i=1,SIZE(orb_arr)
+                CALL NULLIFY(orb_arr(i))
+             END DO
+          END IF
+          DEALLOCATE(orb_arr_, stat=err)
+          DEALLOCATE(rho_distribution, stat=err)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(pdf_arr, stat=err)
+          DEALLOCATE(reg_apriori_arr, stat=err)
+          DEALLOCATE(jacobians, stat=err)
+          DEALLOCATE(rchi2_arr, stat=err)
+          DEALLOCATE(rms, stat=err)
+          DEALLOCATE(pair_histogram, stat=err)
+          DEALLOCATE(cosdec0_arr, stat=err)
+          DEALLOCATE(residual_vector, stat=err)
+          DEALLOCATE(maskarr, stat=err)
+          DEALLOCATE(obs_scoords, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(cov_matrices, stat=err)
+          DEALLOCATE(obsies_ccoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          DEALLOCATE(obs_pair_arr, stat=err)
+          DEALLOCATE(rho1, stat=err)
+          DEALLOCATE(rho2,stat=err)
+          DEALLOCATE(sphdev, stat=err)
+          DEALLOCATE(mjd_lt, stat=err)
+          DEALLOCATE(scoords, stat=err)
+          DEALLOCATE(partials_arr, stat=err)
+          RETURN
+       END IF
+
+       i = MAXLOC(this%pdf_arr_cmp,dim=1)
+       CALL NULLIFY(this%orb_ml_cmp)
+       this%orb_ml_cmp        = copy(this%orb_arr_cmp(i)) 
+       DO i=1, this%sor_norb_cmp
+          this%orb_arr_cmp(i) = copy(orb_arr_(i))
+       END DO
+       this%pdf_arr_cmp       = pdf_arr(1:iorb)
+       this%reg_apr_arr_cmp   = reg_apriori_arr(1:iorb)
+       this%jac_arr_cmp       = jacobians(1:iorb,1:3)
+       this%rchi2_arr_cmp     = rchi2_arr(1:iorb)
+       this%rms_arr_cmp       = rms(1:iorb,:)
+       this%sor_rho_arr_cmp   = rho_distribution(1:iorb,:)
+       this%res_arr_cmp       = residuals(1:iorb,:,:)
+       this%chi2_min_cmp      = MINVAL(rchi2_arr(1:iorb)) + REAL(COUNT(this%obs_masks_prm),bp)
+       IF (this%sor_random_obs_prm) THEN
+          ALLOCATE(this%sor_pair_histo_prm(SIZE(this%sor_pair_arr_prm,1)), stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / statisticalRanging", &
+                  "Could not allocate memory (4).", 1)
+             DO i=1,SIZE(orb_arr_)
+                CALL NULLIFY(orb_arr_(i))
+             END DO
+             IF (ASSOCIATED(orb_arr)) THEN
+                DO i=1,SIZE(orb_arr)
+                   CALL NULLIFY(orb_arr(i))
+                END DO
+             END IF
+             DEALLOCATE(orb_arr_, stat=err)
+             DEALLOCATE(rho_distribution, stat=err)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(pdf_arr, stat=err)
+             DEALLOCATE(reg_apriori_arr, stat=err)
+             DEALLOCATE(jacobians, stat=err)
+             DEALLOCATE(rchi2_arr, stat=err)
+             DEALLOCATE(rms, stat=err)
+             DEALLOCATE(pair_histogram, stat=err)
+             DEALLOCATE(cosdec0_arr, stat=err)
+             DEALLOCATE(residual_vector, stat=err)
+             DEALLOCATE(maskarr, stat=err)
+             DEALLOCATE(obs_scoords, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(cov_matrices, stat=err)
+             DEALLOCATE(obsies_ccoords, stat=err)
+             DEALLOCATE(orb_arr, stat=err)
+             DEALLOCATE(obs_pair_arr, stat=err)
+             DEALLOCATE(rho1, stat=err)
+             DEALLOCATE(rho2,stat=err)
+             DEALLOCATE(sphdev, stat=err)
+             DEALLOCATE(mjd_lt, stat=err)
+             DEALLOCATE(scoords, stat=err)
+             DEALLOCATE(partials_arr, stat=err)
+             RETURN
+          END IF
+          this%sor_pair_histo_prm = pair_histogram
+       END IF
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       IF (ASSOCIATED(orb_arr)) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+       END IF
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(cov_matrices, stat=err)
+       DEALLOCATE(obsies_ccoords, stat=err)
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(obs_pair_arr, stat=err)
+       DEALLOCATE(rho1, stat=err)
+       DEALLOCATE(rho2, stat=err)
+       DEALLOCATE(sphdev, stat=err)
+       DEALLOCATE(mjd_lt, stat=err)
+       DEALLOCATE(scoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / statisticalRanging", &
+            "No sample orbits found!", 1)
+       DO i=1,SIZE(orb_arr_)
+          CALL NULLIFY(orb_arr_(i))
+       END DO
+       IF (ASSOCIATED(orb_arr)) THEN
+          DO i=1,SIZE(orb_arr)
+             CALL NULLIFY(orb_arr(i))
+          END DO
+       END IF
+       DEALLOCATE(orb_arr_, stat=err)
+       DEALLOCATE(rho_distribution, stat=err)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(pdf_arr, stat=err)
+       DEALLOCATE(reg_apriori_arr, stat=err)
+       DEALLOCATE(jacobians, stat=err)
+       DEALLOCATE(rchi2_arr, stat=err)
+       DEALLOCATE(rms, stat=err)
+       DEALLOCATE(pair_histogram, stat=err)
+       DEALLOCATE(cosdec0_arr, stat=err)
+       DEALLOCATE(residual_vector, stat=err)
+       DEALLOCATE(maskarr, stat=err)
+       DEALLOCATE(obs_scoords, stat=err)
+       DEALLOCATE(information_matrix_obs, stat=err)
+       DEALLOCATE(cov_matrices, stat=err)
+       DEALLOCATE(obsies_ccoords, stat=err)
+       DEALLOCATE(orb_arr, stat=err)
+       DEALLOCATE(obs_pair_arr, stat=err)
+       DEALLOCATE(rho1, stat=err)
+       DEALLOCATE(rho2,stat=err)
+       DEALLOCATE(sphdev, stat=err)
+       DEALLOCATE(mjd_lt, stat=err)
+       DEALLOCATE(scoords, stat=err)
+       DEALLOCATE(partials_arr, stat=err)
+       RETURN
+    END IF
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,2(1X,E10.4))") "Initial - final minimum chi2 values    :", &
+            this%chi2_min_prm - this%chi2_min_cmp
+       WRITE(stdout,"(2X,A,4(1X,E10.4))") "Min/max rhos, @ end    :" , &
+            this%sor_rho_cmp(1,1:2), this%sor_rho_cmp(2,1:2)
+       acc(2:3) = acc(2:3)/rad_asec
+       WRITE(stdout,"(2X,A,3(1X,E10.4),A)") "Accur. (rho/R.A./Dec.) :", acc, " (AU/as/as)"
+       WRITE(stdout,"(2X,A)") ""
+    END IF
+
+  END SUBROUTINE statisticalRanging
+
+
+
+
+
+  !!  *Description*:
+  !!
+  !! Finds initial values for the full inversion by including the
+  !! observations one at a time and perfoming a partial inversion.
+  !! A limited amount of required sample orbits and trial orbits are
+  !! used during the initiation phase.
+  !! 
+  !!
+  SUBROUTINE stepwiseRanging(this, nobs_max)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)     :: this
+    INTEGER, INTENT(in)                       :: nobs_max
+
+    TYPE (Observations)                       :: obss, obss_next
+    TYPE (Observation), DIMENSION(:), POINTER :: obs_arr
+    TYPE (Observation)                        :: obs_next
+    TYPE (StochasticOrbit)                    :: storb
+    CHARACTER(len=4)                          :: str1, str2
+    REAL(bp), DIMENSION(4)                    :: rho
+    REAL(bp)                                  :: chi2_min_, chi2_min_final, ddchi2
+    INTEGER(ibp)                              :: nobs, nobs_max_, err, &
+         i, j, k
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    obs_arr => getObservations(this%obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    nobs = SIZE(obs_arr,dim=1)
+    IF (nobs < 2) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "Number of observations is not sufficient. At least two required.", 1)
+       DEALLOCATE(obs_arr, stat=err)
+       RETURN
+    END IF
+    IF (nobs_max < 0 .OR. nobs_max > nobs) THEN
+       nobs_max_ = nobs
+    ELSE
+       nobs_max_ = nobs_max
+    END IF
+    CALL NEW(obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(obs_arr, stat=err)
+       CALL NULLIFY(obss)
+       RETURN
+    END IF
+    CALL addObservation(obss, obs_arr(1))
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "TRACE BACK (15)", 1)
+       DEALLOCATE(obs_arr, stat=err)
+       CALL NULLIFY(obss)
+       RETURN
+    END IF
+
+    i = 1
+    j = 2
+    k = nobs
+    rho(1) = this%sor_rho_prm(1,1)
+    rho(2) = this%sor_rho_prm(1,2)
+    rho(3) = this%sor_rho_prm(2,1)
+    rho(4) = this%sor_rho_prm(2,2)
+    DO WHILE (k-j /= -1 .AND. i < nobs_max_ .AND. i < nobs)
+       i = i + 1
+       IF ((-1)**i < 0) THEN
+          CALL addObservation(obss, obs_arr(j))
+          IF (i /= nobs) THEN 
+             CALL NEW(obss_next, obs_arr(k))
+          END IF
+          j = j + 1
+       ELSE
+          CALL addObservation(obss, obs_arr(k))
+          IF (i /= nobs) THEN 
+             CALL NEW(obss_next, obs_arr(j))
+          END IF
+          k = k - 1
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+               "TRACE BACK (20)", 1)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(obss)
+          RETURN
+       END IF
+       CALL NULLIFY(storb)
+       CALL NEW(storb, obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+               "TRACE BACK (22)", 1)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(obss)
+          CALL NULLIFY(storb)
+          RETURN
+       END IF
+       CALL setParameters(storb, &
+            dyn_model=this%dyn_model_prm, &
+            perturbers=this%perturbers_prm, &
+            integrator=this%integrator_prm, &
+            integration_step=this%integration_step_prm, &
+            t_inv=this%t_inv_prm, &
+            element_type=this%element_type_prm, &
+            multiple_objects=this%multiple_obj_prm, &
+            outlier_rejection=this%outlier_rejection_prm, &
+            dchi2_rejection=this%dchi2_rejection_prm, &
+            regularized_pdf=this%regularization_prm, &
+            jacobians_pdf=this%jacobians_prm, &
+            accept_multiplier=this%accept_multiplier_prm, &
+            apriori_a_max=this%apriori_a_max_prm, &
+            apriori_a_min=this%apriori_a_min_prm, &
+            apriori_periapsis_max=this%apriori_periapsis_max_prm, &
+            apriori_periapsis_min=this%apriori_periapsis_min_prm, &
+            apriori_apoapsis_max=this%apriori_apoapsis_max_prm, &
+            apriori_apoapsis_min=this%apriori_apoapsis_min_prm, &
+            apriori_rho_min=this%apriori_rho_min_prm, &
+            sor_norb=this%sor_norb_sw_prm, &
+                                ! Number of trial orbits increases with number of observations:
+                                !sor_ntrial=this%sor_ntrial_sw_prm*i, &
+            sor_ntrial=this%sor_ntrial_sw_prm, &
+            sor_rho1_l=rho(1), &
+            sor_rho1_u=rho(2), &
+            sor_rho2_l=rho(3), &
+            sor_rho2_u=rho(4), &
+            sor_niter=1, &
+            generat_multiplier=this%generat_multiplier_prm, &
+            sor_2point_method=this%sor_2point_method_sw_prm, &
+            sor_iterate_bounds=this%sor_iterate_bounds_prm)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+               "TRACE BACK (27)", 1)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(obss)
+          CALL NULLIFY(storb)
+          RETURN
+       END IF
+       IF (i == 2) THEN
+          CALL autoStatisticalRanging(storb)
+       ELSE
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X,A,1X,I0,A,I0)") "Nr of observations     :", i, "/", nobs
+          END IF
+          storb%chi2_min_prm = chi2_min_
+          CALL statisticalRanging(storb)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+               "TRACE BACK (30)", 1)
+          DEALLOCATE(obs_arr, stat=err)
+          CALL NULLIFY(obss)
+          CALL NULLIFY(storb)
+          RETURN
+       ELSE
+          this%sor_norb_sw_cmp = storb%sor_norb_cmp
+          this%sor_ntrial_sw_cmp = storb%sor_ntrial_cmp
+          IF (this%sor_norb_sw_cmp < 2) THEN
+             CALL toString(this%sor_norb_sw_cmp, str1, error)
+             CALL toString(i, str2, error)
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  TRIM(str1) // "sample orbits found when " // &
+                  TRIM(str2) // " observations were included." , 1)
+             error = .TRUE.
+             DEALLOCATE(obs_arr, stat=err)
+             CALL NULLIFY(obss)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          IF (exist(obss_next)) THEN
+             CALL constrainRangeDistributions(storb, obss_next)
+             CALL NULLIFY(obss_next)
+          END IF
+          CALL setRangeBounds(storb)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "TRACE BACK (33", 1)
+             DEALLOCATE(obs_arr, stat=err)
+             CALL NULLIFY(obss)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          rho(1:4) = getRangeBounds(storb)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "TRACE BACK (35)", 1)
+             DEALLOCATE(obs_arr, stat=err)
+             CALL NULLIFY(obss)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          chi2_min_ = storb%chi2_min_cmp
+       END IF
+    END DO
+    DEALLOCATE(obs_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+            "Could not deallocate memory.", 1)
+       CALL NULLIFY(obss)
+       CALL NULLIFY(storb)
+       RETURN
+    END IF
+    CALL NULLIFY(obss)
+
+    this%sor_niter_cmp = 0
+    this%sor_rho_histo_cmp = 1
+    IF (nobs == nobs_max_) THEN
+       ddchi2 = 10.0_bp
+       DO WHILE (this%sor_niter_cmp < this%sor_niter_prm .AND. &
+            (this%sor_rho_histo_cmp > 0 .OR. &
+            (this%dchi2_rejection_prm .AND. ddchi2 > 2.0_bp) .OR. &
+            this%sor_norb_cmp < this%sor_norb_prm))
+          CALL setParameters(this, &
+               sor_rho1_l=rho(1), &
+               sor_rho1_u=rho(2), &
+               sor_rho2_l=rho(3), &
+               sor_rho2_u=rho(4))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "TRACE BACK (40)", 1)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X,A,1X,I0)") "Nr of observations     :", i
+          END IF
+          this%chi2_min_prm = chi2_min_
+          CALL statisticalRanging(this)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "Subsequent iteration failed.", 1)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          this%sor_niter_cmp = this%sor_niter_cmp + 1
+          IF (this%sor_norb_cmp < this%sor_norb_prm .AND. err_verb >= 2) THEN
+             WRITE(stderr,"(A,I0)") "Warning by stepwiseRanging:" // &
+                  " Number of sample orbits too small: ", this%sor_norb_cmp
+             WRITE(stderr,"(1X)")
+          END IF
+          ddchi2  = MAXVAL(this%rchi2_arr_cmp) - MINVAL(this%rchi2_arr_cmp) - this%dchi2_prm
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X,A,1X,F12.4)") "Delta dchi2            :", &
+                  ddchi2
+          END IF
+          CALL setRangeBounds(this)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "TRACE BACK (45)", 1)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          rho(1:4) = getRangeBounds(this)
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / stepwiseRanging", &
+                  "TRACE BACK (50)", 1)
+             CALL NULLIFY(storb)
+             RETURN
+          END IF
+          chi2_min_ = MIN(this%chi2_min_cmp,this%chi2_min_prm)
+       END DO
+    ELSE
+       CALL NULLIFY(this)
+       this = copy(storb)
+    END IF
+    CALL NULLIFY(storb)
+
+  END SUBROUTINE stepwiseRanging
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Optimizes the range distribution corresponding to the first and
+  !! last observation of a set of observations which is a combination
+  !! of this%obss and the additional observations supplied with this
+  !! subroutine. For the estimation of the ranges the algorithm
+  !! selects all orbits which reproduce the observations with
+  !! acceptable residuals (limit is set by the 1-sigma astrometric
+  !! uncertainty multiplied by this%accept_multiplier_prm) or, if i<10
+  !! orbits with acceptable residuals are found, selects the 10-i
+  !! orbits that produce the smallest rchi2 values.
+  !!
+  !! Sets error=.TRUE. if an error occurs.
+  !!
+  SUBROUTINE constrainRangeDistributions(this, obss)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+    TYPE (Observations), INTENT(in) :: obss
+
+    TYPE (Orbit), DIMENSION(:), POINTER :: orb_arr
+    TYPE (Observations) :: obss_
+    TYPE (Observation) :: obs
+    TYPE (CartesianCoordinates), DIMENSION(2) :: observers
+    TYPE (SphericalCoordinates) , DIMENSION(:,:), POINTER :: ephemerides
+    REAL(bp), DIMENSION(:,:,:), POINTER :: residuals, &
+         information_matrix_obs
+    REAL(bp), DIMENSION(:,:), POINTER :: stdevs
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: sor_rho_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER :: dates_orig, dates_add
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: chi2_arr
+    INTEGER :: err, i, j, norb
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask, mask_
+
+    ! Get residuals between predicted positions and additional
+    ! observations:
+    residuals => getResiduals(this, obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "TRACE BACK (5)", 1)
+       DEALLOCATE(residuals, stat=err)
+       RETURN
+    END IF
+
+    ! Get astrometric uncertainty for additional observations:
+    stdevs => getStandardDeviations(obss)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "TRACE BACK (10)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(stdevs, stat=err)
+       RETURN
+    END IF
+
+    ! Find out which orbits reproduce the additional observations
+    ! within the set limits:
+    norb = SIZE(residuals,dim=2)
+    ALLOCATE(mask(norb), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not allocate memory (5)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(stdevs, stat=err)
+       DEALLOCATE(mask, stat=err)
+       RETURN
+    END IF
+
+    mask = .TRUE.
+    DO i=1,norb
+       ! Note that RA,Dec is hardwired here
+       IF (ANY(ABS(residuals(:,i,2:3)) > this%accept_multiplier_prm*stdevs(:,2:3))) THEN
+          mask(i) = .FALSE.
+       END IF
+    END DO
+    DEALLOCATE(stdevs, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not deallocate memory (5)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       RETURN
+    END IF
+    IF (info_verb >= 2 .AND. COUNT(mask) > 0) THEN
+       WRITE(stdout,"(2X,2(A,1X),I0,1X,A)") "constrainRangeDistributions:", &
+            "RA,Dec residuals corresponding to the", COUNT(mask), &
+            "orbits having residuals smaller than the acceptance window [asec]:"
+       DO i=1,SIZE(mask)
+          IF (mask(i)) THEN
+             DO j=1,SIZE(residuals,dim=1)
+                WRITE(stdout,"(2X,2(A,1X,I0,1X),A,2(1X,F10.3))") &
+                     "Orbit #", i, "& observation #", j, ":", residuals(j,i,2:3)/rad_asec
+             END DO
+          END IF
+       END DO
+    END IF
+
+    ! If less than 10 orbits acceptably reproduce the additional
+    ! observations, then select (10 - norb) orbits that have the
+    ! smallest chi2 wrt the additional observations:
+    IF (COUNT(mask) < 10) THEN
+       information_matrix_obs => getBlockDiagInformationMatrix(obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (15)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          RETURN
+       END IF
+       ALLOCATE(chi2_arr(norb), mask_(norb), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "Could not allocate memory (10)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(chi2_arr, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          RETURN
+       END IF
+       mask_ = mask
+       DO i=1,norb
+          chi2_arr(i) = chi_square(residuals(:,i,:), information_matrix_obs, errstr=errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+                  TRIM(errstr), 1)             
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(mask, stat=err)
+             DEALLOCATE(information_matrix_obs, stat=err)
+             DEALLOCATE(chi2_arr, stat=err)
+             DEALLOCATE(mask_, stat=err)
+             RETURN
+          END IF
+       END DO
+       j = COUNT(mask)
+       DO WHILE (COUNT(mask) < 10 .AND. j < norb)
+          j = j + 1
+          i = MINLOC(chi2_arr,1,.NOT.mask)
+          mask(i) = .TRUE.
+       END DO
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,1X,A,1X,I0,1X,A)") "constrainRangeDistributions:", &
+               "RA,Dec residuals corresponding to the", 10-COUNT(mask_), &
+               "additional orbits included [asec]:"
+          DO i=1,SIZE(mask)
+             IF (mask(i) .AND. .NOT.mask_(i)) THEN
+                DO j=1,SIZE(residuals,dim=1)
+                   WRITE(stdout,"(2X,2(A,1X,I0,1X),A,2(1X,F10.3))") &
+                        "Orbit #", i, "& observation #", j, ":", residuals(j,i,2:3)/rad_asec
+                END DO
+             END IF
+          END DO
+       END IF
+       DEALLOCATE(information_matrix_obs, chi2_arr, mask_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "Could not deallocate memory (10)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(information_matrix_obs, stat=err)
+          DEALLOCATE(chi2_arr, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    ! Get observation dates for original data and additional data
+    IF (exist(this%obss)) THEN
+       dates_orig => getDates(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (20)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          RETURN
+       END IF
+       dates_add => getDates(obss)       
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (25)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          RETURN
+       END IF
+    ELSE
+       ALLOCATE(dates_orig(1), dates_add(1), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "Could not allocate memory (15)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          RETURN
+       END IF
+       dates_orig = 1.0_bp
+       dates_add  = 0.0_bp
+    END IF
+
+    ! Re-calculate this%sor_rho_arr_cmp if...
+    IF (& 
+                                ! ...rhos don't exist:
+         .NOT.ASSOCIATED(this%sor_rho_arr_cmp) .OR. & 
+                                ! ...previous observations don't exist -> no way to find out if
+                                ! update needed:
+         .NOT.exist(this%obss) .OR. & 
+                                ! ...additional data earlier than original data:
+         MINVAL(dates_add) < MINVAL(dates_orig) .OR. & 
+                                ! ...additional data later than original data
+         MAXVAL(dates_add) > MAXVAL(dates_orig)) THEN 
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,1X,A)") "constrainRangeDistributions:", &
+               "Re-calculating the rho1 and rho2 distributions..."
+       END IF
+       IF (.NOT.exist(this%obss)) THEN
+          obs = getObservation(obss,1)
+          observers(1) = getObservatoryCCoord(obs)
+          CALL NULLIFY(obs)
+          obs = getObservation(obss,getNrOfObservations(obss))
+          observers(2) = getObservatoryCCoord(obs)
+          CALL NULLIFY(obs)
+       ELSE
+          obss_ = this%obss + obss
+          obs = getObservation(obss_,1)
+          observers(1) = getObservatoryCCoord(obs)
+          CALL NULLIFY(obs)
+          obs = getObservation(obss_,getNrOfObservations(obss_))
+          observers(2) = getObservatoryCCoord(obs)
+          CALL NULLIFY(obs)
+          CALL NULLIFY(obss_)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (30)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          RETURN
+       END IF
+       orb_arr => getSampleOrbits(this)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (35)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err) 
+          DEALLOCATE(orb_arr, stat=err)         
+          RETURN
+       END IF
+       CALL getEphemerides(orb_arr, observers, ephemerides)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "TRACE BACK (40)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          DEALLOCATE(orb_arr, stat=err)         
+          DEALLOCATE(ephemerides, stat=err)         
+          RETURN
+       END IF
+       IF (ASSOCIATED(this%sor_rho_arr_cmp)) THEN
+          DEALLOCATE(this%sor_rho_arr_cmp, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+                  "Could not deallocate memory (15)", 1)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(mask, stat=err)
+             DEALLOCATE(dates_orig, stat=err)
+             DEALLOCATE(dates_add, stat=err)
+             DEALLOCATE(orb_arr, stat=err)         
+             DEALLOCATE(ephemerides, stat=err)         
+             RETURN
+          END IF
+       END IF
+       ALLOCATE(this%sor_rho_arr_cmp(norb,2), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "Could not allocate memory (20)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          DEALLOCATE(orb_arr, stat=err)         
+          DEALLOCATE(ephemerides, stat=err)         
+          RETURN
+       END IF
+       DO i=1,norb
+          this%sor_rho_arr_cmp(i,1) = getDistance(ephemerides(i,1))
+          this%sor_rho_arr_cmp(i,2) = getDistance(ephemerides(i,2))
+          CALL NULLIFY(ephemerides(i,1))
+          CALL NULLIFY(ephemerides(i,2))
+          CALL NULLIFY(orb_arr(i))
+          IF (error) THEN
+             CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+                  "TRACE BACK (45)", 1)
+             DEALLOCATE(residuals, stat=err)
+             DEALLOCATE(mask, stat=err)
+             DEALLOCATE(dates_orig, stat=err)
+             DEALLOCATE(dates_add, stat=err)
+             DEALLOCATE(orb_arr, stat=err)         
+             DEALLOCATE(ephemerides, stat=err)         
+             RETURN
+          END IF
+       END DO
+       CALL NULLIFY(observers(1))
+       CALL NULLIFY(observers(2))
+       DEALLOCATE(ephemerides, orb_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+               "Could not deallocate memory (20)", 1)
+          DEALLOCATE(residuals, stat=err)
+          DEALLOCATE(mask, stat=err)
+          DEALLOCATE(dates_orig, stat=err)
+          DEALLOCATE(dates_add, stat=err)
+          DEALLOCATE(orb_arr, stat=err)         
+          DEALLOCATE(ephemerides, stat=err)         
+          RETURN
+       END IF
+       IF (info_verb >= 2) THEN
+          WRITE(stdout,"(2X,A,1X,A)") "constrainRangeDistributions:", &
+               "Re-calculating the rho1 and rho2 distributions... done"
+       END IF
+    END IF
+    DEALLOCATE(dates_orig, dates_add, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not deallocate memory (25)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       DEALLOCATE(dates_orig, stat=err)
+       DEALLOCATE(dates_add, stat=err)
+       RETURN
+    END IF
+
+    ! Rewrite sor_rho_arr_cmp (N.B. The size of the 1st dimension of
+    ! sor_rho_arr_cmp is no longer necessary equal to norb!)
+    ALLOCATE(sor_rho_arr_cmp(COUNT(mask),2), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not allocate memory (25)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       DEALLOCATE(sor_rho_arr_cmp, stat=err)
+       RETURN
+    END IF
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,1X,A)") "constrainRangeDistributions:", &
+            "Constrained (rho1,rho2-rho1) distribution [AU]: "
+    END IF
+    j = 0
+    DO i=1,SIZE(this%sor_rho_arr_cmp,dim=1)
+       IF (mask(i)) THEN
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(2X,2(1X,F11.7))") &
+                  this%sor_rho_arr_cmp(i,1), &
+                  this%sor_rho_arr_cmp(i,2)-this%sor_rho_arr_cmp(i,1)
+          END IF
+          j = j + 1
+          sor_rho_arr_cmp(j,:) = this%sor_rho_arr_cmp(i,:)
+       END IF
+    END DO
+    DEALLOCATE(this%sor_rho_arr_cmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not deallocate memory (30)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       DEALLOCATE(sor_rho_arr_cmp, stat=err)
+       RETURN
+    END IF
+    ALLOCATE(this%sor_rho_arr_cmp(COUNT(mask),2), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not allocate memory (30)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       RETURN
+    END IF
+    this%sor_rho_arr_cmp = sor_rho_arr_cmp
+    DEALLOCATE(sor_rho_arr_cmp, residuals, mask, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / constrainRangeDistributions", &
+            "Could not deallocate memory (35)", 1)
+       DEALLOCATE(residuals, stat=err)
+       DEALLOCATE(mask, stat=err)
+       DEALLOCATE(sor_rho_arr_cmp, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE constrainRangeDistributions
+
+
+
+
+
+  SUBROUTINE toCartesian_SO(this, frame)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+    CHARACTER(len=*), INTENT(in) :: frame
+
+    CHARACTER(len=FRAME_LEN) :: frame_
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / toCartesian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    frame_ = TRIM(frame)
+    CALL locase(frame_, error)
+    IF (error) THEN
+       CALL errorMessage("StochasticOrbit / toCartesian", &
+            "The frame string contains forbidden characters.", 1)
+       RETURN
+    END IF
+    IF (frame_ /= "equatorial" .AND. &
+         frame_ /= "ecliptic") THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / toCartesian", &
+            "Frame " // TRIM(frame_) // " not recognized.", 1)
+    END IF
+
+    IF (this%element_type_prm == "cartesian") THEN
+       IF (ASSOCIATED(this%orb_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL toCartesian(this%orb_arr_cmp(i), frame_)
+          END DO
+       END IF
+       IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+          this%cov_ml_cmp = getCovarianceMatrix(this, "cartesian", frame_)
+       END IF
+       IF (exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%pdf_arr_cmp)) THEN
+          i = MAXLOC(this%pdf_arr_cmp,dim=1)
+          CALL NULLIFY(this%orb_ml_cmp)
+          this%orb_ml_cmp = copy(this%orb_arr_cmp(i))
+       ELSE IF (exist(this%orb_ml_cmp) .AND. .NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+          CALL toCartesian(this%orb_ml_cmp, frame_)
+       END IF
+    ELSE IF (this%element_type_prm == "cometary" .OR. &
+         this%element_type_prm == "keplerian") THEN
+       IF (ASSOCIATED(this%orb_arr_cmp) .AND. &
+            ASSOCIATED(this%pdf_arr_cmp) .AND. &
+            ASSOCIATED(this%jac_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL toCartesian(this%orb_arr_cmp(i), frame_)
+             !this%pdf_arr_cmp(i) = this%pdf_arr_cmp(i)/this%jac_arr_cmp(i,2)
+          END DO
+          pdf_arr => getPDFValues(this, "cartesian")
+          this%pdf_arr_cmp = pdf_arr
+          DEALLOCATE(pdf_arr)
+       END IF
+       IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+          this%cov_ml_cmp = getCovarianceMatrix(this, "cartesian", frame_)
+          this%cov_type_prm = "cartesian"
+       END IF
+       IF (exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%pdf_arr_cmp)) THEN
+          i = MAXLOC(this%pdf_arr_cmp,dim=1)
+          CALL NULLIFY(this%orb_ml_cmp)
+          this%orb_ml_cmp = copy(this%orb_arr_cmp(i))
+       ELSE IF (exist(this%orb_ml_cmp) .AND. .NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+          CALL toCartesian(this%orb_ml_cmp, frame_)
+       END IF
+       this%element_type_prm = "cartesian"
+    ELSE
+       error =.TRUE.
+       CALL errorMessage("StochasticOrbit / toCartesian", &
+            "Cannot convert from " // TRIM(this%element_type_prm) // &
+            " to Cartesian elements.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE toCartesian_SO
+
+
+
+
+
+  SUBROUTINE toCometary_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / toCometary", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%element_type_prm == "cometary") THEN
+       RETURN
+    END IF
+
+    IF (this%element_type_prm == "cartesian" .OR. &
+         this%element_type_prm == "keplerian") THEN
+       IF (ASSOCIATED(this%orb_arr_cmp) .AND. &
+            ASSOCIATED(this%pdf_arr_cmp) .AND. &
+            ASSOCIATED(this%jac_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL toCometary(this%orb_arr_cmp(i))
+             !this%pdf_arr_cmp(i) = this%pdf_arr_cmp(i)*this%jac_arr_cmp(i,2)
+          END DO
+          pdf_arr => getPDFValues(this, "cometary")
+          this%pdf_arr_cmp = pdf_arr
+          DEALLOCATE(pdf_arr)
+       END IF
+       IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+          this%cov_ml_cmp = getCovarianceMatrix(this, "cometary")
+          this%cov_type_prm = "cometary"
+       END IF
+       IF (exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%pdf_arr_cmp)) THEN
+          i = MAXLOC(this%pdf_arr_cmp,dim=1)
+          CALL NULLIFY(this%orb_ml_cmp)
+          this%orb_ml_cmp = copy(this%orb_arr_cmp(i))
+       ELSE IF (exist(this%orb_ml_cmp) .AND. .NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+          CALL toCometary(this%orb_ml_cmp)          
+       END IF
+       this%element_type_prm = "cometary"
+    ELSE
+       error =.TRUE.
+       CALL errorMessage("StochasticOrbit / toCometary", &
+            "Cannot convert from " // TRIM(this%element_type_prm) // &
+            " to Cometary elements.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE toCometary_SO
+
+
+
+
+
+  SUBROUTINE toKeplerian_SO(this)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)  :: this
+
+    REAL(bp), DIMENSION(:), POINTER :: pdf_arr
+    INTEGER :: i
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / toKeplerian", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (this%element_type_prm == "keplerian") THEN
+       RETURN
+    END IF
+
+    IF (this%element_type_prm == "cartesian" .OR. &
+         this%element_type_prm == "cometary") THEN
+       IF (ASSOCIATED(this%orb_arr_cmp) .AND. &
+            ASSOCIATED(this%pdf_arr_cmp) .AND. &
+            ASSOCIATED(this%jac_arr_cmp)) THEN
+          DO i=1,SIZE(this%orb_arr_cmp)
+             CALL toKeplerian(this%orb_arr_cmp(i))
+             !this%pdf_arr_cmp(i) = this%pdf_arr_cmp(i)*this%jac_arr_cmp(i,2)
+          END DO
+          pdf_arr => getPDFValues(this, "keplerian")
+          this%pdf_arr_cmp = pdf_arr
+          DEALLOCATE(pdf_arr)
+       END IF
+       IF (ASSOCIATED(this%cov_ml_cmp)) THEN
+          this%cov_ml_cmp = getCovarianceMatrix(this, "keplerian")
+          this%cov_type_prm = "keplerian"
+       END IF
+       IF (exist(this%orb_ml_cmp) .AND. ASSOCIATED(this%pdf_arr_cmp)) THEN
+          i = MAXLOC(this%pdf_arr_cmp,dim=1)
+          CALL NULLIFY(this%orb_ml_cmp)
+          this%orb_ml_cmp = copy(this%orb_arr_cmp(i))
+       ELSE IF (exist(this%orb_ml_cmp) .AND. .NOT.ASSOCIATED(this%pdf_arr_cmp)) THEN
+          CALL toKeplerian(this%orb_ml_cmp)          
+       END IF
+       this%element_type_prm = "keplerian"
+    ELSE
+       error =.TRUE.
+       CALL errorMessage("StochasticOrbit / toKeplerian", &
+            "Cannot convert from " // TRIM(this%element_type_prm) // &
+            " to Keplerian elements.", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE toKeplerian_SO
+
+
+
+
+  !! *Description*:
+  !!
+  !! Updates the StochasticOrbit between subsequent calls
+  !! of statistical ranging.
+  !!
+  !! Updates: 
+  !!      - range bounds, currently from the 3-sigma cutoff values 
+  !!         of the range probability density.
+  !!      - Minimum chi2
+  !!      - Optional outlier detection: recognizes outlier observations
+  !!         and optionally flags them (obs_masks -> .false.).
+  !!
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE updateRanging(this, automatic)
+
+    IMPLICIT NONE
+    TYPE(StochasticOrbit), INTENT(inout)  :: this
+    LOGICAL, INTENT(in), OPTIONAL         :: automatic
+
+    CHARACTER(len=128) :: str, frmt
+    REAL(bp), DIMENSION(:,:), POINTER :: stdevs
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: ra_mean, dec_mean
+    REAL(bp) :: ra_std, dec_std
+    INTEGER, DIMENSION(:), ALLOCATABLE :: nr_array
+    INTEGER :: i, nobs, err, nr_of_omitted
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: maskarr
+    LOGICAL :: automatic_
+
+    IF (.NOT. this%is_initialized_prm) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / updateRanging", &
+            "Object has not been initialized.", 1)
+       RETURN
+    END IF
+
+    nobs = getNrOfObservations(this%obss)
+    ALLOCATE(ra_mean(nobs), dec_mean(nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("StochasticOrbit / updateRanging", &
+            "Could not allocate memory (5).", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(automatic)) THEN
+       automatic_ = automatic
+    ELSE
+       automatic_ = .FALSE.
+    END IF
+
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A)") "- - - - - - - - - "
+       WRITE(stdout,"(2X,A)") "UPDATING . . . . ."
+       WRITE(stdout,"(2X,A)") "- - - - - - - - - "
+    END IF
+
+    ! Update range intervals
+    CALL setRangeBounds(this)
+    IF (info_verb >= 2) THEN
+       WRITE(stdout,"(2X,A,4(1X,E10.4))") "Real rho bounds:", &
+            this%sor_rho_cmp(1,1:2), this%sor_rho_cmp(2,1:2)
+       WRITE(stdout,"(2X,A,4(1X,E10.4))") "New rho bounds: ", &
+            this%sor_rho_prm(1,1:2), this%sor_rho_prm(2,1:2)
+    END IF
+
+    DO i=1,nobs
+       CALL moments(this%res_arr_cmp(:,i,2), mean=ra_mean(i), &
+            std_dev=ra_std, errstr=errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / updateRanging", &
+               "Error in moment computation for RA " // &
+               TRIM(errstr), 1)
+          RETURN
+       END IF
+       CALL moments(this%res_arr_cmp(:,i,3), mean=dec_mean(i), &
+            std_dev=dec_std, errstr=errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / updateRanging", &
+               "Error in moment computation for Dec " // &
+               TRIM(errstr), 1)
+          RETURN
+       END IF
+    END DO
+
+    IF (info_verb >= 3) THEN
+       WRITE(stdout,"(2X,A)") "Residual offsets, R.A. & Dec:"
+       DO i=1,nobs
+          WRITE(stdout,"(2X,A,I0,A,2(1X,F10.5))") "Obs no ", i, ":", &
+               ra_mean(i)/rad_asec, dec_mean(i)/rad_asec
+       END DO
+    END IF
+
+    ! Update minimum chi2 value and generating windows
+    this%chi2_min_prm = this%chi2_min_cmp
+
+    ! Recognize outlier observations
+    IF (this%outlier_multiplier_prm > 0.0_bp) THEN
+       ALLOCATE(nr_array(nobs), maskarr(nobs), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / updateRanging", &
+               "Could not allocate memory (10).", 1)
+          RETURN
+       END IF
+       nr_array = RESHAPE((/ (i, i = 1,nobs) /), (/ nobs /))
+       obs_masks => getObservationMasks(this%obss, use_notes=.TRUE.)
+       stdevs => getStandardDeviations(this%obss)
+       IF (error) THEN
+          CALL errorMessage("StochasticOrbit / updateRanging", &
+               "TRACE BACK ()", 1)
+          RETURN
+       END IF
+       maskarr = .FALSE.
+       DO i=1,nobs
+          IF (ABS(ra_mean(i)) > this%outlier_multiplier_prm*stdevs(i,2) .OR. &
+               ABS(dec_mean(i)) > this%outlier_multiplier_prm*stdevs(i,3)) THEN
+             obs_masks(i,1:6) = .FALSE.
+             maskarr(i) = .TRUE.
+          END IF
+       END DO
+
+       nr_of_omitted = COUNT(maskarr)
+       IF (this%outlier_rejection_prm) THEN
+          ! Remove outlier observations
+          this%obs_masks_prm = obs_masks
+          IF (info_verb >= 2) THEN
+             IF (nr_of_omitted == 0) THEN
+                WRITE(stdout,"(2X,A)") "No of omitted: 0"
+             ELSE IF (nr_of_omitted == 1) THEN
+                WRITE(stdout,"(2X,A,2(I0,A))") "No of omitted: ", &
+                     nr_of_omitted,"(",PACK(nr_array,maskarr),")"
+             ELSE IF (nr_of_omitted >= 2) THEN
+                str = " "
+                CALL toString(nr_of_omitted-1, str, error)
+                IF (error) THEN
+                   CALL errorMessage("StochasticOrbit / updateRanging", &
+                        "Error in conversion from integer to character.", 1)
+                   RETURN
+                END IF
+                frmt = "(A,I0,A,I0," // TRIM(str) // "(1X,I0),A)"
+                WRITE(stdout,TRIM(frmt)) "No of omitted: ", &
+                     nr_of_omitted," (",PACK(nr_array,maskarr),")"
+             END IF
+          END IF
+       ELSE IF (nr_of_omitted > 0) THEN
+          IF (info_verb >= 2) THEN
+             WRITE(stdout,"(1X)")
+             WRITE(stdout,"(2X,A,I0)") "WARNING from updateRanging: " // &
+                  "potential outlier observations detected! No: ", nr_of_omitted
+          END IF
+       END IF
+       IF (info_verb >= 3 .AND. this%outlier_rejection_prm) THEN
+          WRITE(stdout,"(2X,A)") &
+               "Obs mask after update + mean RA and Dec:"
+          DO i=1,SIZE(this%obs_masks_prm,dim=1)
+             WRITE(stdout,"(2X,A,I0,A,6(1X,L1),2(1X,F10.5))") &
+                  "Obs #", i, ":", this%obs_masks_prm(i,:), &
+                  ra_mean(i)/rad_asec, dec_mean(i)/rad_asec
+          END DO
+       END IF
+       DEALLOCATE(nr_array, obs_masks, maskarr, stdevs, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("StochasticOrbit / updateRanging", &
+               "Could not deallocate memory (5).", 1)
+          RETURN
+       END IF
+    END IF
+
+    DEALLOCATE(ra_mean, dec_mean, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(ra_mean, stat=err)
+       DEALLOCATE(dec_mean, stat=err)
+       CALL errorMessage("StochasticOrbit / updateRanging", &
+            "Could not deallocate memory (10).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE updateRanging
+
+
+
+
+END MODULE StochasticOrbit_cl
Index: trunk/mops/oorb/classes/Time_class.f90
===================================================================
--- trunk/mops/oorb/classes/Time_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Time_class.f90	(revision 34646)
@@ -0,0 +1,1600 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Type and routines for time.
+!!
+!! @see CartesianCoordinates_class
+!! @see SphericalCoordinates_class
+!! @see Orbit_class
+!! 
+!! @author  MG, JV
+!! @version 2009-10-16
+!!
+MODULE Time_cl
+
+  USE Base_cl
+  USE File_cl
+
+  USE utilities
+
+  IMPLICIT NONE
+  ! Error limit for iterations:
+  REAL(bp), PARAMETER, PRIVATE                 :: epst = 1.0e-10_bp
+  ! Max number of iterations:
+  INTEGER, PARAMETER, PRIVATE                  :: nitmax = 5
+  INTEGER, PARAMETER, PRIVATE                  :: nitutc = 20
+  REAL(bp), DIMENSION(:), POINTER, PRIVATE     :: tv
+  REAL(bp), DIMENSION(:), POINTER, PRIVATE     :: dtv
+  INTEGER, DIMENSION(:), POINTER, PRIVATE      :: mjdv
+  INTEGER, DIMENSION(:), POINTER, PRIVATE      :: idv
+  INTEGER, PRIVATE                             :: jp
+  INTEGER, PRIVATE                             :: ipos
+  INTEGER, PRIVATE                             :: taiut_size
+  INTEGER, PRIVATE                             :: etut_size
+  LOGICAL, PRIVATE                             :: first = .TRUE.
+
+  PRIVATE :: new_T
+  PRIVATE :: new_T_cd_long
+  PRIVATE :: new_T_cd_short
+  PRIVATE :: new_T_mjd
+  PRIVATE :: nullify_T  
+  PRIVATE :: copy_T  
+  PRIVATE :: exist_T  
+  PRIVATE :: equal_T  
+  PRIVATE :: deltaAT
+  PRIVATE :: deltaT
+  PRIVATE :: getCalendarDate_long
+  PRIVATE :: getCalendarDate_short
+  PRIVATE :: getCurrentTime_values
+  PRIVATE :: getMJD_t
+  PRIVATE :: getMJD_cd
+  PRIVATE :: reallocate_T_1
+  PRIVATE :: timescaleConversion
+  PRIVATE :: toNormalForm
+
+  TYPE Time
+     PRIVATE
+     REAL(bp) :: tdt            =  0.0_bp
+     REAL(bp) :: utc            =  0.0_bp
+     REAL(bp) :: tai            =  0.0_bp
+     REAL(bp) :: ut1            =  0.0_bp
+     LOGICAL  :: is_initialized = .FALSE.
+  END TYPE Time
+
+  INTERFACE NEW
+     MODULE PROCEDURE new_T
+     MODULE PROCEDURE new_T_cd_long
+     MODULE PROCEDURE new_T_cd_short
+     MODULE PROCEDURE new_T_mjd
+     MODULE PROCEDURE new_T_MPC
+  END INTERFACE
+
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_T
+  END INTERFACE
+
+  INTERFACE copy
+     MODULE PROCEDURE copy_T
+  END INTERFACE
+
+  INTERFACE exist
+     MODULE PROCEDURE exist_T
+  END INTERFACE
+
+  INTERFACE equal
+     MODULE PROCEDURE equal_T
+  END INTERFACE
+
+  INTERFACE getCalendarDate
+     MODULE PROCEDURE getCalendarDate_long
+     MODULE PROCEDURE getCalendarDate_short
+  END INTERFACE
+
+  INTERFACE getCurrentTime
+     MODULE PROCEDURE getCurrentTime_values
+  END INTERFACE
+
+  INTERFACE getMJD
+     MODULE PROCEDURE getMJD_t
+     MODULE PROCEDURE getMJD_cd
+  END INTERFACE
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_T_1
+  END INTERFACE
+
+CONTAINS
+
+
+
+
+  !! *Desription*:
+  !!
+  !! Initializes a new object using default values.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_T(this)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout) :: this
+    TYPE (Time) :: t
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (first) THEN
+       CALL NEW(t, 0.0_bp, "tdt")
+       CALL NULLIFY(t)
+    END IF
+
+    this%tdt = -1.0_bp
+    this%ut1 = -1.0_bp
+    this%utc = -1.0_bp
+    this%tai = -1.0_bp
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_T
+
+
+
+
+
+  !! *Desription*:
+  !!
+  !! Initializes a new object using values given as a calendar 
+  !! date.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_T_cd_long(this, year, month, day, hour, min, sec, timescale)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    INTEGER, INTENT(in)          :: year, month, day, hour, min
+    REAL(bp), INTENT(in)         :: sec
+    CHARACTER(len=*), INTENT(in) :: timescale
+    REAL(bp)                     :: mjd, tmp
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    tmp = REAL(day,bp) + (REAL(hour,bp) + REAL(min,bp)/60.0_bp + sec/3600.0_bp)/24.0_bp
+    mjd = getMJD(year, month, tmp)
+    CALL NEW(this, mjd, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_T_cd_long
+
+
+
+
+
+  !! *Desription*:
+  !!
+  !! Initializes a new object using values given as a calendar 
+  !! date.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_T_cd_short(this, year, month, day, timescale)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    INTEGER, INTENT(in)          :: year, month
+    REAL(bp), INTENT(in)         :: day
+    CHARACTER(len=*), INTENT(in) :: timescale
+    REAL(bp)                     :: mjd
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+    mjd = getMJD(year, month, day)
+    CALL NEW(this, mjd, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_T_cd_short
+
+
+
+
+
+  !! *Desription*:
+  !!
+  !! Initializes a new object using values 
+  !! given as a MPC packed date.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_T_MPC(this, packed_date, timescale)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: packed_date
+    CHARACTER(len=*), INTENT(in) :: timescale
+    CHARACTER(len=31), PARAMETER :: coding = &
+         "123456789ABCDEFGHIJKLMNOPQRSTUV"
+    INTEGER                      :: year, month
+    REAL(bp)                     :: day
+    INTEGER                      :: tmp, n
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    tmp = INDEX(coding, packed_date(1:1))
+    CALL toInt(packed_date(2:3), year, error)
+    IF (error) THEN
+       CALL errorMessage("Time / new", &
+            "Could not transform string to integer (1).", 1)
+       RETURN
+    END IF
+    year = tmp*100 + year
+    month = INDEX(coding, packed_date(4:4))
+    day = REAL(INDEX(coding, packed_date(5:5)),bp)
+    n = LEN_TRIM(packed_date)
+    IF (n > 5) THEN
+       CALL toInt(packed_date(6:n), tmp, error)
+       IF (error) THEN
+          CALL errorMessage("Time / new", &
+               "Could not transform string to integer (2).", 1)
+          RETURN
+       END IF
+       day = day + tmp/10.0_bp**(n-5)
+    END IF
+
+    CALL NEW(this, year, month, day, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_T_MPC
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new object using values given as a modified 
+  !! Julian date.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE new_T_mjd(this, mjd, timescale)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    REAL(bp), INTENT(in)         :: mjd
+    CHARACTER(len=*), INTENT(in) :: timescale
+    TYPE (File)                  :: datafile
+    CHARACTER(len=10)            :: record
+    REAL(bp)                     :: dt, iii
+    INTEGER                      :: err, year, month, day, &
+         taiut_max, etut_max
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (first) THEN
+
+       ! Load table of TAI-UTC as a function of the day:
+       CALL NEW(datafile, TRIM(OORB_DATA_DIR) // &
+            "/" // TRIM(TAIUTC_FNAME))
+       CALL setActionRead(datafile)
+       CALL setStatusOld(datafile)
+       CALL OPEN(datafile)
+       IF (error) THEN
+          CALL errorMessage("Time / new", &
+               "TRACE BACK 3", 1)
+          RETURN
+       END IF
+       taiut_max = getNrOfLines(datafile)
+       ALLOCATE(idv(taiut_max), mjdv(taiut_max), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Time / new", &
+               "Could not allocate arrays for TAI-UT.", 1)
+          RETURN
+       END IF
+       DO
+          READ(getUnit(datafile), "(A)", iostat=err) record
+          IF (err <  0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "End of file " // TRIM(TAIUTC_FNAME), 1)
+             RETURN
+          ELSE IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "Could not read file " // TRIM(TAIUTC_FNAME), 1)
+             RETURN
+          ELSE
+             IF (record == "----------") EXIT
+          END IF
+       END DO
+       taiut_size = 0
+       DO
+          READ(getUnit(datafile),*,iostat=err) day, month, year, iii
+          IF (err <  0) THEN
+             EXIT
+          ELSE IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "Could not read file " // TRIM(TAIUTC_FNAME), 1)
+             RETURN
+          ELSE
+             taiut_size = taiut_size + 1
+             idv(taiut_size) = iii
+             mjdv(taiut_size) = NINT(getMJD(year,month,day*1.0_bp))
+             IF (taiut_size > 1) THEN
+                IF (mjdv(taiut_size) <= mjdv(taiut_size-1)) THEN
+                   error  = .TRUE.
+                   CALL errorMessage("Time / new", &
+                        "File " // TRIM(TAIUTC_FNAME) // " is not sorted.", 1)
+                   RETURN
+                END IF
+             END IF
+          END IF
+       END DO
+       jp = 2
+       CALL NULLIFY(datafile)
+       IF (error) THEN
+          CALL errorMessage("Time / new", &
+               "TRACE BACK 4", 1)
+          RETURN
+       END IF
+       IF (taiut_size < 2) THEN
+          error = .TRUE.
+          CALL errorMessage("Time / new", &
+               "File " // TRIM(TAIUTC_FNAME) // &
+               " contains less than two data records.", 1)
+          RETURN
+       END IF
+
+       ! Load table of ET-UT as a function of UT:
+       CALL NEW(datafile, TRIM(OORB_DATA_DIR) // "/" &
+            // TRIM(ETUT_FNAME))
+       CALL setActionRead(datafile)
+       CALL setStatusOld(datafile)
+       CALL OPEN(datafile)
+       IF (error) THEN
+          CALL errorMessage("Time / new", &
+               "TRACE BACK 7", 1)
+          RETURN
+       END IF
+       etut_max = getNrOfLines(datafile)
+       ALLOCATE(tv(etut_max), dtv(etut_max), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Time / new", &
+               "Could not allocate arrays for ET-UT.", 1)
+          RETURN
+       END IF
+       DO
+          READ(getUnit(datafile), "(A)", iostat=err) record
+          IF (err <  0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "End of file" // TRIM(ETUT_FNAME), 1)
+             RETURN
+          ELSE IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "Could not read file " // TRIM(ETUT_FNAME), 1)
+             RETURN
+          ELSE
+             IF (record == "----------") EXIT
+          END IF
+       END DO
+       etut_size = 0
+       DO
+          READ(getUnit(datafile),*,iostat=err) day, month, year, dt
+          IF (err <  0) THEN
+             EXIT
+          ELSE IF (err > 0) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / new", &
+                  "Could not read file " // TRIM(ETUT_FNAME), 1)
+             RETURN
+          ELSE
+             etut_size = etut_size + 1
+             tv(etut_size) = getMJD(year, month, day*1.0_bp)
+             dtv(etut_size) = dt
+          END IF
+       END DO
+       ipos = 1
+       CALL NULLIFY(datafile)
+       IF (etut_size < 2) THEN
+          error = .TRUE.
+          CALL errorMessage("Time / new", &
+               "File " // TRIM(ETUT_FNAME) // &
+               " contains less than two data records.", 1)
+          RETURN
+       END IF
+
+       first = .FALSE.
+
+    END IF
+
+    SELECT CASE (TRIM(timescale))
+    CASE ("ut1", "UT1")
+       this%ut1 = mjd
+       CALL timescaleConversion(mjd, "UT1", this%tdt, "TDT")
+       this%utc = -1.0_bp
+       this%tai = -1.0_bp
+    CASE ("tai", "TAI")
+       this%tai = mjd
+       CALL timescaleConversion(mjd, "TAI", this%tdt, "TDT")
+       this%ut1 = -1.0_bp
+       this%utc = -1.0_bp
+    CASE ("utc", "UTC")
+       this%utc = mjd
+       CALL timescaleConversion(mjd, "UTC", this%tdt, "TDT")
+       this%tai = -1.0_bp
+       this%ut1 = -1.0_bp
+    CASE ("tdt", "TDT", "et", "ET", "tt", "TT")
+       this%tdt  = mjd
+       this%utc = -1.0_bp
+       this%tai = -1.0_bp
+       this%ut1 = -1.0_bp
+    CASE default
+       error = .TRUE.
+       CALL errorMessage("Time / new", &
+            "Type of time is either missing or erroneus.", 1)
+       RETURN
+    END SELECT
+    IF (error) THEN
+       CALL errorMessage("Time / new", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+    this%is_initialized = .TRUE.
+
+  END SUBROUTINE new_T_mjd
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Nullifies this object.
+  !!
+  SUBROUTINE nullify_T(this)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout) :: this
+
+    this%tdt            = -1.0_bp
+    this%utc            = -1.0_bp
+    this%tai            = -1.0_bp
+    this%ut1            = -1.0_bp
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_T
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Deallocates the memory required for storing time-difference tables.
+  !!
+  SUBROUTINE nullifyTime()
+
+    IMPLICIT NONE
+    INTEGER :: err
+
+    IF (ASSOCIATED(tv)) THEN
+       DEALLOCATE(tv, stat=err)
+    END IF
+    IF (ASSOCIATED(dtv)) THEN
+       DEALLOCATE(dtv, stat=err)
+    END IF
+    IF (ASSOCIATED(mjdv)) THEN
+       DEALLOCATE(mjdv, stat=err)
+    END IF
+    IF (ASSOCIATED(idv)) THEN
+       DEALLOCATE(idv, stat=err)
+    END IF
+
+  END SUBROUTINE nullifyTime
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_T(this)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(in) :: this
+    TYPE (Time)             :: copy_T
+
+    copy_T%tdt            = this%tdt
+    copy_T%utc            = this%utc
+    copy_T%ut1            = this%ut1
+    copy_T%tai            = this%tai
+    copy_T%is_initialized = this%is_initialized
+
+  END FUNCTION copy_T
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of this object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_T(this)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(in) :: this
+
+    exist_T = this%is_initialized
+
+  END FUNCTION exist_T
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns difference DAT = TAI - UTC as a function of UTC.
+  !!
+  !! INPUT:    mjdc    - Modified Julian Day (UTC)
+  !!
+  !! OUTPUT:   deltaAT - TAI-UTC given as an integer number
+  !!           of seconds
+  !!
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  !! Returns error.
+  !!
+  INTEGER FUNCTION deltaAT(mjdc)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in)  :: mjdc
+    INTEGER              :: i
+
+    ! Trying to use previous value
+    IF(mjdc >= mjdv(jp-1) .AND. mjdc < mjdv(jp)) THEN
+       deltaAT = idv(jp-1)
+       RETURN
+    END IF
+
+    ! Selecting the records of the table before and after the date
+    ! supplied
+    IF (mjdc < mjdv(1)) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / deltaAT", &
+            "TJM too small.", 1)
+       RETURN
+    ELSE IF (mjdc >= mjdv(taiut_size)) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / deltaAT", &
+            "TJM too large.", 1)
+       RETURN
+    ELSE
+       DO i=2, taiut_size
+          IF (mjdc < mjdv(i)) THEN
+             jp = i
+             deltaAT = idv(jp-1)
+             RETURN
+          END IF
+       END DO
+    END IF
+
+  END FUNCTION deltaAT
+
+
+
+
+
+  !! Description:
+  !!
+  !! Returns delta T = ET - UT.
+  !!
+  !! INPUT:    tjm       -  Modified Julian Day (UT1)
+  !!
+  !! OUTPUT:   deltaT    -  ET - UT1 (in seconds)
+  !!
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION deltaT(tjm)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in) :: tjm
+    REAL(bp)             :: c1, c2
+
+    IF (.NOT.ASSOCIATED(dtv)) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / deltaT", &
+            "dtv has not been initialized.", 1)
+       RETURN
+    END IF
+
+    ! Trying to use previous value
+    IF (tjm >= tv(ipos) .AND. tjm <= tv(ipos+1)) THEN
+       c1 = (tv(ipos+1) - tjm) / (tv(ipos+1) - tv(ipos))
+       c2 = 1 - c1
+       deltaT = c1*dtv(ipos) + c2*dtv(ipos+1)
+       RETURN
+    END IF
+    ! Selecting the records of the table before and after the date
+    ! supplied
+    IF (tjm < tv(1) .OR. tjm > tv(etut_size)) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / deltaT", &
+            "TJM out of range", 1)
+       RETURN
+    ELSE
+       DO ipos=1,etut_size-1
+          IF (tjm >= tv(ipos) .AND. tjm <= tv(ipos+1)) THEN
+             c1 = (tv(ipos+1) - tjm) / (tv(ipos+1) - tv(ipos))
+             c2 = 1 - c1
+             deltaT = c1*dtv(ipos) + c2*dtv(ipos+1)
+             RETURN
+          END IF
+       END DO
+       error = .TRUE.
+       CALL errorMessage("Time / deltaT", &
+            "Internal error.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION deltaT
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns .true., if the absolute difference of the
+  !! objects is less than epsilon, and .false. otherwise.
+  !!
+  LOGICAL FUNCTION equal_T(this, that)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(in) :: this, that
+
+    IF (ABS(this%tdt-that%tdt) < EPSILON(this%tdt)) THEN
+       equal_T = .TRUE.
+    ELSE
+       equal_T = .FALSE.
+    END IF
+
+  END FUNCTION equal_T
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !! 
+  !!  - TDT (Terrestrial Dynamical Time; 
+  !!          = ET (Ephemeris Time) 
+  !!          = TT (Terrestrial Time)), or
+  !!  - TAI (Atomic Time, french Temps Atomique International), or
+  !!  - UTC (Coordinated Universal Time), or
+  !!  - UT1 (UT + pole variation)
+  !!
+  !! as a Calendar Date. Default timescale is UTC.
+  !!
+  !! Returns error.
+  !! 
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  SUBROUTINE getCalendarDate_long(this, timescale, year, month, day, hour, min, sec)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: timescale
+    INTEGER, INTENT(out)         :: year, month, day, hour, min
+    REAL(bp), INTENT(out)        :: sec
+    REAL(bp)                     :: aa, mjd, tmp
+    INTEGER                      :: a, b, c, d, e, f
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getCalendarDate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd = getMJD(this, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / getCalendarDate", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    aa = mjd + 2400001.0_bp
+    a = INT(aa)
+    IF (a < 2299161) THEN
+       c = a + 1524
+    ELSE
+       b = FLOOR((a-1867216.25_bp)/36524.25_bp)
+       c = a + b - FLOOR(b/4.0_bp) + 1525
+    END IF
+    d = FLOOR((c-122.1_bp)/365.25_bp)
+    e = FLOOR(365.25_bp*d)
+    f = FLOOR((c-e)/30.6001_bp)
+    tmp = c - e - FLOOR(30.6001_bp*f) + (aa - a)
+    ! date:
+    day = FLOOR(tmp)
+    month = f - 1 - 12*FLOOR(f/14.0_bp)
+    year = d - 4715 - FLOOR((7+month)/10.0_bp)
+    ! time:
+    tmp = 24.0_bp*(tmp - day)
+    hour = FLOOR(tmp)
+    tmp = 60.0_bp*(tmp - hour)
+    min = FLOOR(tmp)
+    sec = 60.0_bp*(tmp - min)
+
+  END SUBROUTINE getCalendarDate_long
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !! 
+  !!  - TDT (Terrestrial Dynamical Time; 
+  !!          = ET (Ephemeris Time) 
+  !!          = TT (Terrestrial Time)), or
+  !!  - TAI (Atomic Time, french Temps Atomique International), or
+  !!  - UTC (Coordinated Universal Time), or
+  !!  - UT1 (UT + pole variation)
+  !!
+  !! as a Calendar Date. Default timescale is UTC.
+  !!
+  !! Returns error.
+  !! 
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  SUBROUTINE getCalendarDate_short(this, timescale, year, month, day)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: timescale
+    INTEGER, INTENT(out)         :: year, month
+    REAL(bp), INTENT(out)        :: day
+    REAL(bp)                     :: aa, mjd
+    INTEGER                      :: a, b, c, d, e, f
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getCalendarDate", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd = getMJD(this, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / getCalendarDate", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    aa = mjd + 2400001.0_bp
+    a = INT(aa)
+    IF (a < 2299161) THEN
+       c = a + 1524
+    ELSE
+       b = FLOOR((a-1867216.25_bp)/36524.25_bp)
+       c = a + b - FLOOR(b/4.0_bp) + 1525
+    END IF
+    d = FLOOR((c-122.1_bp)/365.25_bp)
+    e = FLOOR(365.25_bp*d)
+    f = FLOOR((c-e)/30.6001_bp)
+    day = c - e - FLOOR(30.6001_bp*f) + (aa - a)
+    month = f - 1 - 12*FLOOR(f/14.0_bp)
+    year = d - 4715 - FLOOR((7+month)/10.0_bp)
+
+  END SUBROUTINE getCalendarDate_short
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the calendar date as a string (_yyyy_mm_dd.dddddd_).
+  !!
+  !! Returns error.
+  !!
+  CHARACTER(len=17) FUNCTION getCalendarDateString(this, timescale) RESULT(str)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: timescale
+    REAL(bp)                     :: day, sec
+    INTEGER                      :: err, year, month, day_, hour, min
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getCalendarDateString", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    CALL getCalendarDate(this, timescale, year, month, day_, hour, min, sec)
+    IF (error) THEN
+       CALL errorMessage("Time / getCalendarDateString", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    day = day_ + (hour + min/60.0_bp + sec/3600.0_bp)/24.0_bp
+    WRITE(str, "(I4,1X,I2,1X,F9.6)", iostat=err) year, month, day
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getCalendarDateString", &
+            "Could not write output string.", 1)
+       str = "*****ERROR*****"
+       RETURN
+    END IF
+
+  END FUNCTION getCalendarDateString
+
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This routine returns the current date and time of any timezone
+  !! given the difference between the needed timezone and the timezone
+  !! of the computer (e.g., for a Helsinki based computer timezone
+  !! should be set to -2 to get Greenwich time).
+  !!
+  !! Programming interface:
+  !!
+  !! integer getCurrentTime(1) is day
+  !! integer getCurrentTime(2) is month (Jan=1,...,Dec=12)
+  !! integer getCurrentTime(3) is year
+  !! integer getCurrentTime(4) is hour
+  !! integer getCurrentTime(5) is minute
+  !! integer getCurrentTime(6) is second
+  !!
+  !! Returns error.
+  !!
+  FUNCTION getCurrentTime_values(timezone)
+
+    IMPLICIT NONE
+    INTEGER, DIMENSION(6) :: getCurrentTime_values
+    REAL(bp), INTENT(in)  :: timezone
+    TYPE (Time)           :: t
+    REAL(kind=bp)         :: mjd, s, day
+    INTEGER, DIMENSION(8) :: date_time
+
+    IF (first) THEN
+       CALL NEW(t, 54000.0_bp, "tdt")
+       CALL NULLIFY(t)
+    END IF
+
+    CALL DATE_AND_TIME(values=date_time)
+    day = REAL(date_time(3),bp) + (REAL(date_time(5),bp) + &
+         REAL(date_time(6),bp)/60.0_bp + &
+         REAL(date_time(7),bp)/3600.0_bp)/hour_day
+    mjd = getMJD(date_time(1), date_time(2), day) + timezone/24.0_bp
+    CALL NEW(t, mjd, "utc")
+    IF (error) THEN
+       CALL errorMessage("Time / getCurrentTime", "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    CALL getCalendarDate(t, "utc", date_time(1), date_time(2), &
+         date_time(3), date_time(5), date_time(6), s)
+    IF (error) THEN
+       CALL errorMessage("Time / getCurrentTime", "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    date_time(7) = NINT(s)
+    CALL NULLIFY(t)
+
+    ! If seconds rounds to 60 then add half a second to the Julian
+    ! date and recalculate the calendar date:
+    IF (date_time(7) == 60) THEN
+       mjd = mjd + 0.5d0/86400.0d0
+       CALL NEW(t, mjd, "utc")
+       IF (error) THEN
+          CALL errorMessage("Time / getCurrentTime", "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL getCalendarDate(t, "utc", date_time(1), date_time(2), &
+            date_time(3), date_time(5), date_time(6), s)
+       IF (error) THEN
+          CALL errorMessage("Time / getCurrentTime", "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       date_time(7) = NINT(s)
+       CALL NULLIFY(t)
+    END IF
+    getCurrentTime_values(1:3) = date_time(1:3)
+    getCurrentTime_values(4:6) = date_time(5:7)
+
+  END FUNCTION getCurrentTime_values
+
+
+
+
+
+  !!
+  !! Greenwich Mean Sidereal Time as a function of UT1        
+  !!
+  !! INPUT:    TJM       -  Modified Julian Time (UT1)
+  !!
+  !! OUTPUT:   GMST      -  Greenwich Mean Sidereal Time referred
+  !!                        to the mean equinox of date (rad)
+  !!
+  !! Based on routines by Mario Carpino (carpino@brera.mi.astro.it)
+  !!
+  REAL(bp) FUNCTION getGMST(this)
+
+    IMPLICIT NONE
+
+    TYPE(Time), INTENT(inout) :: this
+    INTEGER                :: itjm,i
+    REAL(bp)               :: t0,tjm,gmst0,gmst,h
+    REAL(bp), PARAMETER    :: c0  = 24110.54841_bp, c1 = 8640184.812866_bp,&
+         c2  = 9.3104e-2_bp,   c3 =-6.2e-6_bp, &
+         rap = 1.00273790934_bp
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getGMST", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    tjm = getMJD(this, "UT1")
+    ! Sidereal time at 0h UT1
+    itjm = tjm
+    t0 = (itjm-51544.5_bp)/36525.0_bp
+    gmst0 = ((c3*t0+c2)*t0+c1)*t0 + c0
+    gmst0 = gmst0*two_pi/86400.0_bp
+
+    ! Increment in GMST from 0h
+    h = (tjm-itjm)*two_pi
+    gmst = gmst0 + h*rap
+    i = gmst/two_pi
+    IF (gmst < 0.0_bp) THEN
+       i = i - 1
+    END IF
+    gmst = gmst - i*two_pi
+
+    getGMST = gmst
+
+  END FUNCTION getGMST
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !! 
+  !!  - TDT (Terrestrial Dynamical Time; 
+  !!          = ET (Ephemeris Time) 
+  !!          = TT (Terrestrial Time)), or
+  !!  - TAI (Atomic Time, french Temps Atomique International), or
+  !!  - UTC (Coordinated Universal Time), or
+  !!  - UT1 (UT + pole variation)
+  !! 
+  !! of this Time object as a Julian Date.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getJD(this, timescale) RESULT(jd)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: timescale
+    REAL(bp)                     :: mjd
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getJD", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    mjd = getMJD(this, timescale)
+    IF (error) THEN
+       CALL errorMessage("Time / getJD", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    jd = mjd + 2400000.5_bp 
+
+  END FUNCTION getJD
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !! 
+  !!  - TDT (Terrestrial Dynamical Time; 
+  !!          = ET (Ephemeris Time) 
+  !!          = TT (Terrestrial Time)), or
+  !!  - TAI (Atomic Time, french Temps Atomique International), or
+  !!  - UTC (Coordinated Universal Time), or
+  !!  - UT1 (UT + pole variation)
+  !! 
+  !! of this Time object as a Modified Julian Date.
+  !!
+  !! Returns error.
+  !!
+  REAL(bp) FUNCTION getMJD_t(this, timescale) RESULT(mjd)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(inout)   :: this
+    CHARACTER(len=*), INTENT(in) :: timescale
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / getMJD", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    SELECT CASE (TRIM(timescale))
+    CASE ("ut1", "UT1")
+       IF (this%ut1 < 0.0_bp) THEN
+          CALL timescaleConversion(this%tdt, "TDT", mjd, "UT1")
+          IF (error) THEN
+             CALL errorMessage("Time / getMJD", &
+                  "TRACE BACK (5)", 1)
+             RETURN
+          END IF
+          this%ut1 = mjd
+       ELSE
+          mjd = this%ut1
+       END IF
+    CASE ("tai", "TAI")
+       IF (this%tai < 0.0_bp) THEN
+          CALL timescaleConversion(this%tdt, "TDT", mjd, "TAI")
+          IF (error) THEN
+             CALL errorMessage("Time / getMJD", &
+                  "TRACE BACK (10)", 1)
+             RETURN
+          END IF
+          this%tai = mjd
+       ELSE
+          mjd = this%tai
+       END IF
+    CASE ("utc", "UTC")
+       IF (this%utc < 0.0_bp) THEN
+          CALL timescaleConversion(this%tdt, "TDT", mjd, "UTC")
+          IF (error) THEN
+             CALL errorMessage("Time / getMJD", &
+                  "TRACE BACK (15)", 1)
+             RETURN
+          END IF
+          this%utc = mjd
+       ELSE
+          mjd = this%utc
+       END IF
+    CASE ("tdt", "TDT", "et", "ET", "tt", "TT")
+       mjd = this%tdt
+    CASE default
+       error = .TRUE.
+       CALL errorMessage("Time / getMJD", &
+            "Timescale " // TRIM(timescale) // " is erroneus.", 1)
+       RETURN
+    END SELECT
+
+  END FUNCTION getMJD_t
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes the Modified Julian Date from Calendar Date.
+  !!
+  !! INPUT:    year   -  Year (e.g.: 1987)
+  !!           month  -  Month of the year ( 1 <= month <= 12 )
+  !!           day    -  Day of the month ( 1.0 <= day < 32.0 )
+  !!
+  !! OUTPUT:   getMJD -  Modified Julian Day MJD = JD - 2,400,000.5
+  !!
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  REAL(bp) FUNCTION getMJD_cd(year, month, day)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in)  :: month, year
+    REAL(bp), INTENT(in) :: day
+    INTEGER              :: k1, k2, ib, month_, year_
+
+    year_ = year
+    month_ = month
+    DO WHILE (month_ > 12)
+       month_ = month_ - 12
+       year_ = year_ + 1
+    END DO
+    DO WHILE (month_ <= 2)
+       year_ = year_ - 1
+       month_ = month_ + 12
+    END DO
+    IF (year_ > 1582) THEN
+       ib = year_/400 - year_/100
+    ELSE
+       ib = -2
+       IF (year_ == 1582) THEN
+          IF (month_ > 10) THEN
+             ib = year_/400 - year_/100
+          ELSE IF (month_ == 10 .AND. day >= 15) THEN
+             ib = year_/400 - year_/100
+          END IF
+       END IF
+    END IF
+    k1 = 365.25_bp*year_
+    k2 = 30.6001_bp*(month_+1)
+    getMJD_cd = k1 + k2 + ib - 679004 + day
+
+  END FUNCTION getMJD_cd
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reallocates a pointer array of Time-objects and
+  !! copies the data from the old array to the new array (if it fits).
+  !!
+  !! *Usage*:
+  !!
+  !! mytimes => reallocate(mytimes,4)
+  !!
+  !! Returns error.
+  !!
+  FUNCTION reallocate_T_1(array,n)
+
+    IMPLICIT NONE
+    TYPE (Time), DIMENSION(:), POINTER :: reallocate_T_1, array
+    INTEGER, INTENT(in)                 :: n
+    INTEGER                             :: i, nold, err
+
+    ALLOCATE(reallocate_T_1(n), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / reallocate", &
+            "Could not allocate memory.", 1)
+       reallocate_T_1 => NULL()
+       RETURN
+    END IF
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    DO i=1, MIN(n,nold)
+       reallocate_T_1(i) = copy(array(i))
+    END DO
+    DEALLOCATE(array, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Time / reallocate", &
+            "Could not deallocate memory.", 1)
+       RETURN
+    END IF
+
+  END FUNCTION reallocate_T_1
+
+
+
+
+
+  !! Description:
+  !!
+  !! Conversion of a modified Julian date from one timescale 
+  !! to another.
+  !!
+  !! INPUT:    mjd1      -  Modified Julian Day
+  !!           scale1    -  Input time scale
+  !!           scale2    -  Output (required) time scale
+  !!
+  !! OUTPUT:   mjd2      -  Modified Julian Day
+  !!
+  !! Supported time scales:
+  !!        UT1
+  !!        TAI
+  !!        UTC
+  !!        TDT = TT = ET
+  !!
+  !! Returns error.
+  !!
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  SUBROUTINE timescaleConversion(mjd1, scale1, mjd2, scale2)
+
+    IMPLICIT NONE
+    REAL(bp), INTENT(in)         :: mjd1
+    CHARACTER(len=*), INTENT(in) :: scale1, scale2
+    REAL(bp), INTENT(out)        :: mjd2
+    CHARACTER(len=3)             :: eqsc, eqsc2, scale
+    REAL(bp)                     :: tjm2, dt, tjmt, sec2r, diff, &
+         sect, dat, sec1, sec2
+    INTEGER                      :: loops, nit, mjd2_real, mjdt, mjd2_int
+
+    sec1  = 86400.0_bp*(mjd1 - INT(mjd1))
+    mjd2_int = INT(mjd1)
+    sec2 = sec1
+    ! Current timescale (in which mjd2_int,sec2 are given)
+    scale = scale1
+    eqsc  = scale1
+    eqsc2 = scale2
+
+    loops = 0
+    DO
+       CALL toNormalForm(mjd2_int, sec2, eqsc)
+       IF (error) THEN
+          CALL errorMessage("Time / timescaleConversion", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       ! Required timescale has been reached
+       IF (eqsc == eqsc2) THEN
+          mjd2 = mjd2_int + sec2/86400.0_bp
+          RETURN
+       END IF
+       ! Check on infinite loops
+       IF (loops > 6) THEN
+          error = .TRUE.
+          CALL errorMessage("Time / timescaleConversion", &
+               "Too many loops.", 1)
+          RETURN
+       END IF
+       loops = loops + 1
+       ! Transformations are performed according to the following path:
+       !
+       !                UT1 -- TDT -- TAI -- UTC
+       !
+       IF(eqsc == "UT1") THEN
+          ! Conversion UT1 --> TDT
+          tjm2 = mjd2_int + sec2/86400.0_bp
+          dt = deltaT(tjm2)
+          sec2 = sec2 + dt
+          eqsc = "TDT"
+       ELSE IF (eqsc == "TDT") THEN
+          IF (eqsc2 == "UT1") THEN
+             ! Conversion TDT --> UT1 (iterative method)
+             !   a) computation of DT = TDT - UT1 using (mjd2_int,sec2) (TDT) as an
+             !      approximate value of UT1
+             tjm2 = mjd2_int + sec2/86400.0_bp
+             dt = deltaT(tjm2)
+             !   b) subtract DT from (mjd2_int,sec2), finding a first approximation
+             !      for UT1
+             mjdt = mjd2_int
+             sect = sec2 - dt
+             !   start iterations
+             nit = 0
+             DO
+                CALL toNormalForm(mjdt, sect, "UT1")
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (10)", 1)
+                   RETURN
+                END IF
+                nit = nit + 1
+                IF (nit > nitmax) THEN
+                   error = .TRUE.
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "Abnormal end.",1)
+                   RETURN
+                ENDIF
+                !   c) try to find the starting value of TDT from the approximate
+                !      value of UT1
+                tjmt = mjdt + sect/86400.0_bp
+                dt = deltaT(tjmt)
+                mjd2_real = mjdt
+                sec2r = sect + dt
+                CALL toNormalForm(mjd2_real, sec2r, "TDT")
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (15)", 1)
+                   RETURN
+                END IF
+                !   d) computation of error and correction of the approximate value
+                diff = (mjd2_real-mjd2_int)*86400.0_bp + sec2r - sec2
+                IF(ABS(diff) > epst) THEN
+                   sect = sect - diff
+                ELSE
+                   EXIT
+                END IF
+             END DO
+             mjd2_int = mjdt
+             sec2 = sect
+             eqsc = "UT1"
+          ELSE
+             ! Conversion TDT --> TAI
+             sec2 = sec2 - etmtai
+             eqsc = "TAI"
+          END IF
+       ELSE IF (eqsc == "TAI") THEN
+          IF (eqsc2 == "UTC") THEN
+             ! Conversion TAI --> UTC (iterative method)
+             !   a) computation of DAT = TAI - UTC using (mjd2_int,sec2) (TAI) as an
+             !      approximate value of UTC
+             mjdt = mjd2_int
+             sect = sec2
+             dat = deltaAT(mjdt)
+             IF (error) THEN
+                CALL errorMessage("Time / timescaleConversion", &
+                     "TRACE BACK (20)", 1)
+                RETURN
+             END IF
+             !   b) subtract DAT from (mjd2_int,sec2), finding a first approximation
+             !      for UTC
+             sect = sec2 - dat
+             !   start iterations
+             nit = 0
+             DO
+                CALL toNormalForm(mjdt, sect, "UTC")
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (25)", 1)
+                   RETURN
+                END IF
+                nit = nit + 1
+                IF (nit > nitmax) THEN
+                   error = .TRUE.
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "Abnormal end.",1)
+                   RETURN
+                END IF
+                !   c) try to find the starting value of TAI from the approximate
+                !      value of UTC
+                mjd2_real = mjdt
+                sec2r = sect + deltaAT(mjdt)
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (30)", 1)
+                   RETURN
+                END IF
+                CALL toNormalForm(mjd2_real, sec2r, "TAI")
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (35)", 1)
+                   RETURN
+                END IF
+                !   d) computation of error and correction of the approximate value
+                diff = (mjd2_real-mjd2_int)*86400.0_bp + sec2r - sec2 + &
+                     deltaAT(mjd2_real) - deltaAT(mjd2_int)
+                IF (error) THEN
+                   CALL errorMessage("Time / timescaleConversion", &
+                        "TRACE BACK (40)", 1)
+                   RETURN
+                END IF
+                IF (ABS(diff) > epst) THEN
+                   sect = sect - diff
+                ELSE
+                   EXIT   
+                END IF
+             END DO
+             mjd2_int = mjdt
+             sec2 = sect
+             eqsc = "UTC"
+          ELSE
+             ! Conversion TAI --> TDT
+             sec2 = sec2 + etmtai
+             eqsc = "TDT"
+          END IF
+       ELSE IF (eqsc == "UTC") THEN
+          ! Conversione UTC --> TAI
+          sec2 = sec2 + deltaAT(mjd2_int)
+          IF (error) THEN
+             CALL errorMessage("Time / timescaleConversion", &
+                  "TRACE BACK (45)", 1)
+             RETURN
+          END IF
+          eqsc = "TAI"
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("Time / timescaleConversion", &
+               "Abnormal end.",1)
+          RETURN
+       END IF
+
+    END DO
+
+  END SUBROUTINE timescaleConversion
+
+
+
+
+
+  !! Description:
+  !!
+  !! Reduction of time to normal form.
+  !!
+  !! INPUT:    mjd       -  Modified Julian Day (integer part)
+  !!           sec       -  Seconds within day
+  !!           scale     -  Time scale
+  !!
+  !! OUTPUT:   mjd and sec are normalized, namely sec is reduced within
+  !!           the limits 0 <= sec < lod, and mjd is changed accordingly;
+  !!           lod (length of the day) is usually 86400 s, but can be
+  !!           different from that value in the case of UTC, due to
+  !!           leap seconds.
+  !!
+  !! Returns error.
+  !! 
+  !! Acknowledgements: Based on Mario Carpino's f77 routine.
+  !!
+  SUBROUTINE toNormalForm(mjd, sec, scale)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(inout)       :: mjd
+    REAL(bp), INTENT(inout)      :: sec
+    CHARACTER(len=*), INTENT(in) :: scale
+    INTEGER                      :: nit, idur, isec, k
+    REAL(bp)                     :: fsec
+
+    IF (scale == "UTC") THEN
+       ! Non-trivial case: UTC (the duration of the day can be different
+       ! from 86400 s)
+       nit=0
+       DO
+          nit = nit + 1
+          IF (nit > nitutc) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / toNormalForm", &
+                  "Abnormal end.", 1)
+             RETURN
+          END IF
+          IF (sec < 0.0_bp) THEN
+             ! Duration in seconds of the previous day
+             idur = 86400 + deltaAT(mjd) - deltaAT(mjd-1)
+             IF (error) THEN
+                CALL errorMessage("Time / toNormalForm", &
+                     "TRACE BACK (5)", 1)
+                RETURN
+             END IF
+             sec = sec + idur
+             mjd = mjd - 1
+          ELSE
+             EXIT  
+          END IF
+       END DO
+       ! Decomposition of SEC into integer part (ISEC) + fraction (FSEC),
+       ! where 0 <= FSEC < 1
+       isec = sec
+       fsec = sec - isec
+       ! Duration in seconds of today (MJD)
+       DO
+          idur = 86400 + deltaAT(mjd+1) - deltaAT(mjd)
+          IF (error) THEN
+             CALL errorMessage("Time / toNormalForm", &
+                  "TRACE BACK (10)", 1)
+             RETURN
+          END IF
+          ! Renormalization of time
+          IF (isec >= idur) THEN
+             isec = isec - idur
+             mjd = mjd + 1
+          ELSE
+             EXIT
+          END IF
+       END DO
+       sec = isec + fsec
+
+    ELSE
+
+       ! Trivial case: the duration of the day is always 86400 s
+       ! Also this case requires iterations, due to rounding-off problems.
+       ! EXAMPLE: Let us suppose that the starting values are MJD=48000,
+       ! SEC=-1.d-14. The result of the first iteration is then:
+       !    SEC --> SEC+86400 = 86400 EXACTLY (due to rounding off)
+       !    MJD --> MJD-1 = 47999
+       ! Therefore, a second iteration is required, giving:
+       !    SEC --> SEC-86400 = 0
+       !    MJD --> MJD+1 = 48000
+       nit = 0
+       DO
+          nit = nit + 1
+          IF (nit > nitmax) THEN
+             error = .TRUE.
+             CALL errorMessage("Time / toNormalForm", &
+                  "Abnormal end.", 1)
+             RETURN
+          END IF
+          k = sec/86400.0_bp
+          IF (sec < 0.0_bp) k = k - 1
+          IF (k == 0) RETURN
+          mjd = mjd + k
+          sec = sec - k*86400.0_bp
+       END DO
+    END IF
+
+  END SUBROUTINE toNormalForm
+
+
+
+
+
+END MODULE Time_cl
+
+
+
+
+
Index: trunk/mops/oorb/classes/Unit_class.f90
===================================================================
--- trunk/mops/oorb/classes/Unit_class.f90	(revision 34646)
+++ trunk/mops/oorb/classes/Unit_class.f90	(revision 34646)
@@ -0,0 +1,398 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Class*description*:
+!!
+!! Type and routines for logical unit handling.
+!!
+!! @see File_class
+!! 
+!! @author  MG, JV
+!! @version 2008-08-12
+!!
+MODULE Unit_cl
+
+  USE Base_cl
+  IMPLICIT NONE
+  INTEGER, PARAMETER, PRIVATE :: min_lu = 10 !! Minimum logical unit.
+  INTEGER, PARAMETER, PRIVATE :: max_lu = 99 !! Maximum logical unit.
+  INTEGER, SAVE, PRIVATE :: next_lu = min_lu ! Next supposedly free unit.
+
+  PRIVATE :: new_U
+  PRIVATE :: nullify_U
+  PRIVATE :: copy_U
+  PRIVATE :: exist_U
+  PRIVATE :: safeLogicalUnit
+  PRIVATE :: isOpen
+
+  TYPE Unit
+     PRIVATE
+     INTEGER :: lu                       ! Logical unit.
+     LOGICAL :: is_initialized = .FALSE. ! Has this unit been initialized? 
+     !                                     (true=yes, false=no)
+  END TYPE Unit
+
+  !! Initializes a new instance of Unit.
+  INTERFACE NEW
+     MODULE PROCEDURE new_U
+  END INTERFACE
+
+  !! Nullifies a Unit-object, e.g. closes the unit.
+  INTERFACE NULLIFY
+     MODULE PROCEDURE nullify_U
+  END INTERFACE
+
+  !! Makes a copy of a Unit-object.
+  INTERFACE copy
+     MODULE PROCEDURE copy_U
+  END INTERFACE
+
+  !!
+  INTERFACE exist
+     MODULE PROCEDURE exist_U
+  END INTERFACE
+
+  !! Returns the logical unit number of a Unit instance.
+  INTERFACE getUnit
+     MODULE PROCEDURE getUnit_U
+  END INTERFACE
+
+
+
+
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Initializes a new object and finds a free 
+  !! logical unit. Returns _error_ =
+  !!     - _false_, if a free unit is found.
+  !!     - _true_, if this unit has already been opened, 
+  !!       or a free logical unit ca not be found.
+  !!
+  !! *Usage*:
+  !!
+  !! type (Unit) :: myunit
+  !!
+  !! ...
+  !!
+  !! call new(myunit) 
+  !!
+  SUBROUTINE new_U(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(inout) :: this
+    INTEGER                    :: lu
+
+    IF (this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Unit / new", &
+            "Object has already been initialized.", 1)
+       RETURN
+    END IF
+
+    lu = next_lu
+    CALL safeLogicalUnit(lu)
+    IF (error) THEN
+       CALL errorMessage("Unit / new", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    this%lu             = lu
+    this%is_initialized = .TRUE.
+
+
+  END SUBROUTINE new_U
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Closes logical unit. Returns _error_ =
+  !!     - _false_, if the unit is properly closed, or if the unit 
+  !!                has not been opened at all. 
+  !!     - _true_, if an error occurs during the closing procedure. 
+  !!
+  !! *Usage*:
+  !!
+  !! type (Unit) :: myunit
+  !!
+  !! ...
+  !!
+  !! call nullify(myunit)
+  !!
+  SUBROUTINE nullify_U(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(inout) :: this
+    INTEGER                    :: err
+
+    IF (isOpen(this)) THEN
+       CLOSE(this%lu, iostat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Unit / nullify", &
+               "Could not close unit.", 1)
+          RETURN
+       END IF
+    END IF
+
+    this%is_initialized = .FALSE.
+
+  END SUBROUTINE nullify_U
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns a copy of this object.
+  !!
+  FUNCTION copy_U(this) RESULT(a_copy)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(in)  :: this
+    TYPE (Unit)              :: a_copy
+
+    a_copy%lu             = this%lu
+    a_copy%is_initialized = this%is_initialized
+
+  END FUNCTION copy_U
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the status of the object, i.e. whether
+  !! it exists or not.
+  !!
+  LOGICAL FUNCTION exist_U(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(in)  :: this
+
+    exist_U = this%is_initialized
+
+  END FUNCTION exist_U
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns
+  !!     - logical unit number, if the instance has 
+  !!                            been initialized.
+  !!     - -1, if the unit has not been initialized.
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! type (Unit) :: myunit
+  !!
+  !! integer :: logical_unit
+  !!
+  !! ...
+  !!
+  !! logical_unit = getUnit(myunit) 
+  !!
+  INTEGER FUNCTION getUnit_U(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(in) :: this
+
+    IF (.NOT. this%is_initialized) THEN
+       error = .TRUE.
+       CALL errorMessage("Unit / getUnit", &
+            "Object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    getUnit_U = this%lu
+
+  END FUNCTION getUnit_U
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Examines a Unit instance. Returns
+  !!     - _true_, if the unit is initialized and in use.
+  !!     - _false_, if the unit is not used or not initialized. 
+  !!
+  !! Returns error.
+  !!
+  !! *Usage*:
+  !!
+  !! type (Unit) :: myunit
+  !!
+  !! logical :: open
+  !!
+  !! ...
+  !!
+  !! open = isOpen(myunit)
+  !!
+  LOGICAL FUNCTION isOpen(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(in) :: this
+    LOGICAL                 :: used
+    INTEGER                 :: err
+
+    INQUIRE(this%lu, opened=used, iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("Unit / isOpen", &
+            "Inquiry returned error.", 1)
+       RETURN
+    ELSE
+       IF (this%is_initialized) THEN
+          isOpen = used
+       ELSE
+          isOpen = .FALSE.
+       END IF
+    END IF
+
+  END FUNCTION isOpen
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Examines a logical unit number. If it is unused,
+  !! the value is returned unchanged. If it is in use, 
+  !! the routine finds an unused logical unit number 
+  !! between parameters "min_lu" and "max_lu" (incl.) 
+  !! and returns that value. Returns _error_ =
+  !!     - _false_, if the input unit is ok, or a free 
+  !!                unit was found.
+  !!     - _true_,  if the input unit is not ok, and a 
+  !!                free unit ca not be found.
+  !!
+  !! *Usage*:
+  !!
+  !! integer :: unit_nr = 10
+  !!
+  !! ...
+  !!
+  !! call safeLogicalUnit(unit_nr) 
+  !!
+  SUBROUTINE safeLogicalUnit(lu)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(inout) :: lu
+    INTEGER                :: count, err
+    LOGICAL                :: done, used
+
+    done = .FALSE.
+    count = min_lu
+    DO WHILE (.NOT. done)
+       ! Figure out whether this unit is taken or not:
+       INQUIRE(unit=lu, opened=used, iostat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("Unit / safeLogicalUnit", &
+               "Inquiry failed.", 1)
+          RETURN
+       END IF
+       IF (used) THEN
+          count = count + 1
+          ! If more than max_lu units have been tried,
+          ! every available unit has been tried at least once.
+          ! A free unit could not be found: 
+          IF (count > max_lu) THEN
+             error = .TRUE.
+             CALL errorMessage("Unit / safeLogicalUnit", &
+                  "Could not find a free logical unit.", 1)
+             RETURN
+          END IF
+          ! Try next supposedly free unit:
+          lu = next_lu
+          ! Push next supposedly free unit one unit further:
+          next_lu = next_lu + 1
+          ! Back to beginning if top is reached:
+          IF (next_lu > max_lu) next_lu = min_lu
+       ELSE
+          done = .TRUE.
+       END IF
+    END DO
+
+  END SUBROUTINE safeLogicalUnit
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Sets the logical unit of a Unit instance to 
+  !! the debug logical unit. Returns _error_ =
+  !!     - _false_, if everything is ok.
+  !!     - _true_, if the unit has already been opened.
+  !!
+  !! *Usage*:
+  !!
+  !! type (Unit) :: myunit
+  !!
+  !! ...
+  !!
+  !! call setDebugUnit(myunit)
+  !! 
+  SUBROUTINE setDebugUnit(this)
+
+    IMPLICIT NONE
+    TYPE (Unit), INTENT(inout) :: this
+
+    IF (isOpen(this)) THEN
+       error = .TRUE.
+       CALL errorMessage("Unit / setDebugUnit", &
+            "Unit has already been opened.", 1)
+       RETURN
+    END IF
+
+    this%lu = debug
+
+  END SUBROUTINE setDebugUnit
+
+
+
+
+
+END MODULE Unit_cl
Index: trunk/mops/oorb/configure
===================================================================
--- trunk/mops/oorb/configure	(revision 34646)
+++ trunk/mops/oorb/configure	(revision 34646)
@@ -0,0 +1,145 @@
+#!/bin/bash
+#
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Script for selecting the compiler and setting general options.
+#
+# Author:  MG
+# Version: 2009-11-13
+#
+
+include_file=Makefile.include
+rm -f $include_file
+
+if [[ $1 == absoft ]] ; then
+
+    echo 'FC = $(FC_ABSOFT)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_ABSOFT)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_ABSOFT)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_ABSOFT)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_ABSOFT)' >> $include_file
+
+elif [[ $1 == compaq ]] ; then
+
+    echo 'FC = $(FC_COMPAQ)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_COMPAQ)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_COMPAQ)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_COMPAQ)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_COMPAQ)' >> $include_file
+
+elif [[ $1 == ibm ]] ; then
+
+    if [[ $2 == opt ]] ; then
+	echo 'FC = $(FC_SER_IBM)' > $include_file
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_IBM)' >> $include_file
+    elif [[ $2 == par ]] ; then
+	echo 'FC = $(FC_PAR_IBM)' > $include_file
+	echo 'FCOPTIONS = $(FCOPTIONS_PAR_IBM)' >> $include_file
+    else
+	echo 'FC = $(FC_SER_IBM)' > $include_file
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_IBM)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_IBM)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_IBM)' >> $include_file
+
+elif [[ $1 == intel ]] ; then
+
+    echo 'FC = $(FC_INTEL)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_INTEL)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_INTEL)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_INTEL)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_INTEL)' >> $include_file
+
+elif [[ $1 == lahey ]] ; then
+
+    echo 'FC = $(FC_LAHEY)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_LAHEY)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_LAHEY)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_LAHEY)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_LAHEY)' >> $include_file
+
+elif [[ $1 == sun ]] ; then
+
+    echo 'FC = $(FC_SUN)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_SUN)' >> $include_file
+    elif [[ $2 == par ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_PAR_SUN)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_SUN)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_SUN)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_SUN)' >> $include_file
+
+elif [[ $1 == g95 ]] ; then
+
+    echo 'FC = $(FC_G95)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_G95)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_G95)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_G95)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_G95)' >> $include_file
+
+elif [[ $1 == gfortran ]] ; then
+
+    echo 'FC = $(FC_GFORTRAN)' > $include_file
+    if [[ $2 == opt ]] ; then
+	echo 'FCOPTIONS = $(FCOPTIONS_OPT_GFORTRAN)' >> $include_file
+    else
+	echo 'FCOPTIONS = $(FCOPTIONS_DEB_GFORTRAN)' >> $include_file
+    fi
+    echo 'FC_INC = $(FC_INC_GFORTRAN)' >> $include_file
+    echo 'FC_SHARED = $(FC_SHARED_GFORTRAN)' >> $include_file
+
+else
+
+    echo Erroneous compiler: $1
+    rm -f $include_file
+
+fi
+
+# Options for liboorb and Python wrappers.
+SYSTEM=`uname -s`
+if [[ ${SYSTEM} == "Linux" ]] ; then
+    echo 'LIBEXT = so' >> $include_file
+elif [[ ${SYSTEM} == "Darwin" ]] ; then
+    echo 'LIBEXT = dylib' >> $include_file
+else
+    echo 'LIBEXT = so' >> $include_file
+fi
+
Index: trunk/mops/oorb/data/ET-UT.dat
===================================================================
--- trunk/mops/oorb/data/ET-UT.dat	(revision 34646)
+++ trunk/mops/oorb/data/ET-UT.dat	(revision 34646)
@@ -0,0 +1,206 @@
+Values of DeltaT = ET - UT
+at 0h UT of the date (specified as day, month, year)
+from The Astronomical Almanac 2005
+----------------------------------------------
+1 1 1800   13.7
+1 1 1801   13.4
+1 1 1802   13.1
+1 1 1803   12.9
+1 1 1804   12.7
+1 1 1805   12.6
+1 1 1806   12.5
+1 1 1816   12.5
+1 1 1817   12.4
+1 1 1818   12.3
+1 1 1819   12.2
+1 1 1820   12.0
+1 1 1821   11.7
+1 1 1822   11.4
+1 1 1823   11.1
+1 1 1824   10.6
+1 1 1825   10.2
+1 1 1826    9.6
+1 1 1827    9.1
+1 1 1828    8.6
+1 1 1829    8.0
+1 1 1830    7.5
+1 1 1831    7.0
+1 1 1832    6.6
+1 1 1833    6.3
+1 1 1834    6.0
+1 1 1835    5.8
+1 1 1836    5.7
+1 1 1837    5.6
+1 1 1838    5.6
+1 1 1839    5.6
+1 1 1840    5.7
+1 1 1841    5.8
+1 1 1842    5.9
+1 1 1843    6.1
+1 1 1844    6.2
+1 1 1845    6.3
+1 1 1846    6.5
+1 1 1847    6.6
+1 1 1848    6.8
+1 1 1849    6.9
+1 1 1850    7.1
+1 1 1851    7.2
+1 1 1852    7.3
+1 1 1853    7.4
+1 1 1854    7.5
+1 1 1855    7.6
+1 1 1856    7.7
+1 1 1857    7.7
+1 1 1858    7.8
+1 1 1859    7.8
+1 1 1860    7.88
+1 1 1861    7.82
+1 1 1862    7.54
+1 1 1863    6.97
+1 1 1864    6.40
+1 1 1865    6.02
+1 1 1866    5.41
+1 1 1867    4.10
+1 1 1868    2.92
+1 1 1869    1.82
+1 1 1870    1.61
+1 1 1871    0.10
+1 1 1872   -1.02
+1 1 1873   -1.28
+1 1 1874   -2.69
+1 1 1875   -3.24
+1 1 1876   -3.64
+1 1 1877   -4.54
+1 1 1878   -4.71
+1 1 1879   -5.11
+1 1 1880   -5.40
+1 1 1881   -5.42
+1 1 1882   -5.20
+1 1 1883   -5.46
+1 1 1884   -5.46
+1 1 1885   -5.79
+1 1 1886   -5.63
+1 1 1887   -5.64
+1 1 1888   -5.80
+1 1 1889   -5.66
+1 1 1890   -5.87
+1 1 1891   -6.01
+1 1 1892   -6.19
+1 1 1893   -6.64
+1 1 1894   -6.44
+1 1 1895   -6.47
+1 1 1896   -6.09
+1 1 1897   -5.76
+1 1 1898   -4.66
+1 1 1899   -3.74
+1 1 1900   -2.72
+1 1 1901   -1.54
+1 1 1902   -0.02
+1 1 1903    1.24
+1 1 1904    2.64
+1 1 1905    3.86
+1 1 1906    5.37
+1 1 1907    6.14
+1 1 1908    7.75
+1 1 1909    9.13
+1 1 1910   10.46
+1 1 1911   11.53
+1 1 1912   13.36
+1 1 1913   14.65
+1 1 1914   16.01
+1 1 1915   17.20
+1 1 1916   18.24
+1 1 1917   19.06
+1 1 1918   20.25
+1 1 1919   20.95
+1 1 1920   21.16
+1 1 1921   22.25
+1 1 1922   22.41
+1 1 1923   23.03
+1 1 1924   23.49
+1 1 1925   23.62
+1 1 1926   23.86
+1 1 1927   24.49
+1 1 1928   24.34
+1 1 1929   24.08
+1 1 1930   24.02
+1 1 1931   24.00
+1 1 1932   23.87
+1 1 1933   23.95
+1 1 1934   23.86
+1 1 1935   23.93
+1 1 1936   23.73
+1 1 1937   23.92
+1 1 1938   23.96
+1 1 1939   24.02
+1 1 1940   24.33
+1 1 1941   24.83
+1 1 1942   25.30
+1 1 1943   25.70
+1 1 1944   26.24
+1 1 1945   26.77
+1 1 1946   27.28
+1 1 1947   27.78
+1 1 1948   28.25
+1 1 1949   28.71
+1 1 1950   29.15
+1 1 1951   29.57
+1 1 1952   29.97
+1 1 1953   30.36
+1 1 1954   30.72
+1 1 1955   31.07
+1 1 1956   31.35
+1 1 1957   31.68
+1 1 1958   32.18
+1 1 1959   32.68
+1 1 1960   33.15
+1 1 1961   33.59
+1 1 1962   34.00
+1 1 1963   34.47
+1 1 1964   35.03
+1 1 1965   35.73
+1 1 1966   36.54
+1 1 1967   37.43
+1 1 1968   38.29
+1 1 1969   39.20
+1 1 1970   40.18
+1 1 1971   41.17
+1 1 1972   42.23
+1 1 1973   43.37
+1 1 1974   44.49
+1 1 1975   45.48
+1 1 1976   46.46
+1 1 1977   47.52
+1 1 1978   48.53
+1 1 1979   49.59
+1 1 1980   50.54
+1 1 1981   51.38
+1 1 1982   52.17
+1 1 1983   52.96
+1 1 1984   53.79
+1 1 1985   54.34
+1 1 1986   54.87
+1 1 1987   55.32
+1 1 1988   55.82
+1 1 1989   56.30
+1 1 1990   56.86
+1 1 1991   57.57
+1 1 1992   58.31
+1 1 1993   59.12
+1 1 1994   59.98
+1 1 1995   60.78
+1 1 1996   61.63
+1 1 1997   62.29
+1 1 1998   62.97
+1 1 1999   63.47
+1 1 2000   63.83
+1 1 2001   64.09
+1 1 2002   64.30
+1 1 2003   64.47
+1 1 2004   65.
+1 1 2005   66.  
+1 1 2006   66.  
+1 1 2007   67.  
+1 1 2008   68.  
+1 1 2050  114.
+1 1 3000  250.
Index: trunk/mops/oorb/data/JPL_ephemeris/Makefile
===================================================================
--- trunk/mops/oorb/data/JPL_ephemeris/Makefile	(revision 34646)
+++ trunk/mops/oorb/data/JPL_ephemeris/Makefile	(revision 34646)
@@ -0,0 +1,112 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# This is a makefile for Jet Propulsion Laboratory's planetary ephemeris.
+#
+# Author:  MG
+# Version: 2010-01-21
+
+include ../../make.config
+include ../../Makefile.include
+
+# TYPE OF EPHEMERIS [405|406]
+EPH_TYPE = 405
+# FTP client
+FTP_CLIENT = ncftpget
+# Output name of the program: 
+EPH_BIN = de$(EPH_TYPE).dat
+# Name of ascii-to-binary converter program source file:
+CONV_SRC = asc2eph.f90
+# Name of ascii-to-binary converter program:
+CONVERTER = asc2eph
+# Name of test program source file:
+TESTER_SRC = ephtester.f90
+# Name of test program:
+TESTER = ephtester
+# ASCII versions of de405 ephemeris files:
+EPH_ASCII_DE405 = header.405 ascp1600.405 ascp1620.405 ascp1640.405 ascp1660.405 ascp1680.405 \
+                       ascp1700.405 ascp1720.405 ascp1740.405 ascp1760.405 ascp1780.405 \
+                       ascp1800.405 ascp1820.405 ascp1840.405 ascp1860.405 ascp1880.405 \
+                       ascp1900.405 ascp1920.405 ascp1940.405 ascp1960.405 ascp1980.405 \
+                       ascp2000.405 ascp2020.405 ascp2040.405 ascp2060.405 ascp2080.405 \
+                       ascp2100.405 ascp2120.405 ascp2140.405 ascp2160.405 ascp2180.405 \
+                       ascp2200.405
+# ASCII versions of de406 ephemeris files:
+EPH_ASCII_DE406 = header.406 ascm3000.406 ascm2900.406 ascm2800.406 ascm2700.406 ascm2600.406 \
+                             ascm2500.406 ascm2400.406 ascm2300.406 ascm2200.406 ascm2100.406 \
+                             ascm2000.406 ascm1900.406 ascm1800.406 ascm1700.406 ascm1600.406 \
+                             ascm1500.406 ascm1400.406 ascm1300.406 ascm1200.406 ascm1100.406 \
+                             ascm1000.406 ascm0900.406 ascm0800.406 ascm0700.406 ascm0600.406 \
+                             ascm0500.406 ascm0400.406 ascm0300.406 ascm0200.406 ascm0100.406 \
+                             ascp0000.406 ascp0100.406 ascp0200.406 ascp0300.406 ascp0400.406 \
+                             ascp0500.406 ascp0600.406 ascp0700.406 ascp0800.406 ascp0900.406 \
+                             ascp1000.406 ascp1100.406 ascp1200.406 ascp1300.406 ascp1400.406 \
+                             ascp1500.406 ascp1600.406 ascp1700.406 ascp1800.406 ascp1900.406 \
+                             ascp2000.406 ascp2100.406 ascp2200.406 ascp2300.406 ascp2400.406 \
+                             ascp2500.406 ascp2600.406 ascp2700.406 ascp2800.406 ascp2900.406
+# Input file for ascii-to-binary converter:
+EPH_INPUT  = ascii.$(EPH_TYPE)
+# Project name:
+PROJNAME = JPL_Ephemeris
+
+# Compile converter, build input file and convert ascii ephemeris files to a single binary file:
+eph : $(CONVERTER) $(EPH_INPUT)
+	rm -f $(EPH_BIN)
+	nice ./$(CONVERTER) --eph-type=$(EPH_TYPE) < $(EPH_INPUT)
+	rm -f $(EPH_INPUT)
+	cp $(EPH_BIN) ../
+
+test : $(TESTER)
+	$(TESTER) --eph-type=$(EPH_TYPE)
+
+# Compile ascii-to-binary converter:
+$(CONVERTER): modules $(CONV_SRC)
+	$(FC) -o $(CONVERTER) $(FC_INC)../../modules ../../$(MODULEPATH)/*.o $(CONV_SRC)
+
+# Compile tester:
+$(TESTER): modules $(TEST_SRC)
+	$(FC) -o $(TESTER) $(FC_INC)../../modules ../../$(MODULEPATH)/*.o $(TESTER_SRC)
+
+# Build input file for ascii-to-binary converter:
+$(EPH_INPUT):
+	$(FTP_CLIENT) ftp://ssd.jpl.nasa.gov/pub/eph/planets/ascii/de$(EPH_TYPE)/*
+	if [ $(EPH_TYPE) -eq "406" ] ; then gunzip *$(EPH_TYPE).gz ; fi
+	cat $(EPH_ASCII_DE$(EPH_TYPE)) > $(EPH_INPUT)
+	rm -f $(EPH_ASCII_DE$(EPH_TYPE))
+
+# Write back-up:
+backup:
+	$(SHELL) -c "if test -d ../backup_$(PROJNAME); then true; else mkdir ../backup_$(PROJNAME); fi"
+	cp -a * ../backup_$(PROJNAME)
+
+# Make compressed tar-ball:
+tar: clean
+	rm -f $(PROJNAME)-*.tgz
+	tar cvzf $(PROJNAME)-$(EPH_TYPE).tgz *
+
+modules:
+	cd ../../$(MODULEPATH) ; $(MAKE) all
+
+# Clean up directory:
+clean:
+	rm -f *.o *~ core $(CONVERTER) $(TESTER) *.$(EPH_TYPE)
Index: trunk/mops/oorb/data/JPL_ephemeris/asc2eph.f90
===================================================================
--- trunk/mops/oorb/data/JPL_ephemeris/asc2eph.f90	(revision 34646)
+++ trunk/mops/oorb/data/JPL_ephemeris/asc2eph.f90	(revision 34646)
@@ -0,0 +1,301 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! ASC2EPH creates a direct access JPL Planetary Ephemeris file from
+!! one or more ascii text files.
+!!
+!! This program, 'asc2eph', requires (via standard input) an ascii
+!! header file ('header.XXX'), followed by one or more ascii ephemeris 
+!! data files ('ascSYYYY.XXX').  All files must have the same ephemeris
+!! number, XXX.  Further, the data files must be consecutive in time
+!! with no gaps between them. 
+!!
+!! By default, the output ephemeris will span the same interval as the input
+!! text file(s).  If you are interested in only a portion of data, set the
+!! below T1 and T2 to the begin and end times of the span you desire.  T1
+!! and T2 must be specified in  Julian Ephemeris Days (ET).
+!!
+!! A sample sequence of files might be:
+!!
+!!   header.405  asc+1920.405 asc+1940.405 asc+1960.405 asc+1980.405  
+!!
+!! (The data files for DE200 and DE405 contain 20 years each; for DE406, 100 years)
+!!
+!! @author  MG
+!! @version 2010-01-21
+!!
+PROGRAM asc2eph
+
+  USE cl_options
+  IMPLICIT NONE
+
+  !                               *** NOTE ***
+  !
+  ! The units in which the length of a direct access record is specified 
+  ! are PROCESSOR DEPENDENT. The parameter NRECL, the number of units per word, 
+  ! controls the length of a record in the direct access ephemeris.
+  !
+  !*****  The user must choose one of the following statements  *****
+  !
+  INTEGER, PARAMETER :: NRECL = 4
+  !INTEGER, PARAMETER :: NRECL = 1
+  !
+  !******************************************************************
+  !
+  ! This parameter is the 'kind'-attribute of the real value to be read
+  ! from the ascii files. The value eight (8) corresponds to double
+  ! precision numbers, which are used by JPL.
+  INTEGER, PARAMETER :: dp = 8 
+  !
+  ! This parameter is the 'kind'-attribute of the binary real value, to 
+  ! which the ascii values are converted. The value eight (8) corresponds 
+  ! to bp (base precision), which are used by the JPL_ephemeris routine.
+  INTEGER, PARAMETER :: bp = 8 
+
+  CHARACTER(len=6), DIMENSION(400) :: cnam
+  CHARACTER(len=6), DIMENSION(14,3) :: ttl
+  CHARACTER(len=12) :: header
+  CHARACTER(len=3) :: eph_type
+
+  REAL(kind=bp) :: au, emrat, t1, t2
+  REAL(kind=bp), DIMENSION(400) :: cval
+  REAL(kind=bp), DIMENSION(3) :: ss
+  REAL(kind=bp), DIMENSION(3000) :: db
+  REAL(kind=bp) :: db2z = 0.0_bp
+  REAL(kind=dp), DIMENSION(400) :: cval_dp
+  REAL(kind=dp), DIMENSION(3) :: ss_dp
+  REAL(kind=dp), DIMENSION(3000) :: db_dp
+
+  INTEGER, DIMENSION(3,12) :: ipt
+  INTEGER, DIMENSION(3) :: lpt
+  INTEGER :: i, j, k
+  INTEGER :: in, out, ksize, irecsz
+  INTEGER :: n, ncon, nrout, ncoeff, nrw, numde
+
+  LOGICAL :: first = .TRUE.
+
+
+  !By default, the output ephemeris will span the same interval as the
+  !input ascii data file(s).  The user may reset these to other JED's.
+  t1 = 0.0_bp
+  t2 = 9999999.0_bp
+
+  eph_type = get_cl_option("--eph-type=", "406")
+
+  ! Write a fingerprint to the screen.
+  WRITE(*,*) " JPL ASCII-TO-DIRECT-I/O program. Last modified 21-January-2010."
+  WRITE(*,*) 
+  WRITE(*,*) " ASSUMING TYPE OF INPUT ASCII EPHEMERIS FILE IS DE" // TRIM(eph_type)
+
+  IF (nrecl == 0) THEN
+     STOP "*** ERROR: User did not set NRECL ***"
+  END IF
+
+  ! Read the size and number of main ephemeris records.
+  READ(*,"(6X,I6)") ksize
+  WRITE(*,'("  KSIZE = ",I0)') ksize
+
+  irecsz = nrecl * ksize
+
+  ! Now for the alphameric heading records (GROUP 1010)
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1010") CALL errprt(1010, "not header")
+  READ(*,"(14A6)") ttl
+  WRITE(*,"(/(2X,14A6))") ttl
+
+
+  ! Read start, end and record span  (GROUP 1030)
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1030") CALL errprt(1030, " not header")
+  READ(*,"(3D12.0)") ss_dp
+  ss = REAL(ss_dp,bp)
+
+
+  ! Read number of constants and names of constants (GROUP 1040/4).
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1040 ") CALL errprt(1040, " not header")
+  READ(*,"(I6)") n
+  READ(*,"(10A8)") cnam(1:n)
+  ncon = n
+
+
+  ! Read number of values and values (GROUP 1041/4)
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1041") CALL errprt(1041, " not header")
+  READ(*,"(I6)") n
+  READ(*,"(3D26.18)") cval_dp(1:n)
+  cval = REAL(cval_dp,bp)
+  DO  i = 1, n
+     IF (cnam(i) .EQ. "AU    ")  au    = cval(i)
+     IF (cnam(i) .EQ. "EMRAT ")  emrat = cval(i)
+     IF (cnam(i) .EQ. "DENUM ")  numde = cval(i)
+  END DO
+  WRITE(*,"(500(/2(A8,D24.16)))") (cnam(i),cval(i),i=1,n)
+
+
+  ! Read pointers needed by interp (GROUP 1050)
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1050") CALL errprt(1050, " not header")
+  READ(*,"(13I6)") ((ipt(i,j),j=1,12),lpt(i),i=1,3)
+  WRITE(*,"(/(3I5))") ipt, lpt
+
+
+  ! Open direct-access output file ('deXXX.dat')
+
+  OPEN(unit=12, file="de" // TRIM(eph_type) // ".dat", &
+       access="DIRECT", form="UNFORMATTED", recl=irecsz, status="NEW")
+
+  !Read and write the ephemeris data records (GROUP 1070).
+  CALL nxtgrp(header)
+  IF (header /= "GROUP   1070") CALL errprt(1070," not header")
+  nrout = 0
+  in = 0
+  out = 0
+
+  nrw = 0
+  DO WHILE (nrw == 0)
+     READ(*,"(2I6)") nrw, ncoeff
+  END DO
+
+  !READ(*,"(3D26.18)", iostat=in) db_dp(1:ncoeff)
+  READ(*,*,iostat=in) db_dp(1:ncoeff)
+  db = REAL(db_dp,bp)
+
+  DO WHILE(in == 0 .AND. db(2) < t2)
+
+     IF (2*ncoeff /= ksize) THEN
+        CALL errprt(ncoeff, " 2*ncoeff not equal to ksize")
+     END IF
+
+     ! Skip this data block if the end of the interval is less
+     ! than the specified start time or if the it does not begin
+     ! where the previous block ended.
+     IF ((db(2) >= t1) .AND. (db(1) >= db2z)) THEN
+
+        IF (first) THEN
+           ! Don't worry about the intervals overlapping
+           ! or abutting if this is the first applicable
+           ! interval.
+           db2z  = db(1)
+           first = .FALSE.
+        END IF
+
+        IF (db(1) /= db2z) THEN
+           ! Beginning of current interval is past the end
+           ! of the previous one.
+           CALL errprt (nrw, " Records do not overlap or abut")
+        END IF
+
+        db2z = db(2)
+        nrout = nrout + 1
+
+        WRITE(12, rec=nrout+2, iostat=out) db(1:ncoeff)
+        IF (out /= 0) CALL errprt (nrout, "th record not written because of error")
+
+        ! Save this block's starting date, its interval span, and its end 
+        ! date.
+        IF (nrout == 1) THEN
+           ss(1) = db(1)
+           ss(3) = db(2) - db(1)
+        END IF
+        ss(2) = db(2)
+
+        ! Update the user as to our progress every 10th block.
+        IF (MOD(nrout,10) == 1) THEN
+           IF (db(1) >= t1) THEN
+              WRITE(*,'(I6," ephemeris records written. Last jed = ", F12.2)') nrout, db(2)
+           ELSE
+              WRITE(*,*) " Searching for first requested record..."
+           END IF
+        END IF
+     END IF
+
+     !READ(*,"(2I6,3000(/3D26.18))",iostat=in) nrw, ncoeff, db_dp(1:ncoeff)
+     READ(*,"(2I6)",iostat=in) nrw, ncoeff
+     IF (in == 0) THEN
+        READ(*,*,iostat=in) db_dp(1:ncoeff)
+        db = REAL(db_dp,bp)
+     END IF
+
+  END DO
+
+  WRITE(*,'(/I6," ephemeris records written. Last jed = ", F12.2)') nrout, db(2)
+
+
+  ! Write header records onto output file.
+  nrout = 1
+  WRITE(12, rec=1, iostat=out) ttl, cnam, ss, ncon, au, emrat, ipt, numde, lpt
+  IF (out /= 0) CALL errprt(nrout, "th record not written because of error")
+
+  nrout = 2
+  WRITE(12, rec=2, iostat=out) cval
+  IF (out /= 0) CALL errprt(nrout, "th record not written because of error")
+
+  ! We're through.  Wrap it up.
+  CLOSE (12)
+  STOP "ASCII to binary conversion successful."
+
+
+
+CONTAINS
+
+
+
+  SUBROUTINE errprt(i, msg)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: msg
+    INTEGER, INTENT(in) :: i
+
+    WRITE(*,'("ERROR #",I8,2X,A50)') i, msg
+    STOP " ERROR "
+
+  END SUBROUTINE errprt
+
+
+
+  SUBROUTINE nxtgrp(header)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(out) :: header
+    CHARACTER(len=12) :: blank
+
+    !Start with nothing.
+    header = " "
+
+    !The next non-blank line we encounter is a header record.
+    !The group header and data are seperated by a blank line.
+    DO WHILE (header == " ")
+       READ(*,"(A)") header
+    END DO
+
+    !Found the header. Read the blank line so we can get at the data.
+    IF (header /= "GROUP   1070") THEN
+       READ(*,"(A)") blank
+    END IF
+
+  END SUBROUTINE nxtgrp
+
+
+
+END PROGRAM asc2eph
Index: trunk/mops/oorb/data/JPL_ephemeris/ephtester.f90
===================================================================
--- trunk/mops/oorb/data/JPL_ephemeris/ephtester.f90	(revision 34646)
+++ trunk/mops/oorb/data/JPL_ephemeris/ephtester.f90	(revision 34646)
@@ -0,0 +1,92 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!!*Program*description*:
+!!
+!! This program tests an 'deXXX.dat' JPL planetary ephemeris file and
+!! the routine 'JPL_ephemeris' that extracts interpolated positions.
+!! Positions and velocities of the Sun, the 8 planets, the Moon, and
+!! Pluto are included.
+!!
+!! @author  MG
+!! @version 2010-01-21
+!!
+PROGRAM ephtester
+
+  USE parameters
+  USE planetary_data
+  USE cl_options
+
+  CHARACTER(len=256) :: str
+  CHARACTER(len=3) :: eph_type
+  REAL(rprec8), DIMENSION(:,:), POINTER :: ephemeris
+  REAL(rprec8) :: mjd_tt, jd_tt, correct_value
+  INTEGER :: i, ieph_type, ntarget, ncenter, ncoord, err
+  LOGICAL :: error
+
+  eph_type = get_cl_option("--eph-type=", "405")
+  error = .FALSE.
+  OPEN(12,file="testpo." // TRIM(eph_type),status="old")
+  str = ""
+  DO WHILE (str(1:3) /= "EOT")
+     READ(12,"(A)") str
+  END DO
+  CALL JPL_ephemeris_init(error, "de" // TRIM(eph_type) // ".dat")
+  IF (error) THEN
+     WRITE(0,*) "***** INITIALIZATION ERROR OCCURRED *****"     
+     STOP
+  END IF
+  i = 0
+  DO
+     READ(12,*,iostat=err) ieph_type, str, jd_tt, ntarget, &
+          ncenter, ncoord, correct_value
+     IF (err < 0) THEN
+        EXIT
+     ELSE IF (err > 0) THEN
+        IF (error) THEN
+           WRITE(0,*) "***** READ ERROR OCCURRED *****"     
+           STOP
+        END IF
+     END IF
+     i = i + 1
+     IF (ncenter == 0 .OR. ncenter > 11 .OR. ntarget > 11) THEN
+        CYCLE
+     END IF
+     mjd_tt = jd_tt - 2400000.5_rprec8
+     ephemeris => JPL_ephemeris(mjd_tt, ntarget, ncenter, error)
+     IF (error .AND. ieph_type == 406 .AND. i == 36001) THEN
+        error = .FALSE.
+        WRITE(0,*) "***** PREVIOUS NOT AN ERROR IN SW BUT IN JPL TEST FILE *****"
+        CYCLE
+     END IF
+     IF (ABS(ephemeris(1,ncoord)-correct_value) > 10.0E-13_rprec8) THEN
+        WRITE(0,*) "***** COMPARISON ERROR OCCURRED *****"
+        STOP
+     END IF
+     DEALLOCATE(ephemeris)
+  END DO
+  CLOSE(12)
+  CALL JPL_ephemeris_nullify()
+  WRITE(*,*) "*********** EVERYTHING OK ***************"
+
+END PROGRAM ephtester
Index: trunk/mops/oorb/data/OBSCODE.dat
===================================================================
--- trunk/mops/oorb/data/OBSCODE.dat	(revision 34646)
+++ trunk/mops/oorb/data/OBSCODE.dat	(revision 34646)
@@ -0,0 +1,1486 @@
+000   0.0000 0.62411 +0.77873 Greenwich
+001   0.1542 0.62992 +0.77411 Crowborough
+002   0.62   0.622   +0.781   Rayleigh
+003   3.90   0.725   +0.687   Montpellier
+004   1.4625 0.72520 +0.68627 Toulouse
+005   2.231000.659891+0.748875Meudon
+006   2.124170.751042+0.658129Fabra Observatory, Barcelona
+007   2.336750.659470+0.749223Paris
+008   3.0355 0.80172 +0.59578 Algiers-Bouzareah
+009   7.4417 0.6838  +0.7272  Berne-Uecht
+010   6.9267 0.72368 +0.68811 Caussols
+011   8.797  0.6791  +0.7315  Wetzikon
+012   4.358210.633333+0.771306Uccle
+013   4.483970.614813+0.786029Leiden
+014   5.395090.728859+0.682384Marseilles
+015   5.129290.615770+0.785285Utrecht
+016   5.9893 0.68006 +0.73076 Besancon
+017   6.849240.641946+0.764282Hoher List
+018   6.7612 0.62779 +0.77578 Dusseldorf-Bilk
+019   6.9575 0.68331 +0.72779 Neuchatel
+020   7.3004 0.72391 +0.68767 Nice
+021   8.3855 0.65701 +0.75138 Karlsruhe
+022   7.7748 0.70790 +0.70409 Pino Torinese
+023   8.2625 0.64299 +0.76335 Wiesbaden
+024   8.7216 0.65211 +0.75570 Heidelberg-Konigstuhl
+025   9.196500.660205+0.748637Stuttgart
+026   7.465110.684884+0.726402Berne-Zimmerwald
+027   9.1912 0.70254 +0.70929 Milan
+028   9.9363 0.64686 +0.76009 Wurzburg
+029  10.2406 0.59640 +0.80000 Hamburg-Bergedorf
+030  11.254460.723534+0.688012Arcetri Observatory, Florence
+031  11.189850.639061+0.766705Sonneberg
+032  11.582950.631624+0.772706Jena
+033  11.711240.630900+0.773333Karl Schwarzschild Observatory, Tautenburg
+034  12.452460.745176+0.664656Monte Mario Observatory, Rome
+035  12.575920.565008+0.822321Copenhagen
+036  12.650400.747247+0.662420Castel Gandolfo
+037  13.7333 0.73660 +0.67416 Collurania Observatory, Teramo
+038  13.7704 0.70033 +0.71144 Trieste
+039  13.1874 0.56485 +0.82243 Lund
+040  13.7298 0.63019 +0.77387 Lohrmann Institute, Dresden
+041  11.380830.679862+0.731012Innsbruck
+042  13.064280.611721+0.788439Potsdam
+043  11.5286 0.69770 +0.71422 Asiago Astrophysical Observatory, Padua
+044  14.2559 0.75738 +0.65082 Capodimonte Observatory, Naples
+045  16.3390 0.66739 +0.74227 Vienna (since 1879)
+046  14.2881 0.65922 +0.74965 Klet Observatory, Ceske Budejovice
+047  16.8782 0.61146 +0.78864 Poznan
+048  15.840800.641709+0.764432Hradec Kralove
+049  17.6067 0.5088  +0.8580  Uppsala-Kvistaberg
+050  18.0582 0.51118 +0.85660 Stockholm (before 1931)
+051  18.4766 0.83055 -0.55508 Cape
+052  18.3083 0.51224 +0.85597 Stockholm-Saltsjobaden
+053  18.9642 0.67688 +0.73373 Konkoly Observatory, Budapest (since 1934)
+054  11.6654 0.56595 +0.82169 Brorfelde
+055  19.9596 0.64321 +0.76316 Cracow
+056  20.2450 0.65501 +0.75346 Skalnate Pleso
+057  20.5133 0.71074 +0.70116 Belgrade
+058  20.4957 0.57895 +0.81263 Kaliningrad
+059  20.2201 0.65500 +0.75364 Lomnicky Stit
+060  21.4200 0.61572 +0.78535 Warsaw-Ostrowik
+061  22.30   0.661   +0.746   Uzhgorod
+062  22.2293 0.49440 +0.86632 Turku
+063  22.4450 0.49496 +0.86601 Turku-Tuorla
+064  22.7500 0.49489 +0.86605 Turku-Kevola
+065  12.63   0.673   +0.739   Traunstein
+066  23.718290.789309+0.611962Athens
+067  24.0297 0.64632 +0.76058 Lvov University Observatory
+068  24.0142 0.64627 +0.76062 Lvov Polytechnic Institute
+069  24.4042 0.54925 +0.83287 Baldone
+070  25.2865 0.57940 +0.81233 Vilnius (before 1939)
+071  24.7439 0.74803 +0.66185 NAO Rozhen, Smolyan
+072   7.17   0.629   +0.774   Scheuren Observatory
+073  26.0967 0.71549 +0.69630 Bucharest
+074  26.4058 0.87518 -0.48263 Boyden Observatory, Bloemfontein
+075  26.7216 0.52557 +0.84791 Tartu
+076  27.8768 0.90127 -0.43225 Johannesburg-Hartbeespoort
+077  28.0292 0.89819 -0.43876 Yale-Columbia Station, Johannesburg
+078  28.0750 0.89824 -0.43868 Johannesburg
+079  28.2288 0.90120 -0.43251 Radcliffe Observatory, Pretoria
+080  28.9667 0.75566 +0.65278 Istanbul
+081  27.8768 0.90127 -0.43225 Leiden Station, Johannesburg
+082  15.7561 0.66929 +0.74063 St. Polten
+083  30.5056 0.63918 +0.76651 Golosseevo-Kiev
+084  30.3274 0.50471 +0.86041 Pulkovo
+085  30.5023 0.63800 +0.76749 Kiev
+086  30.7582 0.68987 +0.72152 Odessa
+087  31.3411 0.86799 +0.49495 Helwan
+088  31.8250 0.86741 +0.49608 Kottomia
+089  31.9747 0.68359 +0.72743 Nikolaev
+090   8.25   0.645   +0.762   Mainz
+091   4.209190.703630+0.708287Observatoire de Nurol, Aurec sur Loire
+092  18.5546 0.60177 +0.79601 Torun-Piwnice
+093  20.3647 0.3537  +0.9322  Skibotn
+094  33.9974 0.71565 +0.69620 Crimea-Simeis
+095  34.0160 0.71172 +0.70024 Crimea-Nauchnij
+096   9.4283 0.69967 +0.71215 Merate
+097  34.7625 0.86165 +0.50608 Wise Observatory, Mitzpeh Ramon
+098  11.5688 0.69790 +0.71410 Asiago Observatory, Cima Ekar
+099  25.53   0.483   +0.873   Lahti
+100  24.13   0.462   +0.884   Ahtari
+101  36.2322 0.64403 +0.76246 Kharkov
+102  36.59   0.565   +0.823   Zvenigorod
+103  14.47   0.694   +0.715   Ljubljana
+104  10.8042 0.71985 +0.69202 San Marcello Pistoiese
+105  37.5706 0.56403 +0.82302 Moscow
+106  14.0711 0.69662 +0.71519 Crni Vrh
+107  11.0030 0.70998 +0.70186 Cavezzo
+108  11.0278 0.72367 +0.68784 Montelupo
+109   3.0705 0.80241 +0.59481 Algiers-Kouba
+110  39.15   0.544   +0.835   Rostov
+111  10.9721 0.72439 +0.68710 Piazzano Observatory, Florence
+112  10.9039 0.70232 +0.70950 Pleiade Observatory, Verona
+113  13.0166 0.63502 +0.77001 Volkssternwarte Drebach, Schoenbrunn
+114  41.4277 0.72489 +0.68702 Engelhardt Observatory, Zelenchukskaya Station
+115  41.4416 0.72492 +0.68699 Zelenchukskaya
+116  11.5958 0.66893 +0.74094 Giesing
+117  11.5385 0.66897 +0.74092 Sendling
+118  17.2740 0.66558 +0.74394 Astronomical and Geophysical Observatory, Modra
+119  42.8253 0.74729 +0.66264 Abastuman
+120  13.7261 0.70489 +0.70699 Visnjan
+121  36.9369 0.64883 +0.75842 Kharkov University, Chuguevskaya Station
+122   3.5035 0.72017 +0.69176 Pises Observatory
+123  44.2917 0.76352 +0.64398 Byurakan
+124   2.2550 0.72534 +0.68612 Castres
+125  44.90   0.739   +0.671   Tbilisi
+126   9.7903 0.71893 +0.69283 Monte Viseggi
+127   6.9797 0.63385 +0.77088 Bornheim
+128  46.10   0.626   +0.779   Saratov
+129  45.88   0.776   +0.629   Ordubad
+130  10.240700.700125+0.711807Lumezzane
+131   4.725  0.7123  +0.6996  Observatoire de l'Ardeche
+132   5.2461 0.71919 +0.69260 Bedoin
+133   5.0906 0.72819 +0.68309 Les Tardieux
+134  11.4842 0.63160 +0.77277 Groszschwabhausen
+135  49.1210 0.56353 +0.82334 Kasan
+136  48.8156 0.56282 +0.82383 Engelhardt Observatory, Kasan
+137  34.8147 0.84821 +0.52790 Givatayim Observatory
+138   7.5717 0.67550 +0.73494 Village-Neuf
+139   7.1108 0.72526 +0.68618 Antibes
+140   3.6294 0.69945 +0.71241 Augerolles
+141   7.3672 0.65646 +0.75189 Hottviller
+142   7.1874 0.62156 +0.78075 Sinsen
+143   9.024060.692986+0.718590Gnosca
+144   1.6660 0.65549 +0.75268 Bray et Lu
+145   4.5597 0.62734 +0.77614 's-Gravenwezel
+146  10.6673 0.71715 +0.69487 Frignano
+147   8.573910.700430+0.711392Osservatorio Astronomico di Suno
+148   2.0375 0.72481 +0.68667 Guitalens
+149   4.2236 0.65403 +0.75396 Beine-Nauroy
+150   2.1572 0.65806 +0.75045 Maisons Laffitte
+151   8.7440 0.67719 +0.73346 Eschenberg Observatory, Winterthur
+152  25.5633 0.57036 +0.81868 Moletai Astronomical Observatory
+153   9.1747 0.66080 +0.74814 Stuttgart-Hoffeld
+154  12.1043 0.68923 +0.72250 Cortina
+155  10.1971 0.55864 +0.82664 Ole Romer Observatory, Aarhus
+156  15.0858 0.79431 +0.60549 Catania Astrophysical Observatory
+157  12.8117 0.74166 +0.66864 Frasso Sabino
+158   7.6033 0.69871 +0.71333 Promiod
+159  10.5153 0.72065 +0.69115 Monte Agliale
+160  10.841440.722651+0.688913Castelmartini
+161   8.1605 0.70725 +0.70467 Cerrina Tololo Observatory
+162  15.7805 0.75988 +0.64808 Potenza
+163   6.1492 0.65017 +0.75731 Roeser Observatory, Luxembourg
+164   6.8861 0.66631 +0.74325 St. Michel sur Meurthe
+165   1.7553 0.74984 +0.65946 Piera Observatory, Barcelona
+166  16.0117 0.63730 +0.76812 Upice
+167   8.5727 0.67662 +0.73398 Bulach Observatory
+168  59.50   0.546   +0.835   Kourovskaya
+169   8.4016 0.70737 +0.70453 Airali Observatory
+170   1.9206 0.75217 +0.65711 Observatorio de Begues
+171  14.4697 0.81089 +0.58327 Flarestar Observatory, San Gwann
+172   7.0364 0.68593 +0.72539 Onnens
+173  55.5061 0.93464 -0.35447 St. Clotilde, Reunion
+174  25.5131 0.46536 +0.88219 Nyrola Observatory, Jyvaskyla
+175   7.6083 0.6932  +0.7188  F.-X. Bagnoud Observatory, St-Luc
+176   2.8225 0.77098 +0.63475 Observatorio Astronomico de Consell
+177   3.9414 0.72477 +0.68669 Le Cres
+178   6.1344 0.69423 +0.71745 Collonges
+179   9.0175 0.69694 +0.71507 Monte Generoso
+180   3.9519 0.72571 +0.68570 Mauguio
+181  55.4100 0.93288 -0.35941 Observatoire des Makes, Saint-Louis
+182  55.2586 0.93394 -0.35634 St. Paul, Reunion
+183  41.4200 0.72496 +0.68695 Starlab Observatory, Karachay-Cherkessia
+184   6.0361 0.72081 +0.69097 Valmeca Observatory, Puimichel
+185   7.4219 0.67876 +0.73200 Observatoire Astronomique Jurassien-Vicques
+186  66.8821 0.77679 +0.62781 Kitab
+187  17.0733 0.61314 +0.78735 Astronomical Observatory, Borowiec
+188  66.895550.782059+0.621762Majdanak
+189   6.1514 0.69340 +0.71823 Geneva (before 1967)
+190  68.68   0.783   +0.619   Gissar
+191  68.7811 0.78306 +0.62006 Dushanbe
+192  69.2936 0.75213 +0.65692 Tashkent
+193  69.22   0.786   +0.617   Sanglok
+194  18.0094 0.91807 -0.39579 Tivoli
+195  11.4492 0.66804 +0.74174 Untermenzing Observatory, Munich
+196   7.3331 0.65296 +0.75490 Homburg-Erbach
+197  12.1836 0.71739 +0.69434 Bastia
+198   8.756740.662195+0.746924Wildberg
+199   2.4380 0.66659 +0.74294 Buthiers
+200   4.3036 0.63385 +0.77088 Beersel Hills Observatory
+201   7.6033 0.69871 +0.71332 Jonathan B. Postel Observatory
+202   5.8997 0.73137 +0.67971 Tamaris Observatoire, La Seyne sur Mer
+203   8.9964 0.70160 +0.71022 GiaGa Observatory
+204   8.7708 0.69765 +0.71430 Schiaparelli Observatory
+205  11.2731 0.71478 +0.69703 Obs. Casalecchio di Reno, Bologna
+206  10.5667 0.4922  +0.8677  Haagaar Observatory, Eina
+207   9.3065 0.70156 +0.71025 Osservatorio Antonio Grosso
+208   9.5875 0.70893 +0.70294 Rivalta
+209  11.5688 0.69790 +0.71410 Asiago Observatory, Cima Ekar-ADAS
+210  76.9573 0.73042 +0.68104 Alma-Ata
+211  11.1764 0.72338 +0.68815 Scandicci
+212 355.357470.803253+0.593708Observatorio La Dehesilla
+213   2.385390.749843+0.659421Observatorio Montcabre
+214  11.6569 0.66709 +0.74258 Garching Observatory
+215  10.7328 0.67021 +0.73981 Buchloe
+216   5.6914 0.65732 +0.75114 Observatoire des Cote de Meuse
+217  77.88   0.729   +0.683   Assah
+218  78.4541 0.95444 +0.29768 Hyderabad
+219  78.7283 0.95618 +0.29216 Japal-Rangapur
+220  78.8263 0.97627 +0.21634 Vainu Bappu Observatory, Kavalur
+221  16.3631 0.91960 -0.39228 IAS Observatory, Hakos
+222   2.4939 0.66113 +0.74777 Yerres-Canotiers
+223  80.2464 0.97427 +0.22465 Madras
+224   7.3011 0.67722 +0.73336 Ottmarsheim
+225 288.8250 0.7298  +0.6814  Northwood Ridge Observatory
+226  11.8858 0.70293 +0.70888 Guido Ruggieri Observatory, Padua
+227 281.2853 0.73683 +0.67392 OrbitJet Observatory, Colden
+228  13.8750 0.70038 +0.71147 Bruno Zugna Observatory, Trieste
+229  14.9743 0.75936 +0.64857 G. C. Gloriosi Astronomical Observatory, Salerno
+230  12.0133 0.6744  +0.7363  Mt. Wendelstein Observatory
+231   5.3983 0.64403 +0.76253 Vesqueville
+232   1.3317 0.7500  +0.6593  Masquefa Observatory
+233  10.5403 0.72226 +0.68931 Sauro Donati Astronomical Observatory, San Vito
+234   1.128330.614951+0.785931Coddenham Observatory
+235  13.113520.696669+0.714993CAST Observatory, Talmassons
+236  84.9465 0.55370 +0.82995 Tomsk
+237   2.7333 0.6822  +0.7288  Baugy
+238  10.9094 0.50204 +0.86197 Grorudalen Optical Observatory
+239   8.4114 0.64506 +0.76159 Trebur
+240   8.833170.662308+0.746832Herrenberg Sternwarte
+241  13.4700 0.66465 +0.74474 Schaerding
+242   1.6956 0.72681 +0.68460 Varennes
+243   9.4130 0.59572 +0.80050 Umbrella Observatory, Fredenbeck
+244   0.000000.000000 0.000000Geocentric Occultation Observation
+245                           Spitzer Space Telescope
+246  14.2881 0.65922 +0.74965 Klet Observatory-KLENOT
+247                           Roving Observer
+248   0.000000.000000 0.000000Hipparcos
+249                           SOHO
+250                           Hubble Space Telescope
+251 293.246920.949577+0.312734Arecibo
+252 243.205120.817719+0.573979Goldstone DSS 13, Fort Irwin
+253 243.110470.815913+0.576510Goldstone DSS 14, Fort Irwin
+254 288.511280.736973+0.673692Haystack, Westford
+255  33.164120.707954+0.703886Evpatoria
+256 280.160170.784451+0.618320Green Bank
+257 243.124610.816796+0.575252Goldstone DSS 25, Fort Irwin
+260 149.0661 0.85560 -0.51626 Siding Spring Observatory-DSS
+261 243.140220.836325+0.546877Palomar Mountain-DSS
+262 289.266260.873440-0.486052European Southern Observatory, La Silla-DSS
+285   2.3708 0.66135 +0.74759 Flammarion Observatory, Juvisy
+286 102.7883 0.90694 +0.42057 Yunnan Observatory
+290 250.107990.842743+0.537438Mt. Graham-VATT
+291 248.4009 0.84947 +0.52647 LPL/Spacewatch II
+292 285.1058 0.76630 +0.64033 Burlington, New Jersey
+293 285.5899 0.76936 +0.63668 Burlington remote site
+294 285.8467 0.76031 +0.64739 Astrophysical Obs., College of Staten Island
+295 283.0000 0.7789  +0.6251  Catholic University Observatory, Washington
+296 286.2515 0.7365  +0.6742  Dudley Observatory, Albany (after 1893)
+297 286.819  0.7203  +0.6913  Middlebury
+298 287.3408 0.74943 +0.65988 Van Vleck Observatory
+299 107.6160 0.99316 -0.11808 Bosscha Observatory, Lembang
+300 133.544440.823370+0.565720Bisei Spaceguard Center-BATTeRS
+301 288.8467 0.70279 +0.70926 Mont Megantic
+302 288.88   0.990   +0.150   University of the Andes station
+303 289.1329 0.98889 +0.15190 Merida
+304 289.2980 0.87559 -0.48217 Las Campanas Observatory
+305 109.5514 0.82066 +0.56963 Purple Mountain, Hainan Island station
+306 290.6769 0.98477 +0.17381 Observatorio Taya Beixo, Barquisimeto
+309 289.595690.909943-0.414336Cerro Paranal
+312 112.334  0.9574  +0.2877  Tsingtao field station, Xisha Islands
+318 115.691  0.85206 -0.52170 Quinns Rock
+319 116.1350 0.84883 -0.52702 Perth Observatory, Perth-Lowell Telescope
+320 116.4381 0.85859 -0.51102 Chiro Observatory
+321 115.7571 0.85078 -0.52378 Craigie
+322 116.1340 0.84882 -0.52703 Perth Observatory, Bickley-MCT
+323 116.1350 0.84882 -0.52703 Perth Observatory, Bickley
+324 116.3277 0.76598 +0.64072 Peking Observatory, Shaho Station
+327 117.5750 0.76278 +0.64470 Peking Observatory, Xinglong Station
+330 118.8209 0.84828 +0.52788 Purple Mountain Observatory, Nanking
+333 249.5236 0.84936 +0.52642 Desert Eagle Observatory
+334 120.3196 0.80925 +0.58552 Tsingtao
+337 121.1843 0.85708 +0.51348 Sheshan, formerly Zo-Se
+340 135.4853 0.82199 +0.56762 Toyonaka
+341 137.9486 0.80669 +0.58923 Akashina
+342 134.3189 0.83425 +0.54955 Shishikui
+343 127.1258 0.78688 +0.61507 Younchun
+344 128.9767 0.80841 +0.58695 Bohyunsan Optical Astronomy Observatory
+345 128.4575 0.80046 +0.59773 Sobaeksan Optical Astronomy Observatory
+346 127.3854 0.80474 +0.59166 KNUE Astronomical Observatory
+347 139.9086 0.80417 +0.59244 Utsunomiya-Imaizumi
+348 135.2669 0.81698 +0.57475 Ayabe
+349 139.566220.810402+0.583916Ageo
+350 139.2635 0.80504 +0.59132 Kurohone
+351 135.8678 0.81939 +0.57135 Sakamoto
+352 136.1778 0.82061 +0.56963 Konan
+353 135.0648 0.82265 +0.56669 Nishi Kobe
+354 140.0206 0.80109 +0.59674 Kawachi
+355 139.2133 0.81618 +0.57590 Hadano
+356 141.0867 0.78319 +0.61970 Kogota
+357 140.0064 0.80807 +0.58712 Shimotsuma
+358 140.1586 0.78856 +0.61296 Nanyo
+359 135.1719 0.82782 +0.55912 Wakayama
+360 132.9442 0.83314 +0.55138 Kuma Kogen
+361 134.8933 0.82649 +0.56106 Sumoto
+362 140.6550 0.73673 +0.67398 Ray Observatory
+363 130.7703 0.83416 +0.54967 Yamada
+364 130.5747 0.85213 +0.52164 YCPM Kagoshima Station
+365 135.9579 0.82597 +0.56196 Uto Observatory
+366 138.3003 0.81147 +0.58267 Miyasaka Observatory
+367 133.1670 0.81504 +0.57747 Yatsuka
+368 138.8117 0.81213 +0.58191 Ochiai
+369 139.1500 0.8101  +0.5844  Chichibu
+370 133.5273 0.83424 +0.54956 Kochi
+371 133.5965 0.82433 +0.56431 Tokyo-Okayama
+372 133.8276 0.83450 +0.54920 Geisei
+373 135.3397 0.82866 +0.55797 Oishi
+374 134.7196 0.81915 +0.57174 Minami-Oda Observatory
+375 134.8708 0.8206  +0.5697  Uzurano
+376 139.0392 0.81321 +0.58022 Uenohara
+377 135.7933 0.82014 +0.57031 Kwasan Observatory, Kyoto
+378 136.0142 0.82437 +0.56426 Murou
+379 137.6279 0.82300 +0.56613 Hamamatsu-Yuto
+380 137.0349 0.82190 +0.56772 Ishiki
+381 137.6283 0.81220 +0.58173 Tokyo-Kiso
+382 137.5553 0.80915 +0.58639 Tokyo-Norikura
+383 137.8959 0.80218 +0.59526 Chirorin
+384 138.1792 0.8219  +0.5678  Shimada
+385 138.4680 0.82039 +0.56997 Nihondaira Observatory
+386 138.3217 0.81121 +0.58309 Yatsugatake-Kobuchizawa
+387 139.1944 0.81000 +0.58469 Tokyo-Dodaira
+388 139.5421 0.81330 +0.57991 Tokyo-Mitaka
+389 139.7447 0.81347 +0.57965 Tokyo (before 1938)
+390 139.8725 0.80425 +0.59234 Utsunomiya
+391 140.778430.786177+0.615960Sendai Observatory, Ayashi Station
+392 141.3667 0.73355 +0.67741 JCPM Sapporo Station
+393 140.1292 0.8090  +0.5858  JCPM Sakura Station
+394 142.3208 0.70692 +0.70493 JCPM Hamatonbetsu Station
+395 142.3583 0.7224  +0.6891  Tokyo-Asahikawa
+396 142.4208 0.7236  +0.6879  Asahikawa
+397 141.4761 0.73210 +0.67892 Sapporo Science Center
+398 139.1080 0.80870 +0.58630 Nagatoro
+399 144.5900 0.73158 +0.67950 Kushiro
+400 143.7827 0.72344 +0.68811 Kitami
+401 139.4208 0.8088  +0.5861  Oosato
+402 136.3078 0.81800 +0.57335 Dynic Astronomical Observatory
+403 137.0556 0.81593 +0.57625 Kani
+404 140.9292 0.7909  +0.6099  Yamamoto
+405 139.3292 0.8069  +0.5887  Kamihoriguchi
+406 141.8233 0.72946 +0.68174 Bibai
+407 140.3099 0.78426 +0.61837 Kahoku
+408 138.1747 0.81121 +0.58328 Nyukasa
+409 139.5211 0.81234 +0.58124 Kiyose and Mizuho
+410 134.8910 0.81883 +0.57222 Sengamine
+411 139.4170 0.80739 +0.58805 Oizumi
+412 140.5991 0.80011 +0.59803 Iwaki
+413 149.066080.855595-0.516262Siding Spring Observatory
+414 149.0077 0.81694 -0.57499 Mount Stromlo
+415 149.0636 0.81615 -0.57606 Kambah
+416 149.13   0.816   -0.575   Barton
+417 137.1371 0.79611 +0.60317 Yanagida Astronomical Observatory
+418 150.940340.857259-0.513294Tamworth
+419 150.8329 0.83370 -0.55038 Windsor
+420 151.2050 0.83126 -0.55404 Sydney
+421 133.7650 0.83244 +0.55262 Mt. Kajigamori, Otoyo
+422 151.0461 0.85503 -0.51709 Loomberah
+423 151.124730.831807-0.553222North Ryde
+424 149.0658 0.81758 -0.57405 Macquarie
+425 152.9316 0.88796 -0.45843 Taylor Range Observatory, Brisbane
+426 136.8217 0.85618 -0.51498 Woomera
+427 138.7283 0.82667 -0.56084 Stockport
+428 153.3970 0.88271 -0.46837 Reedy Creek
+429 149.0400 0.81761 -0.57402 Hawker
+430 149.2123 0.85550 -0.51623 Rainbow Observatory, near Coonabarabran
+431 149.7578 0.83548 -0.54793 Mt. Tarana Observatory, Bathurst
+432 153.082220.863790-0.502166Boambee
+433 152.1078 0.84197 -0.53771 Bagnall Beach Observatory
+434  10.9206 0.70765 +0.70419 S. Benedetto Po
+435  11.8936 0.70330 +0.70852 G. Colombo Astronomical Observatory, Padua
+436  11.3356 0.71658 +0.69528 Osservatorio di Livergnano
+437 284.6971 0.76700 +0.63953 Haverford
+438 287.3621 0.74059 +0.66978 Smith College Observatory, Northampton
+439 253.2539 0.81156 +0.58288 ROTSE-III, Los Alamos
+440 278.6842 0.73025 +0.68097 Elginfield Observatory
+441 357.1697 0.55559 +0.82867 Swilken Brae, St. Andrews
+442 357.4822 0.7477  +0.6619  Gualba Observatory
+443 301.4656 0.82370 -0.56513 Obs. Astronomico Plomer, Buenos Aires
+444 243.2794 0.83507 +0.54868 Star Cruiser Observatory
+445 359.4200 0.7802  +0.6235  Observatorio d'Ontinyent
+446 262.1666 0.87049 +0.49058 Kingsnake Observatory, Seguin
+447 255.2056 0.77154 +0.63448 Centennial Observatory
+448 253.2801 0.84543 +0.53268 Desert Moon Observatory, Las Cruces
+449 279.6503 0.82617 +0.56156 Griffin Hunter Observatory, Bethune
+450 279.3339 0.81857 +0.57254 Carla Jane Observatory, Charlotte
+451 262.7569 0.79447 +0.60536 West Skies Observatory, Mulvane
+452 279.1063 0.8980  +0.4385  Big Cypress Observatory, Fort Lauderdale
+453 242.1331 0.82030 +0.57021 Edwards Raven Observatory
+454 283.376780.774542+0.630425Maryland Space Grant Consortium Observatory
+455 237.9636 0.78912 +0.61218 CBA Concord
+456 358.8278 0.61348 +0.78709 Daventry Observatory
+457  18.3403 0.66221 +0.74685 Partizanske
+458 355.9806 0.75992 +0.64805 Guadarrama Observatory
+459 288.1172 0.72607 +0.68538 Smith River Observatory, Danbury
+460 265.9981 0.83010 +0.55579 Area 52 Observatory, Nashville
+461  19.8943 0.67153 +0.73869 University of Szeged, Piszkesteto Stn. (Konkoly)
+462 283.0842 0.77905 +0.62488 Mount Belleview Observatory
+463 254.7375 0.76726 +0.63959 Sommers-Bausch Observatory, Boulder
+464 288.5013 0.75109 +0.65799 Toby Point Observatory, Narragansett
+465 174.7801 0.80166 -0.59578 Takapuna
+466 174.8487 0.8002  -0.5977  Mount Molehill Observatory, Auckland
+467 174.7766 0.80058 -0.59724 Auckland Observatory
+468  13.3296 0.74652 +0.66349 Astronomical Observatory, Campo Catino
+469   7.3820 0.67873 +0.73205 Courroux
+470  13.3286 0.74929 +0.66006 Ceccano
+471   8.2389 0.56364 +0.82325 Houstrup
+472   6.3203 0.71225 +0.69998 Merlette
+473  13.316610.694793+0.716822Remanzacco
+474 170.464960.720773-0.691079Mount John Observatory, Lake Tekapo
+475   7.6965 0.70747 +0.70443 Turin (before 1913)
+476   7.1414 0.70659 +0.70535 Grange Observatory, Bussoleno
+477   0.4856 0.62103 +0.78117 Galleywood
+478   3.0896 0.72548 +0.68597 Lamalou-les-Bains
+479   6.0505 0.73020 +0.68096 Sollies-Pont
+480   0.7733 0.61466 +0.78616 Cockfield
+481   7.93   0.596   +0.800   Moorwarfen
+482 357.1854 0.55560 +0.82866 St. Andrews
+483 173.8036 0.74734 -0.66254 Carter Observatory, Black Birch Station
+484 174.75   0.753   -0.657   Happy Valley, Wellington
+485 174.7654 0.75256 -0.65635 Carter Observatory, Wellington
+486 175.47   0.765   -0.643   Palmerston North
+487 355.4444 0.56858 +0.81989 Macnairston Observatory
+488 358.3664 0.57486 +0.81553 Newcastle-upon-Tyne
+489 359.87   0.612   +0.788   Hemingford Abbots
+490 358.00   0.633   +0.772   Wimborne Minster
+491 356.9000 0.76131 +0.64644 Centro Astronomico de Yebes
+492 358.47   0.605   +0.795   Mickleover
+493 357.4542 0.79753 +0.60182 Calar Alto
+494 357.8361 0.61126 +0.78879 Stakenbridge
+495 357.66   0.598   +0.800   Altrincham
+496 358.6860 0.6311  +0.7731  Bishopstoke
+497 359.30   0.626   +0.776   Ascot-Loudwater
+498 359.2581 0.61334 +0.78718 Earls Barton
+499 359.7924 0.62558 +0.77755 Cheam
+500   0.000000.000000 0.000000Geocentric
+501   0.3475 0.63237 +0.77208 Herstmonceux
+502   0.85   0.617   +0.783   Colchester
+503   0.0948 0.61400 +0.78667 Cambridge
+504   4.3944 0.68553 +0.72570 Le Creusot
+505   4.5639 0.6229  +0.7797  Simon Stevin
+506   9.96   0.598   +0.797   Bendestorf
+507   5.22   0.617   +0.783   Nyenheim
+508   5.29   0.617   +0.783   Zeist
+509   5.87   0.732   +0.680   La Seyne sur Mer
+510   8.0256 0.63185 +0.77257 Siegen
+511   5.7157 0.72140 +0.69034 Haute Provence
+512   4.4893 0.61477 +0.78606 Leiden (before 1860)
+513   4.7855 0.69971 +0.71209 Lyons
+514   8.438  0.6513  +0.7563  Mundenheim (1907-1913)
+515   7.4956 0.64656 +0.76038 Volkssternwarte Dhaun, near Kirn
+516   9.973210.595399+0.800741Hamburg (before 1909)
+517   6.1358 0.69201 +0.71957 Geneva (from 1967)
+518   9.9727 0.59545 +0.80071 Marine Observatory, Hamburg
+519   8.29   0.626   +0.776   Meschede
+520   7.0966 0.63427 +0.77053 Bonn
+521  10.8899 0.64562 +0.76116 Bamberg
+522   7.7677 0.66279 +0.74633 Strasbourg
+523   8.6512 0.64251 +0.76374 Frankfurt
+524   8.4605 0.6509  +0.7566  Mannheim
+525   8.7708 0.6331  +0.7715  Marburg
+526  10.1477 0.58426 +0.80886 Kiel
+527   9.9431 0.5955  +0.8007  Altona
+528   9.9426 0.62340 +0.77931 Gottingen
+529  10.7229 0.50259 +0.86163 Christiania
+530  10.6898 0.5911  +0.8039  Lubeck
+531  12.4797 0.74545 +0.66434 Collegio Romano, Rome
+532  11.6084 0.66853 +0.74130 Munich
+533  11.8715 0.70335 +0.70847 Padua
+534  12.3913 0.62606 +0.77719 Leipzig (since 1861)
+535  13.3578 0.78782 +0.61386 Palermo
+536  13.1062 0.61135 +0.78873 Berlin-Babelsberg
+537  13.3642 0.6097  +0.7900  Urania Observatory, Berlin
+538  13.8461 0.70998 +0.70187 Pola
+539  14.1316 0.66968 +0.74024 Kremsmunster
+540  14.2753 0.66470 +0.74477 Linz
+541  14.3953 0.64306 +0.76331 Prague
+542  13.0374 0.6091  +0.7904  Falkensee
+543  12.3688 0.6260  +0.7772  Leipzig (before 1861)
+544  13.351310.610644+0.789263Wilhelm Foerster Observatory, Berlin
+545  16.3817 0.66767 +0.74200 Vienna (before 1879)
+546  16.3549 0.66760 +0.74207 Oppolzer Observatory, Vienna
+547  17.0363 0.62904 +0.77479 Breslau
+548  13.3950 0.60999 +0.78976 Berlin (1835-1913)
+549  17.6257 0.50341 +0.86116 Uppsala
+550  11.4196 0.5943  +0.8015  Schwerin
+551  18.1895 0.67201 +0.73808 Hurbanovo, formerly O'Gyalla
+552  11.3418 0.71485 +0.69700 Osservatorio S. Vittore, Bologna
+553  18.9938 0.64002 +0.76574 Chorzow
+554   8.40   0.638   +0.769   Burgsolms Observatory, Wetzlar
+555  19.8263 0.64336 +0.76306 Cracow-Fort Skala
+556  11.26   0.675   +0.734   Reintal, near Munich
+557  14.7837 0.64530 +0.76148 Ondrejov
+558  21.0303 0.61396 +0.78672 Warsaw
+559  14.98   0.793   +0.607   Serra La Nave
+560  10.931000.703262+0.708561Madonna di Dossobuono
+561  19.8943 0.67153 +0.73869 Piszkesteto Stn. (Konkoly)
+562  15.9236 0.66938 +0.74062 Figl Observatory, Vienna
+563  13.60   0.671   +0.739   Seewalchen
+564  11.19   0.671   +0.741   Herrsching
+565  10.1344 0.70437 +0.70746 Bassano Bresciano
+566 203.7424 0.93623 +0.35156 Haleakala-NEAT/GEODSS
+567  12.7117 0.69783 +0.71387 Chions
+568 204.5278 0.94171 +0.33725 Mauna Kea
+569  24.9587 0.49891 +0.86375 Helsinki
+570  25.2990 0.5794  +0.8123  Vilnius (since 1939)
+571  10.63   0.704   +0.708   Cavriana
+572   6.89   0.631   +0.772   Cologne
+573   9.6612 0.6145  +0.7862  Eldagsen
+574  10.27   0.704   +0.708   Gottolengo
+575   6.808  0.68219 +0.72894 La Chaux de Fonds
+576   0.38   0.631   +0.774   Burwash
+577   7.50   0.678   +0.734   Metzerlen Observatory
+578  27.99   0.898   -0.439   Linden Observatory
+579   8.85   0.711   +0.701   Novi Ligure
+580  15.4936 0.68242 +0.72862 Graz
+581  22.80   0.830   -0.556   Sedgefield
+582   1.2408 0.61682 +0.78447 Orwell Park
+583  30.27   0.692   +0.720   Odessa-Mayaki
+584  30.2946 0.50213 +0.86189 Leningrad
+585  30.4978 0.63920 +0.76650 Kiev comet station
+586   0.1423 0.73358 +0.67799 Pic du Midi
+587   9.230250.697442+0.714485Sormano
+588  11.25   0.715   +0.697   Eremo di Tizzano
+589  12.64   0.739   +0.673   Santa Lucia Stroncone
+590   7.46   0.678   +0.734   Metzerlen
+591   9.6258 0.60995 +0.78979 Resse Observatory
+592   7.021140.628245+0.775437Solingen
+593  11.17   0.739   +0.671   Monte Argentario
+594  13.2033 0.74497 +0.66529 Monte Autore
+595  13.525780.696925+0.714749Farra d'Isonzo
+596  12.6183 0.74446 +0.66545 Colleverde di Guidonia
+597   9.6631 0.61461 +0.78621 Springe
+598  11.334090.717444+0.694448Loiano
+599  13.5625 0.7396  +0.6713  Campo Imperatore-CINEOS
+600  11.4708 0.71618 +0.69564 TLC Observatory, Bologna
+601  13.7281 0.63009 +0.77394 Engelhardt Observatory, Dresden
+602  16.3854 0.66764 +0.74203 Urania Observatory, Vienna
+603  10.1300 0.58622 +0.80745 Bothkamp
+604  13.475240.610235+0.789572Archenhold Sternwarte, Berlin-Treptow
+605   7.1130 0.62142 +0.78086 Marl
+606   9.9956 0.59353 +0.80212 Norderstedt
+607   8.0000 0.6277  +0.7760  Hagen Observatory, Ronkhausen
+608 203.7420 0.93623 +0.35156 Haleakala-AMOS
+609  12.8533 0.73772 +0.67314 Osservatorio Polino
+610  11.3431 0.71577 +0.69604 Pianoro
+611   8.6531 0.64877 +0.75848 Starkenburg Sternwarte, Heppenheim
+612   7.10   0.625   +0.778   Lenkerbeck
+613   7.0709 0.62504 +0.77800 Heisingen
+614   2.467  0.6621  +0.7469  Soisy-sur-Seine
+615   6.9067 0.71233 +0.70014 St. Veran
+616  16.5883 0.65465 +0.75346 Brno
+617   2.5725 0.66496 +0.74437 Arbonne la Foret
+618   5.0077 0.72750 +0.68382 Martigues
+619   2.090130.749506+0.659828Sabadell
+620   2.9517 0.77110 +0.63463 Observatorio Astronomico de Mallorca
+621   7.4858 0.62944 +0.77451 Bergisch Gladbach
+622   7.5680 0.68778 +0.72358 Oberwichtrach
+623   5.5667 0.63577 +0.76932 Liege
+624   9.6167 0.64723 +0.75977 Dertingen
+625 203.5683 0.93557 +0.35201 Kihei-AMOS Remote Maui Experimental Site
+626   4.9864 0.62847 +0.77524 Geel
+627   5.2146 0.72002 +0.69168 Blauvac
+628   6.8442 0.62477 +0.77820 Mulheim-Ruhr
+629  20.1511 0.69273 +0.71880 Szeged Observatory
+630   7.2367 0.67051 +0.73951 Osenbach
+631  10.02   0.596   +0.800   Hamburg-Georgswerder
+632  11.1739 0.72380 +0.68773 San Polo A Mosciano
+633   9.9339 0.71930 +0.69238 Romito
+634   5.1456 0.70182 +0.71007 Crolles
+635   2.9019 0.73605 +0.67467 Pergignan
+636   6.9794 0.62524 +0.77783 Essen
+637  10.0903 0.59326 +0.80232 Hamburg-Himmelsmoor
+638   8.8933 0.61778 +0.78374 Detmold
+639  13.7233 0.62933 +0.77456 Dresden
+640  13.5996 0.6429  +0.7634  Senftenberger Sternwarte
+641  20.0272 0.82468 -0.56374 Overberg
+642 236.6850 0.6648  +0.7445  Oak Bay, Victoria
+643 243.2794 0.83507 +0.54868 OCA-Anza Observatory
+644 243.140220.836325+0.546877Palomar Mountain/NEAT
+645 254.179420.841945+0.538563Apache Point-Sloan Digital Sky Survey
+646 242.4369 0.82999 +0.55603 Santana Observatory, Rancho Cucamonga
+647 245.9683 0.6337  +0.7712  Stone Finder Observatory, Calgary
+648 249.398220.852115+0.522053Winer Observatory, Sonoita
+649 265.3003 0.78207 +0.62117 Powell Observatory, Louisburg
+650 242.9028 0.83510 +0.54836 Temecula
+651 249.419160.852069+0.522123Grasslands Observatory, Tucson
+652 245.9333 0.6291  +0.7749  Rock Finder Observatory, Calgary
+653 237.8678 0.68091 +0.72996 Torus Observatory, Buckley
+654 242.318410.826471+0.561727Table Mountain Observatory, Wrightwood-PHMC
+655 236.383  0.6656  +0.7438  Sooke
+656 236.3921 0.66580 +0.74367 Victoria
+657 236.6903 0.66437 +0.74491 Climenhaga Observatory, Victoria
+658 236.583000.663631+0.745601National Research Council of Canada
+659 237.0514 0.66257 +0.74650 Heron Cove Observatory, Orcas
+660 237.7379 0.79038 +0.61059 Leuschner Observatory, Berkeley
+661 245.7117 0.63251 +0.77222 Rothney Astrophysical Observatory, Priddis
+662 238.3545 0.79619 +0.60335 Lick Observatory, Mount Hamilton
+663 248.3136 0.83483 +0.54879 Red Mountain Observatory
+664 239.2775 0.6840  +0.7273  Manastash Ridge Observatory
+665 240.9903 0.82215 +0.56781 Wallis Observatory
+666 241.1692 0.8270  +0.5604  Moorpark College Observatory
+667 240.009210.684483+0.726626Wanapum Dam
+668 240.82   0.821   +0.568   San Emigdio Peak
+669 240.82   0.826   +0.563   Ojai
+670 240.9558 0.82775 +0.55922 Camarillo
+671 242.0022 0.82719 +0.56052 Stony Ridge
+672 241.9436 0.82794 +0.55942 Mount Wilson
+673 242.317830.826474+0.561722Table Mountain Observatory, Wrightwood
+674 242.336050.826464+0.561730Ford Observatory, Wrightwood
+675 243.137460.836357+0.546831Palomar Mountain
+676 242.3907 0.83553 +0.54762 San Clemente
+677 242.8281 0.82746 +0.56012 Lake Arrowhead
+678 248.2597 0.83352 +0.55083 Fountain Hills
+679 244.5367 0.85792 +0.51292 San Pedro Martir
+680 244.78   0.833   +0.554   Los Angeles
+681 245.8858 0.62954 +0.77459 Calgary
+682 247.6381 0.79932 +0.59932 Kanab
+683 248.9182 0.84751 +0.52922 Goodricke-Pigott Observatory, Tucson
+684 247.5100 0.82512 +0.56356 Prescott
+685 247.84   0.816   +0.575   Williams
+686 249.2092 0.84512 +0.53359 U. of Minn. Infrared Obs., Mt. Lemmon
+687 248.3473 0.81848 +0.57318 Northern Arizona University, Flagstaff
+688 248.4645 0.81938 +0.57193 Lowell Observatory, Anderson Mesa Station
+689 248.2601 0.81851 +0.57319 U.S. Naval Observatory, Flagstaff
+690 248.3367 0.81832 +0.57344 Lowell Observatory, Flagstaff
+691 248.4010 0.84951 +0.52642 Steward Observatory, Kitt Peak-Spacewatch
+692 249.0513 0.84679 +0.53036 Steward Observatory, Tucson
+693 249.267450.845317+0.533211Catalina Station, Tucson
+694 248.9943 0.84700 +0.53009 Tumamoc Hill, Tucson
+695 248.405330.849504+0.526425Kitt Peak
+696 249.1154 0.85205 +0.52249 Whipple Observatory, Mt. Hopkins
+697 248.3842 0.84956 +0.52629 Kitt Peak, McGraw-Hill
+698 249.28   0.844   +0.532   Mt. Bigelow
+699 248.463310.819380+0.571930Lowell Observatory-LONEOS
+700 250.3817 0.80656 +0.58960 Chinle
+701 249.797160.853823+0.519224Junk Bond Observatory, Sierra Vista
+702 252.8117 0.8305  +0.5561  Joint Obs. for cometary research, Socorro
+703 249.267360.845315+0.533213Catalina Sky Survey
+704 253.340930.831869+0.553542Lincoln Laboratory ETS, New Mexico
+705 254.179420.841945+0.538563Apache Point
+706 253.9366 0.78294 +0.62043 Salida
+707 254.56   0.774   +0.633   Chamberlin field station
+708 255.0475 0.77092 +0.63520 Chamberlin Observatory, Denver
+709 254.228820.840250+0.541096W & B Observatory, Cloudcroft
+710 254.7336 0.77980 +0.62458 MPO Observatory, Florissant
+711 255.9785 0.86114 +0.50731 McDonald Observatory, Fort Davis
+712 255.118650.778364+0.626251USAF Academy Observatory, Colorado Springs
+713 254.9897 0.76865 +0.63793 Thornton
+714 246.8173 0.82444 +0.56439 Bagdad
+715 253.2759 0.84546 +0.53264 Jornada Observatory, Las Cruces
+716 255.2489 0.77753 +0.62731 Palmer Divide Observatory, Colorado Springs
+717 256.0481 0.86160 +0.50636 Prude Ranch
+718 247.7125 0.76004 +0.64802 Wiggins Observatory, Tooele
+719 253.086080.829384+0.557204Etscorn Observatory
+720 259.6261 0.90216 +0.43018 Universidad de Monterrey
+721 259.7312 0.76271 +0.64476 Lime Creek
+722 264.4192 0.87017 +0.49110 Missouri City
+723 263.3300 0.82134 +0.56861 Cottonwood Observatory, Ada
+724 260.8053 0.94388 +0.33026 National Observatory, Tacubaya
+725 261.3453 0.86883 +0.49358 Fair Oaks Ranch
+726 265.6933 0.69024 +0.72120 Brainerd
+727 262.538720.813941+0.579096Zeno Observatory, Edmond
+728 262.6084 0.88610 +0.46194 Corpus Christi
+729 262.878580.648804+0.758451Glenlea Astronomical Observatory, Winnipeg
+730 262.841430.671544+0.738537University of North Dakota, Grand Forks
+731 272.6711 0.77290 +0.63244 Rose-Hulman Observatory, Terre Haute
+732 263.2300 0.95591 +0.29359 Oaxaca
+733 263.3546 0.83802 +0.54387 Allen, Texas
+734 263.9986 0.77943 +0.62449 Farpoint Observatory, Eskridge
+735 264.406400.872133+0.487634George Observatory, Needville
+736 263.3357 0.87006 +0.49132 Houston
+737 275.6633 0.8282  +0.5586  New Bullpen Observatory, Alpharetta
+738 267.6733 0.7788  +0.6252  Observatory of the State University of Missouri
+739 265.2440 0.77965 +0.62419 Sunflower Observatory, Olathe
+740 265.3383 0.8511  +0.5233  SFA Observatory, Nacogdoches
+741 266.8503 0.71493 +0.69692 Goodsell Observatory, Northfield
+742 266.312160.748989+0.660428Drake University, Des Moines
+743 267.761480.708545+0.703382University of Minnesota, Minneapolis
+744 273.8378 0.76884 +0.63735 Doyan Rose Observatory, Indianapolis
+745 267.1747 0.77569 +0.62906 Morrison Obervatory, Glasgow
+746 275.2254 0.72551 +0.68597 Brooks Observatory, Mt. Pleasant
+747 268.9292 0.86373 +0.50227 Highland Road Park Observatory
+748 268.4680 0.75014 +0.65912 Van Allen Observatory, Iowa City
+749 276.1642 0.82795 +0.55902 Oakwood
+750 268.7282 0.71059 +0.70131 Hobbs Observatory, Fall Creek
+751 269.2439 0.78038 +0.62324 Lake Saint Louis
+752 275.4647 0.82278 +0.56659 Puckett Observatory, Mountain Town
+753 270.590690.731622+0.679491Washburn Observatory, Madison
+754 271.4432 0.73762 +0.67303 Yerkes Observatory, Williams Bay
+755 274.6478 0.73353 +0.67743 Optec Observatory
+756 272.3257 0.74361 +0.66641 Dearborn Observatory, Evanston
+757 280.0050 0.8096  +0.5851  High Point
+758 279.2379 0.88044 +0.47257 BCC Observatory, Cocoa
+759 273.1947 0.80946 +0.58530 Nashville
+760 273.6048 0.77216 +0.63337 Goethe Link Observatory, Brooklyn
+761 277.6456 0.88138 +0.47083 Zephyrhills
+762 274.2008 0.70885 +0.70304 Four Winds Observatory, Lake Leelanau
+763 280.4658 0.72157 +0.69009 King City
+764 275.1439 0.83264 +0.55205 Puckett Observatory, Stone Mountain
+765 275.5775 0.77669 +0.62784 Cincinnati
+766 275.5167 0.73600 +0.67477 Michigan State University Obs., East Lansing
+767 276.2697 0.74102 +0.66930 Ann Arbor
+768 272.325000.743590+0.666435Dearborn Observatory
+769 276.9892 0.76716 +0.63936 McMillin Observatory, Columbus
+770 274.0786 0.77573 +0.62900 Crescent Moon Observatory, Columbus
+771 277.57   0.922   +0.389   Boyeros Observatory, Havana
+772 284.0865 0.70517 +0.70669 Boltwood Observatory, Stittsville
+773 278.4318 0.74966 +0.65966 Warner and Swasey Observatory, Cleveland
+774 278.9250 0.74905 +0.66039 Warner and Swasey Nassau Station, Chardon
+775 284.6168 0.76029 +0.64743 Sayre Observatory, South Bethlehem
+776 284.4669 0.73472 +0.67619 Foggy Bottom, Hamilton
+777 280.6017 0.72454 +0.68695 Toronto
+778 279.9778 0.76172 +0.64582 Allegheny Observatory, Pittsburgh
+779 280.5779 0.72219 +0.68943 David Dunlap Observatory, Richmond Hill
+780 281.4778 0.78868 +0.61280 Leander McCormick Observatory, Charlottesville
+781 281.5075 1.00045 -0.00405 Quito
+782 281.65   0.999   +0.000   Quito, comet astrograph station
+783 282.02   0.783   +0.622   Rixeyville
+784 282.2146 0.74140 +0.66895 Stull Observatory, Alfred University
+785 285.3542 0.76323 +0.64397 Fitz-Randolph Observatory, Princeton
+786 282.9345 0.77906 +0.62487 U.S. Naval Obs., Washington (since 1893)
+787 282.9494 0.77934 +0.62451 U.S. Naval Obs., Washington (before 1893)
+788 284.3667 0.76953 +0.63650 Mount Cuba Observatory, Wilmington
+789 284.5940 0.73188 +0.67922 Litchfield Observatory, Clinton
+790 284.2835 0.70343 +0.70840 Dominion Observatory, Ottawa
+791 284.5236 0.76713 +0.63937 Flower and Cook Observatory, Philadelphia
+792 288.30   0.753   +0.657   University of Rhode Island, Quonochontaug
+793 286.2200 0.73660 +0.67407 Dudley Observatory, Albany (before 1893)
+794 286.1100 0.74789 +0.66161 Vassar College Observatory, Poughkeepsie
+795 286.0123 0.7589  +0.6491  Rutherford
+796 286.45   0.755   +0.654   Stamford
+797 287.0751 0.75218 +0.65676 Yale Observatory, New Haven
+798 287.0154 0.75093 +0.65822 Yale Observatory, Bethany
+799 288.8650 0.73896 +0.67150 Winchester
+800 288.4511 0.96006 -0.28021 Harvard Observatory, Arequipa
+801 288.442330.738364+0.672183Oak Ridge Observatory
+802 288.871640.739802+0.670574Harvard Observatory, Cambridge
+803 288.9167 0.74543 +0.66436 Taunton
+804 289.3121 0.83421 -0.54976 Santiago-San Bernardo
+805 288.9800 0.83997 -0.54145 Santiago-Cerro El Roble
+806 289.4513 0.83584 -0.54738 Santiago-Cerro Calan
+807 289.1941 0.86560 -0.49980 Cerro Tololo Observatory, La Serena
+808 290.6708 0.85098 -0.52414 El Leoncito
+809 289.266260.873440-0.486052European Southern Observatory, La Silla
+810 288.5154 0.73712 +0.67352 Wallace Observatory, Westford
+811 289.895650.752586+0.656289Maria Mitchell Observatory, Nantucket
+812 288.4543 0.83992 -0.54093 Vina del Mar
+813 289.3083 0.83533 -0.54805 Santiago-Quinta Normal (1862-1920)
+814 288.419170.746007+0.663734North Scituate
+815 289.3479 0.83539 -0.54799 Santiago-Santa Lucia (1849-1861)
+816 285.7583 0.71645 +0.69542 Rand Observatory
+817 288.6104 0.74018 +0.67017 Sudbury
+818 286.4167 0.7040  +0.7079  Gemeaux Observatory, Laval
+819 284.3850 0.69720 +0.71451 Val-des-Bois
+820 295.375810.930491-0.365872Tarija
+821 295.4533 0.85270 -0.52103 Cordoba-Bosque Alegre
+822 295.8035 0.85419 -0.51834 Cordoba
+823 288.1691 0.73715 +0.67354 Fitchburg
+824 285.7528 0.71641 +0.69546 Lake Clear
+825 288.2595 0.74033 +0.67003 Granville
+826 288.2282 0.69312 +0.71843 Plessissville
+827 287.5393 0.66190 +0.74710 Saint-Felicien
+828 288.9758 0.74656 +0.66310 Assonet
+829 290.6979 0.85102 -0.52411 Complejo Astronomico El Leoncito
+830 288.5697 0.73491 +0.67590 Hudson
+831 277.4134 0.87191 +0.48804 Rosemary Hill Observatory, University of Florida
+832 283.1850 0.7653  +0.6416  Etters
+833 301.4633 0.82373 -0.56508 Obs. Astronomico de Mercedes, Buenos Aires
+834 301.5654 0.82398 -0.56473 Buenos Aires-AAAA
+835 288.6428 0.73709 +0.67354 Drum Hill Station, Chelmsford
+836 288.5011 0.74708 +0.66252 Furnace Brook Observatory, Cranston
+837 279.7553 0.89228 +0.44996 Jupiter
+838 275.8628 0.77000 +0.63596 Dayton
+839 302.0678 0.82097 -0.56906 La Plata
+840 276.2833 0.73235 +0.67870 Flint
+841 279.442330.796229+0.603220Martin Observatory, Blacksburg
+842 282.7678 0.76901 +0.63713 Gettysburg College Observatory
+843 273.0648 0.82481 +0.56357 Emerald Lane Observatory, Decatur
+844 303.809820.822499-0.566884Los Molinos
+845 283.5058 0.73942 +0.67107 Ford Observatory, Ithaca
+846 269.655010.779842+0.623926Principia Astronomical Observatory, Elsah
+847 275.9750 0.7078  +0.7041  Lunar Cafe Observator, Flint
+848 237.0219 0.72412 +0.68741 Tenagra Observatory, Cottage Grove
+849 265.1694 0.77927 +0.62467 Everstar Observatory, Olathe
+850 274.0802 0.81810 +0.57333 Cordell-Lorenz Observatory, Sewanee
+851 296.4189 0.71284 +0.69900 Burke-Gaffney Observatory, Halifax
+852 269.4050 0.7805  +0.6231  River Moss Observatory, St. Peters
+853 249.1517 0.84365 +0.53544 Biosphere 2 Observatory
+854 249.179950.846183+0.531351Sabino Canyon Observatory, Tucson
+855 266.5383 0.7093  +0.7026  Wayside Observatory, Minnetonka
+856 242.5540 0.8300  +0.5560  Riverside
+857 249.3992 0.85213 +0.52204 Iowa Robotic Observatory, Sonoita
+858 253.7800 0.8194  +0.5719  Tebbutt Observatory, Edgewood
+859 316.3097 0.94132 -0.33707 Wykrota Observatory-CEAMIG
+860 313.0347 0.92108 -0.38842 Valinhos
+861 312.9204 0.92253 -0.38487 Barao Geraldo
+862 138.5262 0.80861 +0.58658 Saku
+863 137.18   0.807   +0.588   Furukawa
+864 130.7533 0.84257 +0.53680 Kumamoto
+865 285.8792 0.74765 +0.66189 Emmy Observatory, New Paltz
+866 283.5100 0.7784  +0.6257  U.S. Naval Academy, Michelson
+867 134.1222 0.81671 +0.57522 Saji Observatory
+868 135.1359 0.83066 +0.55492 Hidaka Observatory
+869 133.4298 0.83480 +0.54870 Tosa
+870 313.17   0.934   -0.359   Campinas
+871 134.3925 0.82256 +0.56678 Akou
+872 134.2411 0.82904 +0.55734 Tokushima
+873 133.7717 0.82410 +0.56455 Kurashiki Observatory
+874 314.417350.924359-0.380986Itajuba
+875 139.2353 0.80896 +0.58593 Yorii
+876 139.2467 0.80762 +0.58774 Honjo
+877 139.0828 0.81194 +0.58196 Okutama
+878 136.9142 0.82019 +0.57019 Kagiya
+879 137.3535 0.81970 +0.57099 Tokai
+880 316.7771 0.92169 -0.38664 Rio de Janeiro
+881 137.2571 0.81872 +0.57230 Toyota
+882 137.3558 0.81842 +0.57281 JCPM Oi Station
+883 138.4215 0.81986 +0.57065 Shizuoka
+884 138.0792 0.8187  +0.5724  Kawane
+885 138.4667 0.82049 +0.56975 JCPM Yakiimo Station
+886 138.9367 0.81836 +0.57280 Mishima
+887 139.3367 0.80745 +0.58798 Ojima
+888 138.9952 0.81885 +0.57217 Gekko
+889 140.1427 0.80322 +0.59372 Karasuyama
+890 140.2500 0.8108  +0.5834  JCPM Tone Station
+891 140.8633 0.78606 +0.61609 JCPM Kimachi Station
+892 139.4753 0.80852 +0.58650 YGCO Hoshikawa and Nagano Stations
+893 140.862220.786233+0.615870Sendai Municipal Observatory
+894 138.4476 0.81113 +0.58321 Kiyosato
+895 140.7203 0.78573 +0.61658 Hatamae
+896 138.3678 0.81132 +0.58292 Yatsugatake South Base Observatory
+897 139.4929 0.80797 +0.58725 YGCO Chiyoda Station
+898 138.1883 0.82107 +0.56899 Fujieda
+899 142.5500 0.7224  +0.6891  Toma
+900 135.989940.819572+0.571083Moriyama
+901 137.0877 0.81664 +0.57525 Tajimi
+902 132.2208 0.82775 +0.55922 Ootake
+903 135.1769 0.81738 +0.57418 Fukuchiyama and Kannabe
+904 135.12   0.824   +0.565   Go-Chome and Kobe-Suma
+905 135.9246 0.83368 +0.55040 Nachi-Katsuura Observatory
+906 145.667  0.8113  -0.5837  Cobram
+907 144.9758 0.79082 -0.61001 Melbourne
+908 137.2467 0.80352 +0.59330 Toyama
+909 237.8717 0.6711  +0.7389  Snohomish Hilltop Observatory
+910   6.9267 0.72368 +0.68811 Caussols-ODAS
+911 282.9233 0.7429  +0.6672  Collins Observatory, Corning Community College
+912 288.2342 0.74769 +0.66186 Carbuncle Hill Observatory, Greene
+913 303.8161 0.82093 -0.56912 Observatorio Kappa Crucis, Montevideo
+914 288.0108 0.73809 +0.67254 Underwood Observatory, Hubbardston
+915 261.8789 0.86861 +0.49393 River Oaks Observatory, New Braunfels
+916 272.6836 0.77287 +0.63248 Oakley Observatory, Terre Haute
+917 237.5522 0.68140 +0.72948 Pacific Lutheran University Keck Observatory
+918 257.8694 0.72071 +0.69110 Badlands Observatory, Quinn
+919 248.3183 0.8419  +0.5379  Desert Beaver Observatory
+920 282.3353 0.73161 +0.67947 RIT Observatory, Rochester
+921 254.4725 0.83988 +0.54159 SW Institute for Space Research, Cloudcroft
+922 272.8333 0.82335 +0.56569 Timberland Observatory, Decatur
+923 284.6300 0.76655 +0.64006 The Bradstreet Observatory, St. Davids
+924 287.6769 0.68988 +0.72150 Observatoire du Cegep de Trois-Rivieres
+925 249.8589 0.85450 +0.51811 Palominas Observatory
+926 249.1209 0.85394 +0.51902 Tenagra II Observatory
+927 270.5619 0.73509 +0.67593 Madison-YRS
+928 286.6761 0.75688 +0.65136 Moonedge Observatory, Northport
+929 268.7758 0.86319 +0.50319 Port Allen
+930 210.412240.953752-0.299638Southern Stars Observatory, Tahiti
+931 210.3842 0.95330 -0.30100 Punaauia
+932 286.573940.749771+0.659497John J. McCarthy Obs., New Milford
+933 249.7342 0.85383 +0.51924 Rockland Observatory, Sierra Vista
+934 242.9572 0.83985 +0.54108 Poway Valley
+935 282.3394 0.77977 +0.62400 Wyrick Observatory, Haymarket
+936 263.3792 0.77614 +0.62852 Ibis Observatory, Manhattan
+937 358.6900 0.58065 +0.81143 Bradbury Observatory, Stockton-on-Tees
+938 351.6162 0.77243 +0.63299 Linhaceira
+939 359.6033 0.76982 +0.63619 Observatorio Rodeno
+940 358.9611 0.63199 +0.77238 Waterlooville
+941 359.6139 0.76988 +0.63608 Observatorio Pla D'Arguines
+942 359.3636 0.60413 +0.79423 Grantham
+943 355.8664 0.63881 +0.76679 Peverell
+944 354.0828 0.79661 +0.60248 Observatorio Geminis, Dos Hermanas
+945 354.3986 0.72671 +0.68474 Observatorio Monte Deva
+946   0.7931 0.75662 +0.65170 Ametlla de Mar
+947   2.1244 0.65268 +0.75511 Saint-Sulpice
+948   0.2189 0.61048 +0.78937 Pymoor
+949 359.8169 0.67454 +0.73577 Durtal
+950 342.1176 0.87764 +0.47847 La Palma
+951 358.2983 0.62194 +0.78046 Highworth
+952 359.7583 0.7787  +0.6253  Marxuquera
+953   2.1339 0.74602 +0.66393 Montjoia
+954 343.5033 0.8815  +0.4713  Teide Observatory
+955 350.6739 0.78146 +0.62188 Sassoeiros
+956 356.1908 0.76224 +0.64530 Observatorio Pozuelo
+957 359.3506 0.71047 +0.70137 Merignac
+958 358.9717 0.72421 +0.68727 Observatoire de Dax
+959   1.4653 0.72596 +0.68548 Ramonville Saint Agne
+960   0.6108 0.63016 +0.77387 Rolvenden
+961 356.8206 0.56112 +0.82498 City Observatory, Edinburgh
+962 359.8188 0.77845 +0.62561 Gandia
+963 359.7333 0.6084  +0.7909  Werrington
+964 358.8433 0.62471 +0.77826 Southend Bradfield
+965 351.4008 0.79761 +0.60118 Observacao Astronomica no Algarve, Portimao
+966 357.204230.609591+0.790100Church Stretton
+967 358.9778 0.61508 +0.78585 Greens Norton
+968   0.4250 0.6158  +0.7853  Haverhill
+969 359.8454 0.6235  +0.7792  London-Regents Park
+970   0.4954 0.62045 +0.78162 Chelmsford
+971 350.8140 0.78134 +0.62204 Lisbon
+972 357.5833 0.54359 +0.83656 Dun Echt
+973 359.6671 0.62271 +0.77983 Harrow
+974   8.9220 0.71542 +0.69637 Genoa
+975 359.6333 0.77292 +0.63239 Valencia
+976 358.48   0.612   +0.788   Leamington Spa
+977 351.5483 0.58660 +0.80717 Markree
+978 357.245410.588685+0.805673Conder Brow
+979 358.6697 0.62896 +0.77485 South Wonston
+980 357.2200 0.58864 +0.80570 Lancaster
+981 353.3522 0.58409 +0.80898 Armagh
+982 353.6621 0.59771 +0.79904 Dunsink Observatory, Dublin
+983 353.795250.805167+0.591067San Fernando
+984 357.26   0.631   +0.774   Eastfield
+985 357.53   0.607   +0.790   Telford
+986 358.75   0.624   +0.779   Ascot
+987 355.3735 0.58658 +0.80721 Isle of Man Observatory, Foxdale
+988 355.7060 0.56225 +0.82421 Glasgow
+989 357.69   0.600   +0.797   Wilfred Hall Observatory, Preston
+990 356.3121 0.76260 +0.64487 Madrid
+991 356.9278 0.59750 +0.79919 Liverpool (since 1867)
+992 356.9995 0.5973  +0.7993  Liverpool (before 1867)
+993 357.495560.629975+0.774031Woolston Observatory
+994 359.3878 0.62827 +0.77540 Godalming
+995 358.4177 0.57819 +0.81319 Durham
+996 358.7483 0.62025 +0.78179 Oxford
+997 359.15   0.619   +0.783   Hartwell
+998 359.757530.622254+0.780206London-Mill Hill
+999 359.4725 0.71033 +0.70153 Bordeaux-Floirac
+A00   0.3770 0.62475 +0.77821 Clark Observatory, Gravesend
+A01   0.7441 0.74414 +0.66596 Masia Cal Maciarol Modul 1
+A02   0.7441 0.74414 +0.66596 Masia Cal Maciarol Modul 8
+A03   1.4000 0.7541  +0.6546  Torredembarra
+A04   1.7181 0.72206 +0.68956 Saint-Caprais
+A05   1.8175 0.72721 +0.68417 Belesta
+A06   2.4417 0.74922 +0.66012 Mataro
+A07   2.7444 0.66070 +0.74815 Gretz-Armainvilliers
+A08   2.8847 0.72735 +0.68406 Malibert
+A09   1.1803 0.65037 +0.75711 Quincampoix
+A10   1.9281 0.75278 +0.65613 Observatorio Astronomico de Corbera
+A11   2.4718 0.63222 +0.77219 Wormhout
+A12   8.747680.703404+0.708434Stazione Astronomica di Sozzago
+A13   7.1394 0.68632 +0.72501 Observatoire Naef, Marly
+A14   5.1864 0.72028 +0.69143 Les Engarouines Observatory
+A15   6.7972 0.61903 +0.78275 Josef Bresser Sternwarte, Borken
+A16   7.1922 0.68622 +0.72511 Tentlingen
+A17   8.681520.650125+0.757317Guidestar Observatory, Weinheim
+A18   7.1761 0.62342 +0.77928 Herne
+A19   7.0744 0.63164 +0.77267 Koln
+A20   7.518870.605274+0.793357Sogel
+A21   8.0581 0.63667 +0.76862 Irmtraut
+A22   8.6531 0.64877 +0.75848 Starkenburg Sternwarte-SOHAS
+A23   8.6677 0.65027 +0.75719 Weinheim
+A24   8.9481 0.69995 +0.71185 New Millennium Observatory, Mozzate
+A25   9.1925 0.70104 +0.71077 Nova Milanese
+A26   8.657360.646597+0.760303Darmstadt
+A27  10.3236 0.61823 +0.78341 Eridanus Observatory, Langelsheim
+A28  10.3342 0.67398 +0.73642 Kempten
+A29  10.6733 0.72369 +0.68782 Santa Maria a Monte
+A30  11.223080.700397+0.711555Crespadoro
+A31  11.4186 0.70024 +0.71155 Corcaroli Observatory
+A32  10.5517 0.58423 +0.80887 Panker
+A33  11.0157 0.63231 +0.77217 Volkssternwarte Kirchheim
+A34  10.7911 0.64944 +0.75793 Grosshabersdorf
+A35  12.8978 0.63511 +0.76995 Hormersdorf Observatory
+A36   9.7911 0.69856 +0.71340 Ganda di Aviatico
+A37  13.6634 0.61128 +0.78877 Mueggelheim
+A38  13.3747 0.74706 +0.66266 Campocatino Automated Telescope, Collepardo
+A39  12.4186 0.63084 +0.77336 Altenburg
+A40  14.4978 0.81104 +0.58306 Pieta
+A41  14.5911 0.69290 +0.71871 Rezman Observatory, Kamnik
+A42   9.5019 0.61280 +0.78760 Gehrden
+A43  13.0897 0.61201 +0.78821 Inastars Observatory, Potsdam (before 2006)
+A44  13.6972 0.66609 +0.74346 Altschwendt
+A45   9.3620 0.62525 +0.77786 Karrenkneul
+A46  16.5825 0.65349 +0.75447 Lelekovice
+A47  16.6031 0.75962 +0.64829 Matera
+A48  10.8885 0.70401 +0.70782 Povegliano Veronese
+A49  17.6372 0.50372 +0.86098 Uppsala-Angstrom
+A50  28.9973 0.64407 +0.76245 Andrushivka Astronomical Observatory
+A51  18.6667 0.5837  +0.8093  Danzig
+A52  18.7553 0.67756 +0.73304 Etyek
+A53  10.6883 0.70294 +0.70889 Peschiera del Garda
+A54  16.6217 0.60828 +0.79108 Ostrorog
+A55  13.1181 0.73871 +0.67204 Osservatorio Astronomico Vallemare di Borbona
+A56  10.3197 0.71406 +0.69784 Parma
+A57  11.1031 0.72364 +0.68791 Osservatorio Astron. Margherita Hack, Firenze
+A58   2.4694 0.66135 +0.74758 Observatoire de Chalandray-Canotiers
+A59  12.9071 0.64123 +0.76490 Karlovy Vary Observatory
+A60  20.8106 0.84556 -0.53260 YSTAR-NEOPAT Station, Sutherland
+A61   8.8581 0.70949 +0.70238 Tortona
+A62   9.2301 0.66233 +0.74678 Aichtal
+A63   4.7567 0.69879 +0.71298 Cosmosoz Obs., Tassin la Demi Lune
+A64   6.1151 0.69034 +0.72132 Couvaloup de St-Cergue
+A65   2.4083 0.71939 +0.69239 Le Couvent de Lentin
+A66  10.3161 0.72613 +0.68526 Stazione Osservativa Astronomica, Livorno
+A67   7.6785 0.71665 +0.69522 Chiusa di Pesio
+A68   9.6533 0.57755 +0.81362 Swedenborg Obs., Bockholmwik
+A69  11.3300 0.7287  +0.6826  Osservatorio Palazzo Bindi Sergardi
+A70  25.2033 0.42654 +0.90144 Lumijoki
+A71  15.4533 0.66486 +0.74459 Stixendorf
+A72  13.6222 0.62904 +0.77481 Radebeul Observatory
+A73  16.2895 0.66788 +0.74183 Penzing Astrometric Obs., Vienna
+A74   8.762400.641951+0.764216Bergen-Enkheim Observatory
+A75   2.1861 0.75124 +0.65783 Fort Pius Observatory, Barcelona
+A76  20.8356 0.66948 +0.74037 Andromeda Observatory, Miskolc
+A77   5.6475 0.72058 +0.69119 Observatoire Chante-Perdrix, Dauban
+A78  11.715090.730944+0.680264Stia
+A79  23.843400.743686+0.666622Zvezdno Obshtestvo Observatory, Plana
+A80  14.1222 0.61408 +0.78662 Lindenberg Observatory
+A81  12.4033 0.74578 +0.66397 Balzaretto Observatory, Rome
+A82  13.8744 0.70037 +0.71148 Osservatorio Astronomico di Trieste
+A83  29.9969 0.45945 +0.88525 Jakokoski Observatory
+A84  30.3333 0.80175 +0.59632 TUBITAK National Observatory
+A85  30.8065 0.68881 +0.72252 Odessa Astronomical Observatory, Kryzhanovka
+A86   4.3547 0.70170 +0.71021 Albigneux
+A87   8.7662 0.64935 +0.75798 Rimbach
+A88   8.901330.714961+0.696835Bolzaneto
+A89  10.3308 0.67421 +0.73621 Sterni Observatory, Kempten
+A90   2.1431 0.75120 +0.65788 Sant Gervasi Observatory, Barcelona
+A91  26.5997 0.46678 +0.88143 Hankasalmi Observatory
+A92  26.3442 0.71507 +0.69674 Urseanu Observatory, Bucharest
+A93  10.4189 0.72222 +0.68935 Lucca
+A94  13.4577 0.69641 +0.71526 Cormons
+A95  28.3892 0.46584 +0.88193 Taurus Hill Observatory, Varkaus
+A96  16.2867 0.66656 +0.74303 Klosterneuburg
+A97  16.4219 0.66646 +0.74308 Stammersdorf
+A98  30.2092 0.58214 +0.81040 Taurus-1 Observatory, Baran'
+A99  10.8589 0.69978 +0.71223 Osservatorio del Monte Baldo
+B00   2.5767 0.66289 +0.74622 Savigny-le-Temple
+B01   8.4464 0.64117 +0.76499 Taunus Observatory, Frankfurt
+B02  20.6566 0.63224 +0.77224 Kielce
+B03  16.2698 0.66759 +0.74211 Alter Satzberg, Vienna
+B04   7.478510.698677+0.713400OAVdA, Saint-Barthelemy
+B05  37.8831 0.57134 +0.81800 Ka-Dar Observatory, Barybino
+B06   2.5206 0.74755 +0.66208 Montseny Astronomical Observatory
+B07   9.0033 0.69383 +0.71778 Camorino
+B08  11.3807 0.71498 +0.69683 San Lazzaro di Savena
+B09  10.6708 0.72550 +0.68593 Capannoli
+B10   5.5150 0.71564 +0.69631 Observatoire du Mas des Gres, Moydans
+B11  10.6286 0.69881 +0.71318 Osservatorio Cima Rest, Magasa
+B12   4.4906 0.61329 +0.78721 Koschny Observatory, Noordwijkerhout
+B13   8.9311 0.69950 +0.71231 Osservatorio di Tradate
+B14   9.0758 0.71061 +0.70138 Ca del Monte
+B15  13.0129 0.61111 +0.78890 Inastars Observatory, Potsdam (since 2006)
+B16  36.9547 0.56382 +0.82317 1st Moscow Gymnasium Observatory, Lipki
+B17  33.1633 0.70559 +0.70625 AZT-8 Evpatoria
+B18  42.5008 0.72958 +0.68232 Terskol
+B19   2.4414 0.74963 +0.65966 Observatorio Iluro, Mataro
+B20   2.2636 0.75026 +0.65897 Observatorio Carmelita, Tiana
+B21  13.4744 0.66335 +0.74589 Gaisberg Observatory, Schaerding
+B22   0.7441 0.74412 +0.66598 Observatorio d'Ager, Barcelona
+B23  10.9710 0.70124 +0.71069 Fiamene
+B24   2.5983 0.66317 +0.74598 Cesson
+B25  15.0557 0.79386 +0.60614 Catania
+B26   5.6667 0.72204 +0.68966 Observatoire des Terres Blanches, Reillanne
+B27  14.1544 0.66425 +0.74516 Picard Observatory, St. Veit
+B28  13.1836 0.69466 +0.71696 Mandi Observatory, Pagnacco
+B29   0.6701 0.75801 +0.65008 L'Ampolla Observatory, Tarragona
+B30  16.5689 0.60872 +0.79074 Szamotuly-Galowo
+B31  20.8108 0.84560 -0.53254 Southern African Large Telescope, Sutherland
+B32  12.9486 0.63467 +0.77030 Gelenau
+B33  10.7783 0.72588 +0.68555 Libbiano Observatory, Peccioli
+B34  33.7258 0.81748 +0.57405 Green Island Observatory, Gecitkale
+B35  35.0317 0.84991 +0.52524 Bareket Observatory, Macabim
+B36  13.7125 0.66684 +0.74278 Redshed Observatory, Kallham
+B37   2.259340.748338+0.661147Obs. de L' Ametlla del Valles, Barcelona
+B38  11.857460.724995+0.686523Santa Mama
+B39   8.9072 0.69950 +0.71231 Tradate
+B40  15.0706 0.79331 +0.60690 Skylive Observatory, Catania
+B41  17.6925 0.65449 +0.75362 Zlin Observatory
+B42  30.3275 0.57401 +0.81614 Vitebsk
+B43   7.3089 0.63404 +0.77073 Hennef
+B44   5.5906 0.71772 +0.69419 Eygalayes
+B45  19.9356 0.64169 +0.76447 Narama
+B46  12.054390.714373+0.697420Sintini Observatory, Alfonsine
+B47  24.7503 0.49826 +0.86413 Metsala Observatory, Espoo
+B48   6.5981 0.61901 +0.78275 Bocholt
+B49   2.112690.749492+0.659841Paus Observatory, Sabadell
+B50   8.2767 0.65808 +0.75045 Corner Observatory, Durmersheim
+B51   7.066690.725612+0.685830Vallauris
+B52   2.997250.741344+0.668883Observatorio El Far
+B53  12.3536 0.74572 +0.66404 Casal Lumbroso, Rome
+B54   0.7439 0.74413 +0.66597 Ager
+B55  12.876000.689553+0.721975Comeglians
+B56   2.449350.749614+0.659663Observatorio Sant Pere, Mataro
+B57   2.224390.749316+0.660019Laietania Observatory, Parets del Valles
+B58  19.025290.676156+0.734318Polaris Observatory, Budapest
+B59   6.878810.619231+0.782586Borken
+B60   7.175310.612824+0.787576Deep Sky Observatorium, Bad Bentheim
+B61   2.043500.750575+0.658604Valldoreix Obs.,Sant Cugat del Valles
+B62   9.685310.609275+0.790314Brelingen
+B63  20.107990.642600+0.763710Solaris Observatory, Luczanowice
+B64  24.887790.491587+0.867927Slope Rock Observatory, Hyvinkaa
+B65  24.3878 0.49864 +0.86391 Komakallio Observatory, Kirkkonummi
+B66   9.006930.710595+0.701332Osservatorio di Casasco
+B67   9.224190.685858+0.725582Sternwarte Mirasteilas, Falera
+B68  13.539500.693458+0.718372Mount Matajur Observatory
+B69   9.017190.662152+0.746956Owls and Ravens Observatory, Holzgerlingen
+B70   2.4937 0.74787 +0.66165 Sant Celoni
+B71   1.5213 0.75363 +0.65510 Observatorio El Vendrell
+B72   7.6811 0.63470 +0.77022 Soerth
+B73   8.985030.662074+0.747029Mauren Valley Observatory, Holzgerlingen
+B74   1.105360.747550+0.662053Santa Maria de Montmagastrell
+B75   8.805190.701074+0.710741Stazione Astronomica Betelgeuse, Magnago
+B76  13.8944 0.63019 +0.77390 Sternwarte Schonfeld, Dresden
+B77   7.950830.677934+0.732833Schafmatt Observatory, Aarau
+B78  14.128110.670885+0.739158Astrophoton Observatory, Audorf
+B79  11.209900.700480+0.711457Marana Observatory
+B80  12.741260.742254+0.667919Osservatorio Astronomico Campomaggiore
+B81   2.8990 0.76967 +0.63634 Caimari
+B82   9.9716 0.64613 +0.76072 Maidbronn
+B83   5.797690.706034+0.705851Gieres
+B84   3.537750.622812+0.779749Cyclops Observatory, Oostkapelle
+B85   6.510110.604962+0.793587Beilen Observatory
+B86   7.455610.625931+0.777324Sternwarte Hagen
+B87   2.7701 0.74295 +0.66715 Banyoles
+B88   8.296810.710570+0.701309Bigmuskie Observatory, Mombercelli
+B89   2.2619 0.75018 +0.65907 Observatori Astronomic de Tiana
+B90  13.296860.693994+0.717600Malina River Observatory, Povoletto
+B91   7.255440.672149+0.737995Bollwiller
+B92   0.275390.681073+0.729781Chinon
+B93   6.478560.607102+0.791962Hoogeveen
+B94  34.2817 0.47422 +0.87748 Petrozavodsk
+B95   8.154500.602437+0.795492Achternholt
+B96   4.310310.628378+0.775301Brixiis Observatory, Kruibeke
+B97   6.1118 0.61688 +0.78442 Sterrenwacht Andromeda, Meppel
+B98  11.313000.728746+0.682563Siena
+B99   0.7625 0.74431 +0.66577 Santa Coloma de Gramenet
+C00  30.5150 0.55583 +0.82853 Velikie Luki
+C42  87.1778 0.72711 +0.68469 Xingming Observatory, Mt. Nanshan
+C49                           STEREO-A
+C50                           STEREO-B
+D14 113.3231 0.92000 +0.39061 Nanchuan Observatory, Guangzhou
+D16 113.964220.925155+0.378330Po Leung Kuk Observatory, Tuen Mun
+D17 114.2200 0.9245  +0.3799  Hong Kong
+D20 115.713110.854733-0.517343Zadko Observatory, Wallingup Plain
+D21 115.8150 0.8492  -0.5263  Shenton Park
+D24 117.089690.844095-0.534439LightBuckets Observatory, Pingelly
+D25 117.089780.844104-0.534424Tzec Maun Observatory, Pingelly
+D29 118.4639 0.84204 +0.53767 Purple Mountain Observatory, XuYi Station
+D32 119.599750.862770+0.504193JiangNanTianChi Observatory, Mt. Getianling
+D34 120.7839 0.92796 +0.37148 Kenting Observatory, Hengchun
+D35 120.8736 0.91818 +0.39597 Lulin Observatory
+D36 120.8897 0.91801 +0.39625 Tataka, Mt. Yu-Shan National Park
+D39 122.049000.793974+0.605939Shandong University Observatory, Weihai
+D44 124.139280.911427+0.410157Ishigakijima Astronomical Observatory
+D55 127.9747 0.79571 +0.60370 Kangwon Science High School Observatory, Ksho
+D57 128.887440.817572+0.573996Gimhae Astronomical Observatory, Uhbang-dong
+D58 129.025000.818419+0.572736KSA SEM Observatory, Danggam-dong
+D61 134.9131 0.82671 +0.56075 Suntopia Marina, Sumoto
+D62 130.4494 0.83676 +0.54575 Miyaki-Argenteus
+D70 133.4686 0.83505 +0.54834 Tosa
+D74 134.6819 0.83041 +0.55530 Nakagawa
+D78 136.132810.822378+0.567077Iga-Ueno
+D80 138.9728 0.80392 +0.59297 Gumma Astronomical Observatory
+D81 138.2239 0.80310 +0.59394 Nagano
+D82 137.6317 0.83058 -0.55504 Wallaroo
+D83 138.4681 0.80501 +0.59161 Miwa
+D84 138.5086 0.8192  -0.5716  Hallet Cove
+D85 138.6597 0.82186 -0.56782 Ingle Farm
+D86 138.6407 0.83075 -0.55490 Penwortham
+D87 138.5500 0.82079 -0.56931 Brooklyn Park
+D88 139.3142 0.81635 +0.57562 Hiratsuka
+D89 140.3383 0.7871  +0.6149  Yamagata
+D90 140.3420 0.82728 -0.55991 RAS Observatory, Moorook
+D91 140.8250 0.79261 +0.60775 Adati
+D92 140.946380.782920+0.620047Osaki
+D93 140.755160.786291+0.615826Sendai Astronomical Observatory
+D94 139.9962 0.80351 +0.59335 Takanezawa, Tochigi
+E00 144.2089 0.79902 -0.59937 Castlemaine
+E01 144.541420.798618-0.599924Barfold
+E03 145.3822 0.78756 -0.61419 RAS Observatory, Officer
+E04 145.7403 0.96545 +0.25977 Pacific Sky Observatory, Saipan
+E05 145.697210.957625-0.287092Earl Hill Observatory, Trinity Beach
+E08 149.334310.855971-0.515472Wobblesock Observatory, Coonabarabran
+E09 149.0814 0.85551 -0.51630 Oakley Southern Sky Observatory, Coonabarabran
+E10 149.070280.855623-0.516200Siding Spring-Faulkes Telescope South
+E11 149.6627 0.84469 -0.53362 Frog Rock Observatory, Mudgee
+E12 149.0642 0.85563 -0.51621 Siding Spring Survey
+E13 149.0969 0.81622 -0.57597 Wanniassa
+E14 149.1100 0.81852 -0.57274 Hunters Hill Observatory, Ngunnawal
+E15 149.6061 0.82016 -0.57041 Magellan Observatory, near Goulburn
+E16 149.366570.831679-0.553653Grove Creek Observatory, Trunkey
+E17 150.3417 0.8329  -0.5519  Leura
+E18 151.027140.829819-0.556191BDI Observatory, Regents Park
+E19 151.0958 0.83042 -0.55528 Kingsgrove
+E20 151.103200.832146-0.552728Marsfield
+E21 151.5667 0.8838  -0.4665  Norma Rose Observatory, Leyburn
+E22 151.855000.885337-0.463616Univ. of Southern Queensland Obs., Mt. Kent
+E25 153.1170 0.88713 -0.45997 Rochedale (APTA)
+E26 153.3971 0.88414 -0.46566 RAS Observatory, Biggera Waters
+E27 153.2667 0.8871  -0.4600  Thornlands
+E85 174.894000.800696-0.597064Farm Cove
+E94 177.883310.782217-0.620920Possum Observatory, Gisborne
+F51 203.744090.936242+0.351541Pan-STARRS 1, Haleakala
+F59 201.941000.932037+0.361160Ironwood Remote Observatory, Hawaii
+F60 201.952830.929942+0.366558Ironwood Observatory, Hawaii
+F65 203.7424 0.93624 +0.35154 Haleakala-Faulkes Telescope North
+F84 210.3842 0.95330 -0.30100 Hibiscus Observatory, Punaauia
+F85 210.3842 0.95330 -0.30100 Tiki Observatory, Punaauia
+F86 210.383810.953304-0.301004Moana Observatory, Punaauia
+G56 237.9294 0.78983 +0.61128 Walnut Creek
+G57 236.8564 0.70171 +0.71009 Dilbert Observatory, Forest Grove
+G58 237.8180 0.79100 +0.60988 Chabot Space and Science Center, Oakland
+G59 237.4530 0.67475 +0.73559 Maiden Lane Obs., Bainbridge Island
+G60 240.338880.825544+0.562496Carroll Observatory, Montecito
+G61 238.1524 0.79270 +0.60760 Pleasanton
+G62 238.5469 0.72214 +0.68971 Sunriver Nature Center Observatory, Sunriver
+G63 238.6858 0.70152 +0.71031 Mill Creek Observatory, The Dalles
+G64 239.2911 0.77535 +0.62979 Blue Canyon Observatory
+G65 238.3612 0.79616 +0.60338 Vulcan North, Lick Observatory, Mount Hamilton
+G66 238.9169 0.78135 +0.62206 Lake Forest Observatory, Forest Hills
+G67 239.3650 0.78134 +0.62225 Rancho Del Sol, Camino
+G68 240.2250 0.78044 +0.62355 Sierra Stars Observatory, Markleeville
+G69 241.0158 0.82829 +0.55850 Thousand Oaks
+G70 241.4547 0.82543 +0.56273 Francisquito Observatory, Los Angeles
+G71 241.6047 0.83216 +0.55276 Rancho Palos Verdes
+G72 241.824080.829301+0.556970University Hills
+G73 241.9400 0.82804 +0.55925 Mount Wilson-TIE
+G74 242.8854 0.83743 +0.54485 Escondido
+G75 243.2783 0.8351  +0.5487  Starry Knight Observatory, Coto de Caza
+G76 242.4178 0.83388 +0.55015 Altimira Observatory, Coto de Caza
+G77 243.7183 0.8274  +0.5603  Baldwin Lake
+G78 244.3127 0.84158 +0.53832 Desert Wanderer Observatory, El Centro
+G79 243.6165 0.82718 +0.56030 Goat Mountain Astronomical Research Station
+G80 240.5873 0.79904 +0.59962 Sierra Remote Observatories, Auberry
+G81 242.913000.834904+0.548639Temecula
+G82 248.400250.849488+0.526449SARA Observatory, Kitt Peak
+G83 250.110390.842740+0.537440Mt. Graham-LBT
+G84 249.210840.845112+0.533610Mount Lemmon SkyCenter
+G85 247.565180.799502+0.599067Vermillion Cliffs Observatory, Kanab
+G86 249.0697 0.84645 +0.53090 Tucson-Winterhaven
+G87 248.1894 0.74666 +0.66331 Calvin M. Hooper Memorial Observatory, Hyde Park
+G88 247.8881 0.83064 +0.55514 LAMP Observatory, New River
+G89 248.3069 0.81933 +0.57197 Kachina Observatory, Flagstaff
+G90 248.9658 0.84301 +0.53639 Three Buttes Observatory, Tucson
+G91 249.1154 0.85205 +0.52249 Whipple Observatory, Mt. Hopkins--2MASS
+G92 249.2814 0.84920 +0.52660 Jarnac Observatory, Vail
+G93 249.3726 0.85215 +0.52201 Sonoita Research Observatory, Sonoita
+G94 249.9267 0.84971 +0.52594 Sonoran Skies Observatory, St. David
+G95 249.7622 0.85404 +0.51888 Hereford Arizona Observatory, Hereford
+G96 249.211280.845111+0.533614Mt. Lemmon Survey
+G97 250.8694 0.84965 +0.52600 Astronomical League Alpha Observatory, Portal
+G98 251.343540.815037+0.578012Calvin-Rehoboth Observatory, Rehoboth
+G99 251.8104 0.84192 +0.53835 NF Observatory, Silver City
+H00 251.6987 0.84247 +0.53746 Tyrone
+H01 252.8108 0.83047 +0.55610 Magdalena Ridge Observatory, Socorro
+H02 253.3706 0.81146 +0.58309 Sulphur Flats Observatory, La Cueva
+H03 253.3553 0.81753 +0.57440 Sandia View Observatory, Rio Rancho
+H04 254.0260 0.81388 +0.57964 Santa Fe
+H05 256.0707 0.77126 +0.63477 Edmund Kline Observatory, Deer Trail
+H06 254.471340.840711+0.540310RAS Observatory, Mayhill
+H07 254.471340.840711+0.5403107300 Observatory, Cloudcroft
+H08 254.470810.840705+0.540319BlackBird Observatory, Cloudcroft
+H09 255.5886 0.77070 +0.63549 Antelope Hills Observatory, Bennett
+H10 254.471410.840711+0.540309Tzec Maun Observatory, Mayhill
+H11 250.9840 0.85029 +0.52492 Rodeo
+H12 254.470780.840712+0.540307LightBuckets Observatory, Mayhill
+H22 272.7371 0.77438 +0.63062 Terre Haute
+H23 273.498580.862319+0.504671Pear Tree Observatory, Valparaiso
+H24 274.598810.733648+0.677310J. C. Veen Observatory, Lowell
+H25 266.870820.714467+0.697388Harvest Moon Observatory, Northfield
+H26 270.789220.735075+0.675789Doc Greiner Research Observatory, Janesvillle
+H27 266.231340.780074+0.623645Moonglow Observatory, Warrensburg
+H28 263.231500.836912+0.545569Preston Hills Observatory, Celina
+H29 262.5494 0.81372 +0.57940 Ivywood Observatory, Edmond
+H30 262.5558 0.81808 +0.57328 University of Oklahoma Observatory, Norman
+H31 263.3300 0.87011 +0.49123 Star Ridge Observatory, Weimar
+H32 263.6334 0.86174 +0.50567 Texas A&M Physics Observatory, College Station
+H33 264.1217 0.80990 +0.58466 Bixhoma Observatory, Bixby
+H34 264.8258 0.84600 +0.53143 Chapel Hill
+H35 264.9517 0.77423 +0.63085 Leavenworth
+H36 264.2936 0.78043 +0.62323 Sandlot Observatory, Scranton
+H37 265.2003 0.72947 +0.68182 Grems Timmons Observatories, Graettinger
+H38 265.9864 0.75079 +0.65840 Timberline Observatory, Urbandale
+H39 266.6828 0.70944 +0.70247 S.O.S. Observatory, Minneapolis
+H40 266.7306 0.82519 +0.56302 Nubbin Ridge Observatory
+H41 267.0742 0.81870 +0.57238 Petit Jean Mountain
+H42 267.5078 0.73568 +0.67512 Wartburg College Observatory, Waverly
+H43 267.4998 0.81918 +0.57163 Conway
+H44 267.7982 0.81880 +0.57220 Cascade Mountain
+H45 267.0831 0.81890 +0.57210 Arkansas Sky Obs., Petit Jean Mountain South
+H46 265.7297 0.77818 +0.62602 Ricky Observatory, Blue Springs
+H47 269.1439 0.84639 +0.53079 Vicksburg
+H48 265.0139 0.79424 +0.60565 PSU Greenbush Observatory, Pittsburg
+H49 266.8636 0.81712 +0.57457 ATU Astronomical Observatory, Russellville
+H50 267.541390.819253+0.571536University of Central Arkansas Obs., Conway
+H51 270.4003 0.73117 +0.68011 Greiner Research Observatory, Verona
+H52 270.673560.739151+0.671335Hawkeye Observatory, Durand
+H53 271.228420.789618+0.611581Thompsonville
+H54 271.6514 0.71305 +0.69883 Cedar Drive Observatory, Pulaski
+H55 271.8558 0.77283 +0.63254 Astronomical Research Observatory, Charleston
+H56 272.167640.742693+0.667433Northbrook Meadow Observatory
+H57 275.972460.758850+0.649150Ohio State University Observatory, Lima
+H58 273.3353 0.82349 +0.56548 NASA/MSFC ALaMO, Redstone Arsenal
+H59 273.3651 0.76362 +0.64356 Prairie Grass Observatory, Camp Cullom
+H60 273.865420.767435+0.639034Shadowbox Observatory, Carmel
+H61 281.416890.721533+0.690080Newcastle
+H62 274.4117 0.73335 +0.67763 Calvin College Observatory
+H63 274.9276 0.75227 +0.65672 DeKalb Observatory, Auburn
+H64 275.4364 0.77796 +0.62623 Thomas More College Observatory, Crestview Hills
+H65 275.4364 0.77995 +0.62381 Waltonfields Observatory, Walton
+H66 276.1460 0.76956 +0.63651 Yellow Springs
+H67 276.162410.740813+0.669522Stonegate Observatory, Ann Arbor
+H68 276.348240.854246+0.518152Red Barn Observatory, Ty Ty
+H69 276.944630.764320+0.642741Perkins Observatory, Delaware
+H70 277.4458 0.81412 +0.57897 Asheville
+H71 276.482820.852885+0.520378Chula
+H72 278.2258 0.89584 +0.44289 Evelyn L. Egan Observatory, Fort Myers
+H73 278.6351 0.74850 +0.66097 Lakeland Astronomical Observatory, Kirtland
+H74 278.8747 0.87602 +0.48066 Bar J Observatory, New Smyrna Beach
+H75 278.918560.749551+0.659816Indian Hill North Observatory, Huntsburg
+H76 279.4133 0.90197 +0.43036 Oakridge Observatory, Miami
+H77 279.7653 0.89877 +0.43695 Buehler Observatory
+H78 282.708961.000183+0.021030University of Narino Observatory, Pasto
+H79 280.492700.723258+0.688308York University Observatory, Toronto
+H80 285.335670.763194+0.644015Halstead Observatory, Princeton
+H81 283.6161 0.73896 +0.67161 Hartung-Boothroyd Observatory, Ithaca
+H82 281.7839 0.77836 +0.62576 CBA-NOVAC Observatory, Front Royal
+H83 282.6641 0.77926 +0.62463 Timberlake Observatory, Oakton
+H84 282.4961 0.73259 +0.67843 Northview Observatory, Mendon
+H85 283.0029 0.77784 +0.62638 Silver Spring
+H86 283.1576 0.77693 +0.62749 CBA-East Observatory, Laurel
+H87 282.4361 0.79309 +0.60708 Fenwick Observatory, Richmond
+H88 283.7577 0.77295 +0.63235 Hope Observatory, Belcamp
+H89 284.2975 0.70235 +0.70945 Galaxy Blues Observatory, Gatineau
+H90 284.4731 0.70267 +0.70914 Ottawa
+H91 285.048390.712263+0.699590Reynolds Observatory, Potsdam
+H92 285.6211 0.76785 +0.63849 Arcturus Observatory
+H93 285.5758 0.75934 +0.64853 Berkeley Heights
+H94 285.5439 0.75781 +0.65032 Cedar Knolls
+H95 285.821200.758745+0.649211NJIT Observatory, Newark
+H96 286.6142 0.69143 +0.72005 Observatoire des Pleiades, Mandeville
+H97 287.201320.746487+0.663233Talcott Mountain Science Center, Avon
+H98 287.2655 0.74987 +0.65938 Dark Rosanne Obs., Middlefield
+H99 288.8036 0.74040 +0.66992 Sunhill Observatory, Newton
+I00 288.2294 0.74794 +0.66157 Carbuncle Hill Observatory, Coventry
+I01 288.862530.740677+0.669630Clay Center Observatory, Brookline
+I02 289.1941 0.86560 -0.49980 Cerro Tololo Observatory, La Serena--2MASS
+I03 289.266260.873440-0.486052European Southern Obs., La Silla--ASTROVIRTEL
+I04 289.3152 0.86693 -0.49697 Mamalluca Observatory
+I05 289.2980 0.87559 -0.48217 Las Campanas Observatory-TIE
+I06 289.8061 0.74801 +0.66147 Werner Schmidt Obs., Dennis-Yarmouth Regional HS
+I07 288.0971 0.74279 +0.66735 Conlin Hill Observatory, Oxford
+I08 290.6932 0.85116 -0.52394 Alianza S4, Cerro Burek
+I09 289.803770.910166-0.413875Cerro Armazones
+I10 291.8200 0.92165 -0.38770 Campo Catino Austral Obs., San Pedro de Atacama
+I11 289.263450.865020-0.500901Gemini South Observatory, Cerro Pachon
+I12 288.870530.736679+0.673998Phillips Academy Observatory, Andover
+I13 282.930060.779116+0.624793Washington D.C.
+I14 288.589310.740298+0.670040Tigh Speuran Observatory, Framingham
+I15 288.700750.747034+0.662557Wishing Star Observatory, Barrington
+I19 295.407110.854834-0.517422Tanti
+I20 295.681610.838551-0.543122Rio Cuarto
+I21 295.8281 0.85465 -0.51760 El Condor Observatory, Cordoba
+I22 296.1740 0.71212 +0.69973 Abbey Ridge Observatory, Stillwater Lake
+I30 299.3417 0.83966 -0.54131 Observatorio Geminis Austral
+I31 299.3649 0.83995 -0.54086 Observatorio Astronomico del Colegio Cristo Rey
+I32 299.3464 0.83969 -0.54125 Observatorio Beta Orionis, Rosario
+I36 301.2827 0.81998 -0.57048 Observatorio Los Campitos, Canuelas
+I37 301.352750.825603-0.562360Astrodomi Observatory, Santa Rita
+I38 302.021410.854400-0.517885Observatorio Los Algarrobos, Salto
+I68 312.4981 0.96931 -0.24573 Pousada dos Anoes Observatory
+I77 316.0025 0.94119 -0.33714 CEAMIG-REA Observatory, Belo Horizonte
+J04 343.488170.881463+0.471461ESA Optical Ground Station, Tenerife
+J05 355.296390.749617+0.659822Bootes Observatory, Boecillo
+J06 358.812470.604374+0.794039Trent Astronomical Observatory, Clifton
+J07 353.895430.767881+0.638546Observatorio SPAG Monfrague, Palazuelo-Empalme
+J08 359.6549 0.77127 +0.63439 Observatorio Zonalunar, Puzol
+J09 353.7917 0.59450 +0.80141 Balbriggan
+J10 359.598390.784437+0.618151Alicante
+J11 351.317690.746984+0.662617Matosinhos
+J12 356.510610.758248+0.649949Caraquiz
+J13 342.1208 0.87763 +0.47851 La Palma-Liverpool Telescope
+J14 345.992810.880303+0.472891La Corte
+J15 352.830610.755420+0.653125Muxagata
+J16 354.203560.584292+0.808826An Carraig Observatory, Loughinisland
+J17 357.203130.609723+0.790018Ragdon
+J18 356.906000.609920+0.789845Churchstoke
+J19 359.830360.764671+0.642359El Maestrat
+J20 356.219260.762019+0.645541Aravaca
+J21 356.080030.759065+0.649062El Boalo
+J22 342.132350.878415+0.476543Tacande Observatory, La Palma
+J23 358.493610.671765+0.738300Centre Astronomique de La Couyere
+J24 343.557190.881661+0.470499Observatorio Altamira
+J25 354.488830.728241+0.683076Penamayor Observatory, Nava
+J26 356.981190.612507+0.787898The Spaceguard Centre, Knighton
+J27 355.968990.760373+0.647528El Guijo Observatory
+J28 356.213810.791408+0.609366Jaen
+J29 346.342130.875695+0.481318Observatorio Nira, Tias
+J30 356.293000.761925+0.645666Observatorio Ventilla, Madrid
+J31 355.774110.802445+0.594759La Axarquia
+J32 352.977690.796769+0.602268Aljaraque
+J33 359.906000.620040+0.781953University of Hertfordshire Obs., Bayfordbury
+J34 355.227110.748695+0.660858La Fecha
+J35 356.029110.792167+0.608432Tucci Observatory, Martos
+J36 356.945310.765252+0.641721Observatorio El Olivo, Illana
+J37 353.064690.796893+0.602104Huelva
+J38 353.608900.726876+0.684507Observatorio La Vara, Valdes
+J39 344.5636 0.88429 +0.46547 Ingenio
+J40 355.558470.802546+0.594601Malaga
+J41 353.8189 0.59779 +0.79897 Raheny
+J42 359.6989 0.77138 +0.63425 Puzol
+J43 352.1189 0.85642 +0.51538 Oukaimeden Observatory
+J44 357.6552 0.73506 +0.67596 Observatorio Iturrieta, Alava
+J45 344.6779 0.88370 +0.46678 Observatorio Montana Cabreja, Vega de San Mateo
+J46 346.3594 0.87569 +0.48131 Observatorio Montana Blanca, Tias
+J47 346.4440 0.87501 +0.48260 Observatorio Nazaret
+J48 343.6960 0.87977 +0.47393 Observatory Mackay, La Laguna
+J49 359.4482 0.78695 +0.61496 Santa Pola
+J50 342.1176 0.87764 +0.47847 La Palma-NEON
+J51 343.728980.879789+0.473809Observatorio Atlante, Tenerife
+J52 358.6608 0.74198 +0.66826 Observatorio Pinsoro
+J53 354.892780.791142+0.609607Posadas
+J54 343.4906 0.88149 +0.47142 Bradford Robotic Telescope
+J55 344.3144 0.88549 +0.46313 Los Altos de Arguineguin Observatory
+J56 344.4536 0.88416 +0.46624 Observatorio La Avejerilla
+J57 358.890890.767817+0.638833Centro Astronomico Alto Turia, Valencia
+J58 356.6644 0.62304 +0.77959 Brynllefrith Observatory, Llantwit Fardre
+J59 356.202560.726956+0.684386Observatorio Linceo, Santander
+J60 354.3406 0.74773 +0.66201 Tocororo Observatory, Arquillinos
+J61 353.4264 0.59719 +0.79942 Brownstown Observatory, Kilcloon
+J62 351.6345 0.59017 +0.80459 Kingsland Observatory, Boyle
+J63 359.4831 0.78548 +0.61683 San Gabriel
+J64 359.3459 0.78871 +0.61271 La Mata
+J65 353.4497 0.59830 +0.79860 Celbridge
+J66 357.7833 0.61071 +0.78922 Kinver
+J67 359.4667 0.77114 +0.63457 Observatorio La Puebla de Vallbona
+J68 357.7055 0.61813 +0.78345 Tweenhills Observatory, Hartpury
+J69 358.9803 0.63144 +0.77286 North Observatory, Clanfield
+J70 358.8404 0.78968 +0.61149 Obs. Astronomico Vega del Thader, El Palmar
+J71 357.8947 0.59350 +0.80217 Willow Bank Observatory
+J72 358.9664 0.79065 +0.61028 Valle del Sol
+J73 359.0833 0.6187  +0.7830  Quainton
+J74 357.0961 0.72950 +0.68169 Bilbao
+J75 357.434710.789388+0.612222OAM Observatory, La Sagra
+J76 358.797180.790771+0.610163La Murta
+J77 357.5947 0.63154 +0.77276 Golden Hill Observatory, Stourton Caundle
+J78 358.8244 0.78887 +0.61253 Murcia
+J79 358.380660.795516+0.603908Observatorio Calarreona, Aguilas
+J80 359.1083 0.70862 +0.70323 Sainte Helene
+J81 358.1350 0.7360  +0.6749  Guirguillano
+J82 357.3067 0.5935  +0.8021  Leyland
+J83 357.3883 0.59274 +0.80270 Olive Farm Observatory, Hoghton
+J84 358.9803 0.63144 +0.77285 South Observatory, Clanfield
+J85 357.4833 0.5666  +0.8213  Makerstoun
+J86 356.6153 0.79930 +0.59968 Sierra Nevada Observatory
+J87 355.5067 0.76047 +0.64753 La Canada
+J88 358.5592 0.63165 +0.77266 Strawberry Field Obs., Southampton
+J89 356.2861 0.76045 +0.64739 Tres Cantos Observatory
+J90 358.5317 0.62251 +0.78000 West Challow
+J91 357.0483 0.7411  +0.6692  Alt emporda Observatory, Figueres
+J92 359.3487 0.62214 +0.78031 Beaconsfield
+J93 357.7426 0.61927 +0.78255 Mount Tuffley Observatory, Gloucester
+J94 357.7886 0.61909 +0.78270 Abbeydale
+J95 358.553000.624147+0.778709Great Shefford
+J96 356.056690.735326+0.675690Observatorio de Cantabria
+J97 359.5333 0.7754  +0.6293  Alginet
+J98 359.5344 0.77275 +0.63259 Observatorio Manises
+J99 359.578080.772589+0.632790Burjassot
Index: trunk/mops/oorb/data/TAI-UTC.dat
===================================================================
--- trunk/mops/oorb/data/TAI-UTC.dat	(revision 34646)
+++ trunk/mops/oorb/data/TAI-UTC.dat	(revision 34646)
@@ -0,0 +1,34 @@
+Differences TAI-UTC from IERS Bulletin C
+The leap second is introduced at the beginning
+of the day reported
+The last value of the file is not used;
+the corresponding date defines the limit
+of validity of the file
+Day, month, year, TAI-UTC (s)
+---------------------------------------------------
+ 1  1  1972    10
+ 1  7  1972    11
+ 1  1  1973    12
+ 1  1  1974    13
+ 1  1  1975    14
+ 1  1  1976    15
+ 1  1  1977    16
+ 1  1  1978    17
+ 1  1  1979    18
+ 1  1  1980    19
+ 1  7  1981    20
+ 1  7  1982    21
+ 1  7  1983    22
+ 1  7  1985    23
+ 1  1  1988    24
+ 1  1  1990    25
+ 1  1  1991    26
+ 1  7  1992    27
+ 1  7  1993    28 
+ 1  7  1994    29
+ 1  1  1996    30
+ 1  7  1997    31
+ 1  1  1999    32
+ 1  1  2006    33
+ 1  1  2009    34
+ 1  7  2130  9999
Index: trunk/mops/oorb/data/updateOBSCODE
===================================================================
--- trunk/mops/oorb/data/updateOBSCODE	(revision 34646)
+++ trunk/mops/oorb/data/updateOBSCODE	(revision 34646)
@@ -0,0 +1,37 @@
+#!/bin/bash
+#
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# This is a small utility script that downloads the most recent table
+# of observatory coordinates from the Minor Planet Center and
+# re-formats them for OpenOrb.
+#
+# Author: MG
+# Date:   2009-07-27
+
+wget http://www.cfa.harvard.edu/iau/lists/ObsCodes.html 
+sed -e '2d' ObsCodes.html | grep -v "<" > OBSCODE.dat
+rm -f ObsCodes.html
+
+
Index: trunk/mops/oorb/doc/Makefile
===================================================================
--- trunk/mops/oorb/doc/Makefile	(revision 34646)
+++ trunk/mops/oorb/doc/Makefile	(revision 34646)
@@ -0,0 +1,77 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Produces documentation for the OpenOrb project.
+#
+# Author:  MG
+# Version: 2009-07-25
+
+include ../make.config
+
+FILE = OpenOrb_Tutorial
+PSFILE = $(FILE).ps
+PDFFILE = $(FILE).pdf
+DVIFILE = $(FILE).dvi
+BIBTEX = bibtex
+LATEX = latex
+PS2PDF= ps2pdf
+DVIPS = dvips
+GV = ggv -scale 0
+XDVI = xdvi
+
+#----------------------
+
+.SUFFIXES: $(SUFFIXES) .tex .dvi .ps
+
+.tex.dvi:
+	$(LATEX) $<
+	$(LATEX) $<
+	$(BIBTEX) $(FILE)
+	$(BIBTEX) $(FILE)
+	$(LATEX) $<
+	$(LATEX) $<
+
+.dvi.ps:
+	$(DVIPS) -o $(PSFILE) $<
+
+all: $(PSFILE)
+
+dvi: $(DVIFILE)
+	$(XDVI) $(DVIFILE)
+
+pdf: $(DVIFILE)
+	$(DVIPS) -Ppdf -j0 -G0 -o prepdf_$(PSFILE) $<
+	$(PS2PDF) -sPAPERSIZE=a4 -dMaxSubsetPct=100 \
+	-dCompatibilityLevel=1.2 -dSubsetFonts=true \
+	-dEmbedAllFonts=true -sOutputFile=$(PDFFILE) \
+	prepdf_$(PSFILE)
+	rm -f prepdf_$(PSFILE)
+
+clean:
+	rm -f $(PSFILE) prepdf_$(PSFILE) \
+	*.dvi *.log *.aux *~ core *.bbl *.blg *.out \
+	*.toc
+
+$(PSFILE): $(DVIFILE)
+$(PDFFILE): $(DVIFILE)
+$(DVIFILE): $(TEXFILES)
Index: trunk/mops/oorb/doc/OpenOrb_Tutorial.tex
===================================================================
--- trunk/mops/oorb/doc/OpenOrb_Tutorial.tex	(revision 34646)
+++ trunk/mops/oorb/doc/OpenOrb_Tutorial.tex	(revision 34646)
@@ -0,0 +1,629 @@
+%====================================================================%
+%                                                                    %
+% Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  %
+% Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      %
+% Dagmara Oszkiewicz                                                 %
+%                                                                    %
+% This file is part of OpenOrb.                                      %
+%                                                                    %
+% OpenOrb 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.                                %
+%                                                                    %
+% OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    %
+%                                                                    %
+%====================================================================%
+\documentclass[12pt,english,twoside,a4paper]{report}
+\usepackage{babel}
+\usepackage{t1enc}
+\usepackage[T1]{fontenc}
+\usepackage[latin1]{inputenc}
+\usepackage{epsfig}
+\usepackage{amsmath}
+\usepackage{amssymb}
+\usepackage{graphics}
+\usepackage{graphicx}
+\usepackage{lscape}
+\usepackage{rotating}
+\usepackage{verbatim}
+\usepackage{latexsym}
+\usepackage{ae}
+\usepackage{aecompl}
+\usepackage{acronym}
+\usepackage{harvard}
+\usepackage{ae}    
+\usepackage{aecompl}  
+\usepackage{url}
+
+\pagestyle{plain} 
+\renewcommand{\baselinestretch}{1}
+\renewcommand{\deg}{^\circ}
+\newcommand{\arcmin}{^{\prime}}
+\newcommand{\arcsec}{^{\prime\prime}}
+\newcommand{\h}{^\mathrm{h}}
+\newcommand{\m}{^\mathrm{m}}
+\newcommand{\s}{^\mathrm{s}}
+\newcommand{\Mpc}{\,\mathrm{Mpc}}
+\newcommand{\kpc}{\,\mathrm{kpc}}
+\newcommand{\pc}{\,\mathrm{pc}}
+\newcommand{\AU}{\,\mathrm{AU}}
+\newcommand{\km}{\,\mathrm{km}}
+\newcommand{\meter}{\,\mathrm{m}}
+\newcommand{\cm}{\,\mathrm{cm}}
+\newcommand{\mm}{\,\mathrm{mm}}
+\newcommand{\um}{\,\mu \mathrm{m}}
+\newcommand{\nm}{\,\mathrm{nm}}
+\newcommand{\rad}{\,\mathrm{rad}}
+\newcommand{\anno}{\,\mathrm{a}}
+\newcommand{\days}{\,\mathrm{d}}
+\newcommand{\vrk}{\,\mathrm{vrk}}
+\newcommand{\hours}{\,\mathrm{hours}}
+\newcommand{\hour}{\,\mathrm{h}}
+\newcommand{\minute}{\,\mathrm{min}}
+\newcommand{\second}{\,\mathrm{s}}
+\newcommand{\magnitude}{^\mathrm{m}}
+\newcommand{\K}{\,\mathrm{K}}
+\newcommand{\TJ}{\,\mathrm{TJ}}
+\newcommand{\J}{\,\mathrm{J}}
+\newcommand{\N}{\,\mathrm{N}}
+\newcommand{\kg}{\,\mathrm{kg}}
+\newcommand{\g}{\,\mathrm{g}}
+\newcommand{\AMU}{\,\mathrm{AMU}}
+\newcommand{\W}{\,\mathrm{W}}
+\newcommand{\MW}{\,\mathrm{MW}}
+%\newcommand{\elements}{\mathbf{P}}
+\newcommand{\ud}{\mathrm{d}}
+%\renewcommand{\r}{\mathbf{r}}
+%\renewcommand{\v}{\mathbf{v}}
+\newcommand{\f}{\mathnormal{f}}
+\renewcommand{\g}{\mathnormal{g}}
+\title{OpenOrb Tutorial v.0.2}
+\author{Mikael Granvik (mgranvik@iki.fi) \\ Jenni Virtanen (jenni.virtanen@fgi.fi)}
+\date{\today}
+\usepackage{hyperref} 
+\begin{document}
+\maketitle
+\citationstyle{agsm}
+\citationmode{abbr}
+
+\pagenumbering{roman}
+\setcounter{page}{1}
+%\pagestyle{fancy}
+
+\begin{verbatim}
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+\end{verbatim}
+
+\pagebreak
+
+\tableofcontents
+
+\pagebreak
+\pagenumbering{arabic}
+\setcounter{page}{1}
+
+\chapter{Short introduction to OpenOrb}
+
+\section{Theory}
+
+In the Bayesian framework, the parameters to be estimated are treated
+as random variables and the complete solution to the inverse problem
+is contained in the parameters' posterior probability densities. The
+posterior distribution $p_\mathrm{p}$ is proportional to the a priori
+($p_\mathrm{pr}$) and the observational error ($p_\mathrm{\epsilon}$)
+PDFs:
+\begin{equation}
+p_\mathrm{p}(\mathbf{P}) \propto p_\mathrm{pr}(\mathbf{P}) p_\mathrm{\epsilon}(\Delta
+\psi (\mathbf{P}))
+\end{equation}
+where $\mathbf{P}$ refers to the orbital elements and $\Delta \psi
+(\mathbf{P})$ stands for the observed minus computed ($O-C$) residuals
+\cite{mui1993a,vir2005c}. The a priori often used is Jeffreys' a
+priori which secures the invariance of the results. For example, the
+collision probability does not depend on the type of orbital elements
+used in the analysis \cite{vir2006a}.
+
+If you want to transform the computed orbital-element PDF to
+another set of variables such as other types of orbital elements or
+ephemerides, you must also transform (that is, propagate) the weights
+to the new variables \cite{mui1993a}:
+\begin{equation}
+p(\mathbf{F}) = \int dP p(\mathbf{P})\delta_\mathrm{D}
+(\mathbf{F}-\mathbf{F}(\mathbf{P})) = \frac{1}{\det(\frac{\delta
+    \mathbf{F}}{\delta \mathbf{P}})_\mathbf{F}}
+p(\mathbf{P}(\mathbf{F})),
+\end{equation}
+where
+$\mathbf{F}(\mathbf{P})=(F_1(\mathbf{P}),\ldots,F_k(\mathbf{P}))^T$ is
+a set of functions of the orbital elements, $\delta_\mathrm{D}$ is
+Dirac's function, and $\det(\frac{\delta \mathbf{F}}{\delta
+  \mathbf{P}})_F$ is the determinant of the Jacobian matrix for the
+transformation $\mathbf{P} \rightarrow \mathbf{F}$. The propagation of
+the weights is done automatically for the PDFs produced by the
+``official'' OpenOrb executable, \verb|oorb|.
+
+
+
+\section{Numerical Methods} 
+
+\subsection{Orbital inversion}
+
+\subsubsection{Ranging}
+
+Ranging maps the non-Gaussian orbital-element PDF with a given
+number of sample orbits \cite{vir2001a,mui2001a}. Each sample orbit is
+computed using the following scheme: Two observations are chosen from
+the data set and a random deviate is added to all four coordinates to
+mimic observational noise. Next, a random topocentric distance is
+generated for the first observation date using a, typically, broad
+interval. The topocentric distance for the second observation date is
+generated from an interval relative to the topocentric distance on the
+first observation date. Since the location of the observatory with
+respect to the Sun is usually known, the four plane-of-sky coordinates
+and the two topocentric distances can be transformed into two
+heliocentric positions corresponding to the two observation
+dates. Using well-established methods in celestial mechanics, an orbit
+can be computed using the two heliocentric positions. The generated
+sample orbit is then used to compute ephemerides for the other
+observation dates. If the residuals are acceptable and the
+PDF value is good enough with respect to the until-then best-fit
+orbit, the sample orbit is accepted. The inversion can be sped up by
+iteratively adjusting the intervals for the topocentric distance
+either by performing the simulation for a smaller number of sample
+orbits before performing the full-scale inversion \cite{vir2003a} or
+by starting with only two observations and adding more observations
+step by step \cite{gra2005c}.
+
+\subsubsection{Least-squares with linearized covariances}
+
+Least-squares with linearized covariances (LSL)\ldots
+
+\subsection{Integration}
+
+- Bulirsch-Stoer extrapolation method
+
+- $n$-body dynamical model contains 8 planets + Moon + Pluto
+
+- leading relativistic term by the Sun (perihelion shift)
+
+\chapter{Installing OpenOrb}
+
+\section{Software requirements}
+
+In addition to basic Unix tools such as \verb|tar| and \verb|make|,
+using OpenOrb only requires a Fortran 90/95 compiler---we are mostly
+using the free \verb|gfortran| compiler (http://gcc.gnu.org/)---and
+\verb|gnuplot| (http://www.gnuplot.info) for automatic generation of
+plots.
+
+\section{Producing the executable}
+
+Extracting the source code archive will produce a directory called
+\verb|OpenOrb|: \\ \\
+\verb|tar xvzf OpenOrb-vN.N.tar.gz|\\ \\
+Change directory to the \verb|OpenOrb| directory:\\ \\
+\verb|cd OpenOrb|\\ \\
+Run configuration script to set up the chosen compiler and its
+command-line switches:\\ \\
+\verb+./configure [COMPILER] [opt | deb]+\\ \\
+Here \verb|COMPILER| can be one of the following: gfortran, g95,
+lahey, intel, sun, compaq, or absoft. The option \verb|opt| will
+produce optimized code for production use, whereas \verb|deb| will
+produce code suitable for debugging. The compiler commands and
+switches are explicitly given in (and should be modified through) the
+\verb|make.config| file. Next change to the \verb|main| directory and
+produce the \verb|oorb| executable: \\ \\
+\verb|cd main| \\
+\verb|make oorb| \\ \\
+Assuming everything compiled without problems\footnote{The only known
+  (compatibility) issue can be found at the end of
+  \mbox{modules/cl\_options.f90} and requires commenting certain lines
+  in/out. If you are using the latest gfortran compiler, everything
+  should compile without errors.} the \verb|oorb| executable is now in
+the \verb|main| directory.
+
+To allow a flexible usage of the executable, you may want to make the
+following changes or additions to your shell's configuration file: \\ \\ 
+\verb|export PATH=$PATH:/path/to/oorb| \\ \\
+If you have access to \verb|gnuplot| and want to make automatic plots
+of the orbital-element PDFs, you should define the
+\verb|$OORB_GNUPLOT_SCRIPTS_DIR| environment variable: \\ \\ 
+\verb|export OORB_GNUPLOT_SCRIPTS_DIR=/path/to/OpenOrb/gnuplot/|
+
+
+\section{Getting and processing required data files}
+
+Access to the following data files is required to run \verb|oorb|: 
+\begin{itemize}
+  \item OBSCODE.dat \href{http://www.cfa.harvard.edu/iau/lists/ObsCodes.html}{http://www.cfa.harvard.edu/iau/lists/ObsCodes.html}
+  \item TAI-UTC.dat \href{http://hpiers.obspm.fr/eop-pc/}{http://hpiers.obspm.fr/eop-pc/}
+  \item ET-UT.dat \href{}{}
+  \item de405.dat
+\end{itemize}
+The most recent versions of the three first files are incorporated in
+the OpenOrb package. OBSCODE.dat is updated every night by the Minor
+Planet Center. However, if you do not use observations from
+observatories that have recently acquired an observatory code, there
+is no need to update this file more often than, say, once every year
+or so. Note that the format of the OBSCODE.dat is identical to the
+HTML page with the exception that all HTML tags and the header line
+have been deleted. TAI-UTC.dat and ET-UT.dat have to be updated
+manually. A suitable interval to check the availability of updates is
+every six months or so.
+
+To generate the JPL planetary ephemeris file \verb|de405.dat|, go to
+the \\ \verb|OpenOrb/data/JPL_ephemeris/| directory \\ \\ 
+\verb|cd ../data/JPL_ephemeris/| \\ \\ 
+and issue the following \verb|make| command: \\ \\ 
+\verb|make de405| \\ \\
+If successful, the ASCII versions of the de405 ephemerides will first
+be automatically downloaded from the JPL FTP server, and then built to
+the binary file \verb|de405.dat|. Finally, \verb|de405.dat| is copied
+to the \verb|data| directory and the intermediate files are
+deleted. Note that you do not have to rebuild the \verb|de405.dat|
+file every time you get a new version of OpenOrb. However, since
+\verb|de405.dat| is a binary file, it may have to be built separately
+for every operating system. The correctness of the generated ephemeris
+file can be checked with \\ \\
+\verb|make de405_test| \\ \\
+Finally, the \verb|OORB_DATA| environment variable, which contains the
+path to the data directory (usually \verb|OpenOrb/data/|), should be
+added to the environment: \\ \\
+\verb|export OORB_DATA=/path/to/data/directory/| \\ \\
+Again, consider adding the \verb|OORB_DATA| variable to your shell's
+configuration file. 
+
+
+\section{Configuration file}
+
+The explanations and possible values for the configuration parameters
+are given in Table \ref{table:conf}. The path to the configuration
+file \verb|FILE| (path to default file is
+\verb|OpenOrb/main/oorb.conf|) can either be given using the command
+line option \verb|--conf=FILE| or using an environment variable:
+\\ \\ \verb|export OORB_CONF=/path/to/configuration/FILE| \\ \\ If
+neither of these are used, it is assumed that the configuration file
+is called \verb|oorb.conf| and resides in the working directory. Note
+that specifying the path as a command-line parameter
+(\verb|--conf=FILE|) overrides the environment variable
+(\verb|$OORB_CONF|) which in turn overrides the default path
+(\verb|./oorb.conf|).
+
+\begin{table}\label{table:conf}
+\centering
+\begin{tabular}{cc}
+\hline
+Option & Explanation \\
+\hline
+MANY OPTIONS & NOT MUCH TIME \\
+\hline
+\end{tabular}
+\caption{See configuration file. The options should be self-explanatory\ldots}  
+\end{table}
+
+
+
+\section{Sample configuration file}
+
+If you are using Bash, it makes life quite a bit easier if the
+\verb|.bashrc| file contains the following entries:
+\begin{verbatim}
+export PATH=$PATH:/path/to/oorb
+export OORB_CONF=/path/to/oorb/configuration/file
+export OORB_DATA=/path/to/data/directory/
+export OORB_GNUPLOT_SCRIPTS_DIR=/path/to/OpenOrb/gnuplot/
+\end{verbatim}
+
+
+
+\chapter{Using OpenOrb}
+
+The basic options (input, output, etc.) are given as command-line
+parameters when running \verb|oorb|, but more detailed configuration
+parameters are defined using a configuration file.
+
+\section{File formats}
+
+\subsection{Observations}
+
+\begin{itemize}
+
+\item Current MPC format (.mpc).
+\item New MPC format (.mpc3).
+
+\end{itemize}
+
+In the future, OpenOrb will be able to use the format which Pan-STARRS
+will be using.
+
+\subsection{Orbits}
+
+Current OpenOrb format (.orb).
+
+\subsection{Ephemeris}
+
+Current OpenOrb format (.eph).
+
+
+
+\section{Computing orbital-elements based on observed positions}
+
+The \verb|oorb| executable currently has to ways of obtaining the
+orbital-element PDF based on the observed positions, Ranging
+(\verb|--task=ranging|) and LSL (\verb|--task=lsl|). Whereas Ranging
+maps the PDF rigorously, that is, without prior
+assumptions of its shape, LSL assumes that the PDF is Gaussian and
+derives a so-called single-point estimate for the orbital-element
+PDF. In practice, the single-point estimate consists of the nominal
+orbit and the corresponding hyperellipsoid which describes the
+uncertainty of the orbit. In general, Ranging is optimized for
+situations with scarce data. LSL, on the other hand, should only be
+used when there is enough data available to assume that the {\it true}
+shape of the orbital-element PDF is indeed more or less
+Gaussian. The orbital inversion is performed by using either one of
+the followong commands: \\ \\
+\verb|oorb --task=ranging --obs-in=FILE.mpc [ --orb-out=OUTFILE ]| \\
+\verb|   [ --orb-out-separately ]| \\ \\ 
+\verb|oorb --task=lsl --obs-in=FILE.mpc --orb-in=INFILE|\\
+\verb|   [ --orb-out=OUTFILE ] [ --orb-out-separately ]| \\ \\ 
+Here \verb|FILE.mpc| contains the observed positions in the Minor
+Planet Center (MPC) format, and the file may contain more than one
+object in which case the number or temporary designation separates
+different sets. The observational uncertainty is specified in the
+configuration file. Currently, OpenOrb also allows observations to be
+fed using the ``New MPC Format'' the fate of which is still
+uncertain. In the New MPC Format (OpenOrb recognizes it by the suffix
+\verb|.mpc3|) observations are, among other things, allowed to have
+individual uncertainties. For LSL, \verb|oorb| needs at least one
+starting point which is supplied using INFILE. If
+\verb|--orb-out=OUTFILE| is omitted, the resulting orbital-element
+PDF is written to standard out. With the
+\verb|--orb-out-separately| option the orbit or orbits for each
+separate observation set is written to separate file the name of which
+is defined by the designation or number of the observation set.
+
+\subsection{Tips for using Ranging}
+
+\begin{itemize}
+
+\item Make a reasonable assumption for the observational uncertainty
+  $\sigma_\mathrm{obs}$, e.g., the observatory's historical RMS for
+  $O-C$ residuals.
+
+\item If using relative weights for sample orbits (non-uniform
+  sampling), make sure the acceptance window ($[-c_\mathrm{acc} \times
+    \sigma_\mathrm{obs},+c_\mathrm{acc} \times \sigma_\mathrm{obs}]$,
+  where $c_\mathrm{acc}$ is the acceptance-window multiplier) is large
+  enough to allow sampling without cut-offs due to residuals. In
+  practice, make sure the residual stamps figure do not show cut-offs.
+
+\item The generation window ($[-c_\mathrm{gen} \times
+  \sigma_\mathrm{obs},+c_\mathrm{gen} \times \sigma_\mathrm{obs}]$,
+  where $c_\mathrm{gen}$ is the generation-window multiplier) should
+  not be larger than the acceptance window. Typically, they have the
+  same size, that is, $c_\mathrm{acc}=c_\mathrm{gen}$.
+
+\item Use a number of sample orbits which is enough to do statistics,
+  but is still not overkill considering running time. Typically,
+  2,000--10,000 sample orbits is enough.
+
+\item As rule of thumb, use the two-body approximation for
+  Ranging. The $n$-body corrections are usually only required for
+  special cases such as collision-probability estimation.
+
+\end{itemize}
+
+\section{Propagation of orbital elements from one epoch to another}
+
+The orbital-element PDF can be propagated to another epoch using
+the command \\ \\
+\verb|oorb --task=propagation --epoch-mjd-tt=MJD --orb-in=INFILE| \\
+\verb|   [ --orb-out=OUTFILE ]| \\ \\
+The mode of propagation, that is, analytical two-body propagation or
+numerical $n$-body propagation using an integrator, can be defined in
+the configuration file. If \verb|--orb-out=OUTFILE| is omitted, the
+resulting orbital-element PDF is written to standard out.
+
+\section{Computing ephemerides}
+
+Topocentric ephemerides and their uncertainties are computed based on
+the orbital-element PDF using the command \\ \\
+\verb+oorb --task=ephemeris --obs-code=CODE [ --epoch-mjd-utc=MJD |+\\
+\verb+     --epoch-mjd-tt=MJD | --timespan=DT1 --step=DT2 ]+\\
+\verb+     --orb-in=INFILE+\\ \\
+where \verb|CODE| is the observatory code assigned by MPC and MJD is
+the Modified Julian Date of the desired ephemerides either in UTC or
+TT. DT1 is the timespan (in days) over which ephemerides should be
+computed when starting from the epoch of the orbital-elements and DT2
+is the frequency (in days) of the ephemerides. Positive values for DT1
+and DT2 indicate going forwards in time from the epoch, whereas
+negative values indicate going backwards. The ephemeris prediction
+based on the sampled PDF is a discrete set of predicted positions
+on the sky and their individual weights, and the ephemeris prediction
+based on the single-point estimate is the nominal position with a
+3-$\sigma$ uncertainty ellipse. Note that the non-Gaussian uncertainty
+region equivalent to the Gaussian 3-$\sigma$ region can also be
+obtained for the sampled prediction by normalizing the sum of the
+weights to unity and requiring that 99.73002\% of the total weight
+(probability mass) is within the boundaries. The ephemerides are
+written to standard out.
+
+\section{Dynamical classification}
+
+%Dynamical classification without the use of a priori knowledge is
+%currently included in the \verb|*.sor| file. The file is produced for
+%every observation set which is run through Ranging.
+For cases where the orbital-element PDF has been sampled, it is
+possible to classify the object in a dynamical sense by using the
+relative weight of sample orbits. The classification
+\\ \\ \verb|oorb --task=classification --orb-in=INFILE| \\ \\ The
+results are written to standard output.  The classification criteria
+can be changed by modifying the \verb|getGroupProbabilities|
+subroutine in \\ \verb|StochastiOrbit_class.f90|. Note that the
+current implementation of the dynamical classification is only done in
+the osculating $(a,e,i,q,Q)$ space, which means that, e.g., the
+classification of Jupiter Trojans is not carried out rigorously.
+
+\section{Conversion between file types}
+
+Use \\ \\
+\verb|oorb --task=mpctompc3 --obs-in=FILE1 [ --obs-out=FILE2]| \\ \\
+to convert an observation file (FILE1) formatted according to the
+current MPC format to a file (FILE2) formatted according to the
+proposed new MPC format. Observational uncertainties are taken from
+the configuration file. If they are not defined, the default
+uncertainty is zero. Use \\ \\
+\verb|oorb --task=mpc3tompc --obs-in=FILE1 [ --obs-out=FILE2]| \\ \\
+to convert an observation file (FILE1) formatted according to the
+proposed new MPC format to a file (FILE2) formatted according to the
+current MPC format. Note that information regarding observational
+uncertainties is lost during the conversion. Use \\ \\
+\verb|oorb --task=astorbtoorb --astorb=FILE1 [ --orb-out=FILE2]| \\ \\
+to convert the orbital elements and the (H,G) values in Ted Bowell's
+astorb.dat file to the .orb format. Here FILE1 is the astorb.dat file
+and FILE2 is the output .orb file. Again, if FILE2 is omitted the
+output is sent to standard out.
+
+\section{Example}
+
+In the \verb|OpenOrb/test/| directory you can find two almost
+identical observation files in the MPC format,
+\verb|K08K42V_ranging.mpc| and \verb|K08K42V_lsl.mpc|. The difference
+between these files is that in the previous file all but the three
+first observations have been commented out, whereas in the latter none
+are commented out.
+
+First, compute a Ranging solution for observation set \#1:
+\\ \\ 
+\verb|oorb --task=ranging --obs-in=K08K42V_ranging.mpc \| \\
+\verb|     --orb-out=K08K42V_ranging.orb|
+\\ \\
+The output is written both in the form of an orbital-element
+PDF file called \verb|K08K42V_ranging.orb| and a more general
+output file called \\ \verb|K08K42V_ranging.sor|. Moreover, two separate
+plots were also produced:
+\verb|K08K0042V_0.08_sor_keplerian_results.eps.gz| shows the
+orbital-element PDF and
+\verb|K08K0042V_0.08_sor_residual_stamps.eps.gz| shows stamps of the
+$O-C$ residual distributions corresponding to each observation
+included in the inversion.
+
+Then, use the orbits produced by Ranging to initiate the differential
+correction (LSL) using observation set \#2: \\ \\ 
+\verb|oorb --task=lsl --obs-in=K08K42V_lsl.mpc \| \\
+\verb|     --orb-in=K08K42V_ranging.orb --orb-out=K08K42V_lsl.orb| \\ \\ 
+Again, the output is written in the form of an orbital-element file
+called \verb|K08K42V_lsl.orb| which contains the nominal orbit and the
+standard deviations and correlations for the elements, and a general
+output file called \verb|K08K42V_lsl.ls|. The nominal orbit and the
+1-$\sigma$ and the 3-$\sigma$ uncertainty ellipsoids are shown in plot
+\verb|K08K0042V_37.80_ls_keplerian_results.eps.gz|.
+
+To make a dynamical classification of the object, do \\ \\
+\verb|oorb --task=classification --orb-in=K08K42V_ranging.orb| \\ \\
+The result strongly suggests that the object is something unknown to
+the current classification scheme and, in fact, the object is the
+first retrograde TNO discovered.
+
+To propagate the orbital-element PDF to the current date
+(2008-08-12) epoch, do \\ \\ 
+\verb|oorb --task=propagation --orb-in=K08K42V_ranging.orb \| \\ 
+\verb|     --epoch-mjd-tt=54690 --orb-out=K08K42V_ranging_54690.orb| \\ \\ 
+The file \verb|K08K42V_ranging_54690.orb| contains the orbital-element
+PDF at the new epoch.
+
+To compute follow-up ephemerides (topocentric distance, R.A., Dec.,
+and their corresponding time derivatives) for 10 dates with one-day
+intervals starting at 2008-08-12.0 TT, use \\ \\
+\verb|oorb --task=ephemeris --orb-in=K08K42V_ranging_54690.orb \| \\ 
+\verb|     --timespan=10.0 --step=1.0| \\ \\ 
+The ephemerides are written to standard out.
+
+\chapter{Developing your own applications based on OpenOrb}
+
+It is reasonably straightforward to develop your own applications in
+the OpenOrb framework due to the object-oriented approach. Although
+Fortran 90/95 is not a pure object-oriented language, we have mimicked
+object-oriented concepts in the software by using the guidelines by
+\citeasnoun{dec1997a}.
+
+More to be added later if there is interest\ldots
+
+
+\chapter{Communication}
+
+\section{Getting help}
+
+Due to manpower limitations, we cannot promise to give personal
+assistance in all situations. It is assumed that the user is familiar
+with state-of-the-art orbit computation methods and Bayesian inversion
+theory through published literature
+\citeaffixed{vir2005c,bow2003a,vir2008a}{for reviews, see}. However,
+if you intend to publish results obtained with OpenOrb and have doubt
+regarding the interpretation of the results, we encourage you to
+contact either Mikael Granvik (mgranvik@iki.fi) or Jenni Virtanen
+(jenni.virtanen@fgi.fi) for assistance.
+
+If needed, there may be help available for developing source code
+based on OpenOrb to solve more complicated orbit-computation-related
+problems. However, the help has a price, which is typically to be paid
+in the currency which our funding agencies understand and accept, that
+is, as a co-authorship in the resulting publication(s).
+
+\section{Reporting bugs}
+
+OpenOrb has been tested during the years by comparing the results to
+the results obtained with either our older software or by software by
+colleagues. If you nevertheless find a bug, please report it to us so
+that we can fix the problem. The report should be concise and contain
+everything needed for reproducing the erroneous result. Send the
+report to MG (mgranvik@iki.fi) with the text ``OpenOrb bug'' in the
+subject line.
+
+\section{Acknowledging the use of OpenOrb}
+
+If you find OpenOrb useful in your work, please acknowledge our
+efforts by citing, in addition to the relevant original papers, the
+following abstract (which will hopefully evolve into an ACM 2008
+conference proceedings ma\-nu\-script) on the OpenOrb software package: \\ \\ 
+
+\noindent Granvik, M., Virtanen, J., and Muinonen, K. (2008),
+`OpenOrb: Open-source asteroid-orbit-computation software including
+statistical orbital ranging', Asteroids, Comets, Meteors 2008,
+Abstract \#8206, CD-ROM, LPI Contribution No.\ 1405.
+
+
+
+\bibliographystyle{agsm}
+\bibliography{asteroid,educational,fortran}
+%\nocite{mui1999a}
+
+\end{document}
Index: trunk/mops/oorb/doc/README
===================================================================
--- trunk/mops/oorb/doc/README	(revision 34646)
+++ trunk/mops/oorb/doc/README	(revision 34646)
@@ -0,0 +1,8 @@
+To produce a PS version of the OpenOrb tutorial, type
+
+    make
+
+To produce a PDF version, type
+
+    make pdf
+
Index: trunk/mops/oorb/doc/agsm.bst
===================================================================
--- trunk/mops/oorb/doc/agsm.bst	(revision 34646)
+++ trunk/mops/oorb/doc/agsm.bst	(revision 34646)
@@ -0,0 +1,1336 @@
+% BibTeX standard bibliography style `agsm' (one of the harvard family)
+	% version 0.99a for BibTeX versions 0.99a or later, LaTeX version 2.09.
+	% Copyright (C) 1991, all rights reserved.
+	% Copying of this file is authorized only if either
+	% (1) you make absolutely no changes to your copy, including name, or
+	% (2) if you do make changes, you name it something other than
+	% btxbst.doc, plain.bst, unsrt.bst, alpha.bst, abbrv.bst, agsm.bst,
+        % dcu.bst or kluwer.bst.
+	% This restriction helps ensure that all standard styles are identical.
+	% The file harvard.tex has the documentation for this style.
+
+% ACKNOWLEDGEMENT:
+%   This document is a modified version of alpha.bst to which it owes much of
+%   its functionality.
+
+% AUTHOR
+%   Peter Williams, Key Centre for Design Quality, Sydney University
+%   e-mail: peterw@archsci.arch.su.oz.au
+
+ENTRY
+  { address
+    author
+    booktitle
+    chapter
+    edition
+    editor
+    howpublished
+    institution
+    journal
+    key
+    month
+    note
+    number
+    organization
+    pages
+    publisher
+    school
+    series
+    title
+    type
+    volume
+    year
+  }
+  { field.used etal.allowed etal.required} %%%XXX change
+  { extra.label sort.label list.year }
+
+INTEGERS { output.state before.all mid.sentence after.sentence after.block }
+
+FUNCTION {init.state.consts}
+{ #0 'before.all :=
+  #1 'mid.sentence :=
+  #2 'after.sentence :=
+  #3 'after.block :=
+}
+
+STRINGS { s t f }
+
+FUNCTION {output.nonnull}
+{ 's :=
+  output.state mid.sentence =
+    { ", " * write$ }
+    { output.state after.block =
+	{ add.period$ write$
+	  newline$
+	  "\newblock " write$
+	}
+	{ output.state before.all =
+	    'write$
+	    { add.period$ " " * write$ }
+	  if$
+	}
+      if$
+      mid.sentence 'output.state :=
+    }
+  if$
+  s
+}
+
+FUNCTION {output}
+{ duplicate$ empty$
+    'pop$
+    'output.nonnull
+  if$
+}
+
+FUNCTION {output.check}
+{ 't :=
+  duplicate$ empty$
+    { pop$ "empty " t * " in " * cite$ * warning$ }
+    'output.nonnull
+  if$
+}
+
+FUNCTION {item.check}
+{ 't :=
+  empty$
+    { "empty " t * " in " * cite$ * warning$ }
+    { skip$ }
+  if$
+}
+
+FUNCTION {fin.entry}
+{ add.period$
+  write$
+  newline$
+}
+
+FUNCTION {new.block}
+{ output.state before.all =
+    'skip$
+    { after.block 'output.state := }
+  if$
+}
+
+FUNCTION {not}
+{   { #0 }
+    { #1 }
+  if$
+}
+
+FUNCTION {and}
+{   'skip$
+    { pop$ #0 }
+  if$
+}
+
+FUNCTION {or}
+{   { pop$ #1 }
+    'skip$
+  if$
+}
+
+FUNCTION {field.or.null}
+{ duplicate$ empty$
+    { pop$ "" }
+    'skip$
+  if$
+}
+
+FUNCTION {emphasize}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\em " swap$ * "}" * }
+  if$
+}
+
+FUNCTION {embolden}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "{\bf " swap$ * "}" * }
+  if$
+}
+
+FUNCTION {quote}
+{ duplicate$ empty$
+    { pop$ "" }
+    { "`" swap$ * "'" * }
+  if$
+}
+
+INTEGERS { nameptr namesleft numnames }
+
+FUNCTION {format.names}
+{ 's :=
+  'f :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr f format.name$ 't :=
+      nameptr #1 >
+	{ namesleft #1 >
+	    { ", " * t * }
+	    { t "others" =
+		{ " et~al." * }
+		{ " \harvardand\ " * t * }
+	      if$
+	    }
+	  if$
+	}
+	't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+FUNCTION {format.authors}
+{ author empty$
+    { "" }
+    { "{vv~}{ll}{, jj}{, f.}" author format.names }
+  if$
+}
+
+FUNCTION {format.editors}
+{ editor empty$
+    { "" }
+    { "{vv~}{ll}{, jj}{, f.}" editor format.names
+      editor num.names$ #1 >
+	{ ", eds" * }
+	{ ", ed." * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.editors.reverse}
+{ editor empty$
+    { "" }
+    { "{f.~}{vv~}{ll}{, jj}" editor format.names
+      editor num.names$ #1 >
+	{ ", eds" * }
+	{ ", ed." * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.title}
+{ title empty$
+    { "" }
+    { title "t" change.case$ }
+  if$
+}
+
+FUNCTION {n.dashify}
+{ 't :=
+  ""
+    { t empty$ not }
+    { t #1 #1 substring$ "-" =
+	{ t #1 #2 substring$ "--" = not
+	    { "--" *
+	      t #2 global.max$ substring$ 't :=
+	    }
+	    {   { t #1 #1 substring$ "-" = }
+		{ "-" *
+		  t #2 global.max$ substring$ 't :=
+		}
+	      while$
+	    }
+	  if$
+	}
+	{ t #1 #1 substring$ *
+	  t #2 global.max$ substring$ 't :=
+	}
+      if$
+    }
+  while$
+}
+
+FUNCTION {format.btitle}
+{ title emphasize
+}
+
+FUNCTION {tie.or.space.connect}
+{ duplicate$ text.length$ #3 <
+    { "~" }
+    { " " }
+  if$
+  swap$ * *
+}
+
+FUNCTION {either.or.check}
+{ empty$
+    'pop$
+    { "can't use both " swap$ * " fields in " * cite$ * warning$ }
+  if$
+}
+
+FUNCTION {format.bvolume}
+{ volume empty$
+    { "" }
+    { "Vol." volume tie.or.space.connect
+      series empty$
+	'skip$
+	{ " of " * series emphasize * }
+      if$
+      "volume and number" number either.or.check
+    }
+  if$
+}
+
+FUNCTION {format.number.series}
+{ volume empty$
+    { number empty$
+	{ series field.or.null }
+	{ output.state mid.sentence =
+	    { "number" }
+	    { "Number" }
+	  if$
+	  number tie.or.space.connect
+	  series empty$
+	    { "there's a number but no series in " cite$ * warning$ }
+	    { " {\em in} " * series quote * }
+	  if$
+	}
+      if$
+    }
+    { "" }
+  if$
+}
+
+FUNCTION {format.edition}
+{ edition empty$
+    { "" }
+    { output.state mid.sentence =
+	{ edition "l" change.case$ " edn" * }
+	{ edition "t" change.case$ " edn" * }
+      if$
+    }
+  if$
+}
+
+INTEGERS { multiresult }
+
+FUNCTION {multi.page.check}
+{ 't :=
+  #0 'multiresult :=
+    { multiresult not
+      t empty$ not
+      and
+    }
+    { t #1 #1 substring$
+      duplicate$ "-" =
+      swap$ duplicate$ "," =
+      swap$ "+" =
+      or or
+	{ #1 'multiresult := }
+	{ t #2 global.max$ substring$ 't := }
+      if$
+    }
+  while$
+  multiresult
+}
+
+FUNCTION {format.pages}
+{ pages empty$
+    { "" }
+    { pages multi.page.check
+	{ "pp.~" pages n.dashify * }
+	{ "p.~" pages * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.vol.num.pages}
+{ volume embolden field.or.null
+  number empty$
+    'skip$
+    { "(" number * ")" * *
+      volume empty$
+	{ "there's a number but no volume in " cite$ * warning$ }
+	'skip$
+      if$
+    }
+  if$
+  pages empty$
+    'skip$
+    { duplicate$ empty$
+	{ pop$ format.pages }
+	{ ",~" * pages n.dashify * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.chapter.pages}
+{ chapter empty$
+    'format.pages
+    { type empty$
+	{ "chapter" }
+	{ type "l" change.case$ }
+      if$
+      chapter tie.or.space.connect
+      pages empty$
+	'skip$
+	{ ", " * format.pages * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {format.in.ed.booktitle}
+{ booktitle empty$
+    { "" }
+    { editor empty$
+	{ "{\em in} " booktitle quote * }
+	{ "{\em in} " format.editors.reverse * ", " * booktitle quote * }
+      if$
+    }
+  if$
+}
+
+FUNCTION {empty.misc.check}
+{ author empty$ title empty$ howpublished empty$
+  month empty$ year empty$ note empty$
+  and and and and and
+  key empty$ not and
+    { "all relevant fields are empty in " cite$ * warning$ }
+    'skip$
+  if$
+}
+
+FUNCTION {format.thesis.type}
+{ type empty$
+    'skip$
+    { pop$
+      type "t" change.case$
+    }
+  if$
+}
+
+FUNCTION {format.tr.number}
+{ type empty$
+    { "Technical Report" }
+    'type
+  if$
+  number empty$
+    { "t" change.case$ }
+    { number tie.or.space.connect }
+  if$
+}
+
+FUNCTION {format.article.crossref}
+{ key empty$
+    { journal empty$
+	{ "need key or journal for " cite$ * " to crossref " * crossref *
+	  warning$
+	  ""
+	}
+	{ "in {\em " journal * "\/} \cite{" * crossref * "}" *}
+      if$
+    }
+    { "{\em in} \citeasnoun{" crossref * "}" * }
+  if$
+ 
+}
+
+FUNCTION {format.book.crossref}
+{ volume empty$
+    { "empty volume in " cite$ * "'s crossref of " * crossref * warning$
+      "in "
+    }
+    { "Vol." volume tie.or.space.connect
+      " of " *
+    }
+  if$
+  editor empty$
+  editor field.or.null author field.or.null =
+  or
+    { key empty$
+	{ series empty$
+	    { "need editor, key, or series for " cite$ * " to crossref " *
+	      crossref * warning$
+	      "" *
+	    }
+	    { "{\em " * series * "\/} \cite{" * crossref * "}" *}
+	  if$
+	}
+	{ " \citeasnoun{" * crossref * "}" * }
+      if$
+    }
+    { " \citeasnoun{" * crossref * "}" * }
+  if$
+}
+
+FUNCTION {format.incoll.inproc.crossref}
+{ editor empty$
+  editor field.or.null author field.or.null =
+  or
+    { key empty$
+	{ booktitle empty$
+	    { "need editor, key, or booktitle for " cite$ * " to crossref " *
+	      crossref * warning$
+	      ""
+	    }
+	    { "in {\em " booktitle * "\/}" * " \cite{" * crossref * "}" *}
+	  if$
+	}
+	{ "{\em in} \citeasnoun{" crossref * "}" * }
+      if$
+    }
+    { "{\em in} \citeasnoun{" crossref * "}" * }
+  if$
+  
+}
+
+INTEGERS { len }
+
+FUNCTION {chop.word}
+{ 's :=
+  'len :=
+  s #1 len substring$ =
+    { s len #1 + global.max$ substring$ }
+    's
+  if$
+}
+
+INTEGERS { ind tsslen }
+
+STRINGS { tss ret rss istr }
+
+FUNCTION {replace.substring}{
+  'rss :=
+  'tss :=
+  'istr :=
+  "" 'ret :=
+  tss text.length$ 'tsslen :=
+  #1 'ind :=
+    { istr ind tsslen substring$ "" = not }
+    { istr ind tsslen substring$ tss =
+        { ret rss * 'ret :=
+          ind tsslen + 'ind :=
+        }
+        { ret istr ind #1 substring$ * 'ret :=
+          ind #1 + 'ind :=
+        }
+      if$
+    }
+  while$
+  ret
+}
+
+FUNCTION {format.lab.names.abbr}
+{ 's :=
+  s num.names$ 'numnames :=
+  numnames #1 >
+    { numnames #2 >
+	{ s #1 "{vv~}{ll}" format.name$ " et~al." * }
+	{ s #2 "{ff }{vv }{ll}{ jj}" format.name$ "others" =
+            { s #1 "{vv~}{ll}" format.name$ " et~al." * }
+	    { s #1 "{vv~}{ll}" format.name$ " \harvardand\ " *
+              s #2 "{vv~}{ll}" format.name$ * 
+            }
+          if$
+        }
+      if$
+    }
+    { s #1 "{vv~}{ll}" format.name$ }
+  if$
+}
+
+FUNCTION {format.lab.names.full}
+{ 's :=
+  #1 'nameptr :=
+  s num.names$ 'numnames :=
+  numnames 'namesleft :=
+    { namesleft #0 > }
+    { s nameptr "{vv~}{ll}" format.name$ 't :=
+      nameptr #1 >
+	{ namesleft #1 >
+	    { ", " * t * }
+	    { t "others" =
+		{ " et~al." * }
+		{ " \harvardand\ " * t * }
+	      if$
+	    }
+	  if$
+	}
+	't
+      if$
+      nameptr #1 + 'nameptr :=
+      namesleft #1 - 'namesleft :=
+    }
+  while$
+}
+
+INTEGERS { author.field editor.field organization.field title.field key.field }
+
+FUNCTION {init.field.constants}
+{ #0 'author.field :=
+  #1 'editor.field :=
+  #2 'organization.field :=
+  #3 'title.field :=
+  #4 'key.field :=
+}
+
+FUNCTION {make.list.label}
+{ author.field field.used =
+    { format.authors }
+    { editor.field field.used =
+        { format.editors }
+        { organization.field field.used =
+            { "The " #4 organization chop.word #3 text.prefix$ }
+            { title.field field.used =
+                { format.btitle }
+                { key.field field.used =
+                    { key #3 text.prefix$ }
+                    { "Internal error :001 on " cite$ * " label" * warning$ }
+                  if$
+                }
+              if$
+            }
+          if$
+        }
+      if$
+    }
+  if$
+}
+
+FUNCTION {make.full.label}
+{ author.field field.used =
+    { author format.lab.names.full }
+    { editor.field field.used =
+        { editor format.lab.names.full }
+        { organization.field field.used =
+            { "The " #4 organization chop.word #3 text.prefix$ }
+            { title.field field.used =
+                { format.btitle }
+                { key.field field.used =
+                    { key #3 text.prefix$ }
+                    { "Internal error :001 on " cite$ * " label" * warning$ }
+                  if$
+                }
+              if$
+            }
+          if$
+        }
+      if$
+    }
+  if$
+}
+
+FUNCTION {make.abbr.label} %%%XXX change
+{
+  etal.allowed
+    { author.field field.used =
+        { author format.lab.names.abbr }
+        { editor.field field.used =
+            { editor format.lab.names.abbr }
+            { organization.field field.used =
+                { "The " #4 organization chop.word #3 text.prefix$ }
+                { title.field field.used =
+                    { format.btitle }
+                    { key.field field.used =
+                        { key #3 text.prefix$ }
+                        {"Internal error :001 on " cite$ * " label" * warning$ }
+                      if$
+                    }
+                  if$
+                }
+              if$
+            }
+          if$
+        }
+      if$
+    }
+    { make.full.label }
+  if$
+}
+
+FUNCTION {output.bibitem}
+{ newline$
+  etal.allowed        %%%XXX change
+  etal.required
+  and
+    {
+      "\harvarditem[" write$
+      make.abbr.label write$
+      "]{" write$
+    }
+    {
+      "\harvarditem{" write$
+    }
+  if$
+  make.full.label write$
+  "}{" write$
+  list.year write$
+  "}{" write$
+  cite$ write$
+  "}" write$
+  newline$
+  ""
+  before.all 'output.state :=
+}
+
+FUNCTION {list.label.output}
+{ make.list.label " " * write$
+}
+
+FUNCTION {article}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author "author" item.check
+  title.field field.used =
+    { skip$ }
+    { format.title quote "title" output.check }
+  if$
+  crossref missing$
+    { journal emphasize "journal" duplicate$ item.check
+      pages empty$
+        {
+          output
+        }
+        {
+          " " *
+          format.vol.num.pages * output
+        }
+      if$
+    }
+    { format.article.crossref output.nonnull
+      format.pages output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {book}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author empty$
+    { editor "author and editor" item.check }
+    { crossref missing$
+	{ "author and editor" editor either.or.check }
+	'skip$
+      if$
+    }
+  if$
+  title.field field.used =
+    { skip$ }
+    { format.btitle "title" output.check }
+  if$
+  crossref missing$
+    { format.bvolume output
+      format.number.series output
+      format.edition output
+      publisher "publisher" output.check
+      address output
+    }
+    { format.book.crossref output.nonnull
+      format.edition output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {booklet}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.title quote "title" output.check }
+  if$
+  howpublished output
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inbook}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author empty$
+    { editor "author and editor" item.check }
+    { crossref missing$
+	{ "author and editor" editor either.or.check }
+	'skip$
+      if$
+    }
+  if$
+  title.field field.used =
+    { skip$ }
+    { format.btitle "title" output.check }
+  if$
+  crossref missing$
+    { format.bvolume output
+      format.number.series output
+      format.edition output
+      publisher "publisher" output.check
+      address output
+    }
+    { format.book.crossref output.nonnull
+      format.edition output
+    }
+  if$
+  format.chapter.pages "chapter and pages" output.check
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {incollection}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.title "title" output.check }
+  if$
+  author "author" item.check
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.edition output
+      format.bvolume output
+      format.number.series output
+      publisher "publisher" output.check
+      address output
+    }
+    { format.incoll.inproc.crossref output.nonnull
+    }
+  if$
+  format.chapter.pages output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {inproceedings}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.title "title" output.check }
+  if$
+  author "author" item.check
+  crossref missing$
+    { format.in.ed.booktitle "booktitle" output.check
+      format.bvolume output
+      format.number.series output
+      address empty$
+	{ organization output
+	  publisher output
+	}
+	{ organization output
+	  publisher output
+          address output.nonnull
+ 	}
+      if$
+    }
+    { format.incoll.inproc.crossref output.nonnull
+    }
+  if$
+  format.pages output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {conference} { inproceedings }
+
+FUNCTION {manual}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.btitle "title" output.check }
+  if$
+  format.edition output
+  author empty$
+    { organization empty$
+	{ address output }
+	'skip$
+      if$
+    }
+    { organization output
+      address output
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {mastersthesis}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author "author" item.check
+  title.field field.used =
+    { skip$ }
+    { format.title "title" output.check }
+  if$
+  "Master's thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {misc}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.title quote output }
+  if$
+  howpublished output
+  new.block
+  note output
+  fin.entry
+  empty.misc.check
+}
+
+FUNCTION {phdthesis}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author "author" item.check
+  title.field field.used =
+    { skip$ }
+    { title "title" output.check }
+  if$
+  "PhD thesis" format.thesis.type output.nonnull
+  school "school" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {proceedings}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  title.field field.used =
+    { skip$ }
+    { format.btitle "title" output.check }
+  if$
+  format.bvolume output
+  format.number.series output
+  address empty$
+    { editor empty$
+	{ skip$ }
+	{ organization output
+	}
+      if$
+      publisher output
+    }
+    { editor empty$
+	'skip$
+	{ organization output }
+      if$
+      publisher output
+      address output.nonnull
+    }
+  if$
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {techreport}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author "author" item.check
+  title.field field.used =
+    { skip$ }
+    { format.title "title" output.check }
+  if$
+  format.tr.number output.nonnull
+  institution "institution" output.check
+  address output
+  new.block
+  note output
+  fin.entry
+}
+
+FUNCTION {unpublished}
+{ output.bibitem
+  list.label.output
+  " \harvardleft " list.year * "\harvardright " * output.nonnull
+  author "author" item.check
+  title.field field.used =
+    { skip$ }
+    { format.title "title" output.check }
+  if$
+  note "note" output.check
+  fin.entry
+}
+
+FUNCTION {default.type} { misc }
+
+MACRO {jan} {"January"}
+
+MACRO {feb} {"February"}
+
+MACRO {mar} {"March"}
+
+MACRO {apr} {"April"}
+
+MACRO {may} {"May"}
+
+MACRO {jun} {"June"}
+
+MACRO {jul} {"July"}
+
+MACRO {aug} {"August"}
+
+MACRO {sep} {"September"}
+
+MACRO {oct} {"October"}
+
+MACRO {nov} {"November"}
+
+MACRO {dec} {"December"}
+
+MACRO {acmcs} {"ACM Computing Surveys"}
+
+MACRO {acta} {"Acta Informatica"}
+
+MACRO {cacm} {"Communications of the ACM"}
+
+MACRO {ibmjrd} {"IBM Journal of Research and Development"}
+
+MACRO {ibmsj} {"IBM Systems Journal"}
+
+MACRO {ieeese} {"IEEE Transactions on Software Engineering"}
+
+MACRO {ieeetc} {"IEEE Transactions on Computers"}
+
+MACRO {ieeetcad}
+ {"IEEE Transactions on Computer-Aided Design of Integrated Circuits"}
+
+MACRO {ipl} {"Information Processing Letters"}
+
+MACRO {jacm} {"Journal of the ACM"}
+
+MACRO {jcss} {"Journal of Computer and System Sciences"}
+
+MACRO {scp} {"Science of Computer Programming"}
+
+MACRO {sicomp} {"SIAM Journal on Computing"}
+
+MACRO {tocs} {"ACM Transactions on Computer Systems"}
+
+MACRO {tods} {"ACM Transactions on Database Systems"}
+
+MACRO {tog} {"ACM Transactions on Graphics"}
+
+MACRO {toms} {"ACM Transactions on Mathematical Software"}
+
+MACRO {toois} {"ACM Transactions on Office Information Systems"}
+
+MACRO {toplas} {"ACM Transactions on Programming Languages and Systems"}
+
+MACRO {tcs} {"Theoretical Computer Science"}
+
+READ
+
+EXECUTE {init.field.constants}
+
+FUNCTION {sortify}
+{ purify$
+  "l" change.case$
+}
+
+FUNCTION {sortify.names}
+{ " \harvardand\ " " " replace.substring
+  " et~al." " zzz" replace.substring
+  sortify
+}
+
+FUNCTION {author.key.label}
+{ author empty$
+    { key empty$
+	{ title.field 'field.used := }
+	{ key.field 'field.used := }
+      if$
+    }
+    { author.field 'field.used := }
+  if$
+}
+
+FUNCTION {author.editor.key.label}
+{ author empty$
+    { editor empty$
+	{ key empty$
+	    { title.field 'field.used := }
+	    { key.field 'field.used := }
+	  if$
+  	}
+	{ editor.field 'field.used := }
+      if$
+    }
+    { author.field 'field.used := }
+  if$
+}
+
+FUNCTION {author.key.organization.label}
+{ author empty$
+    { key empty$
+	{ organization empty$
+	    { title.field 'field.used := }
+	    { organization.field 'field.used := }
+	  if$
+	}
+	{ key.field 'field.used := }
+      if$
+    }
+    { author.field 'field.used := }
+  if$
+}
+
+FUNCTION {editor.key.organization.label}
+{ editor empty$
+    { key empty$
+	{ organization empty$
+	    { title.field 'field.used := }
+	    { organization.field 'field.used := }
+	  if$
+	}
+	{ key.field 'field.used := }
+      if$
+    }
+    { editor.field 'field.used := }
+  if$
+}
+
+FUNCTION {sort.format.title}
+{ 't :=
+  "A " #2
+    "An " #3
+      "The " #4 t chop.word
+    chop.word
+  chop.word
+  sortify
+  #1 global.max$ substring$
+}
+
+FUNCTION {calc.label} %%%XXX change
+{ make.abbr.label
+  title.field field.used =
+    { sort.format.title }
+    { sortify.names }
+  if$
+  year field.or.null purify$ #-1 #4 substring$ sortify
+  *
+  'sort.label :=
+}
+
+FUNCTION {preliminaries} %%%XXX change
+{ type$ "book" =
+  type$ "inbook" =
+  or
+    'author.editor.key.label
+    { type$ "proceedings" =
+	'editor.key.organization.label
+	{ type$ "manual" =
+	    'author.key.organization.label
+	    'author.key.label
+	  if$
+	}
+      if$
+    }
+  if$
+  author.field field.used = %%%XXX change
+    {
+      author num.names$ #2 >
+        { #1 }
+        { #0 }
+      if$
+      'etal.required :=
+    }
+    {
+      editor.field field.used = 
+        {
+          editor num.names$ #2 >
+            { #1 }
+            { #0 }
+          if$
+        }
+        { #0 }
+      if$
+      'etal.required :=
+    }
+  if$
+  #1 'etal.allowed :=
+}
+
+FUNCTION {first.presort}
+{ calc.label
+  sort.label
+  title.field field.used =
+    { skip$ }
+    { "    "
+      *
+      make.list.label sortify.names
+      *
+      "    "
+      *
+      title field.or.null
+      sort.format.title
+      *
+    }
+  if$
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {preliminaries}
+
+ITERATE {first.presort}
+
+SORT
+
+STRINGS { last.sort.label next.extra last.full.label}
+
+INTEGERS { last.extra.num last.etal.allowed}
+
+FUNCTION {initialize.confusion}
+{ #0 int.to.chr$ 'last.sort.label :=
+  #0 int.to.chr$ 'last.full.label :=
+  #1 'last.etal.allowed :=
+}
+
+FUNCTION {confusion.pass}
+{ last.sort.label sort.label =
+    { last.etal.allowed 
+        { last.full.label make.full.label sortify.names =
+            { skip$ }
+            { #0 'etal.allowed :=
+              #0 'last.etal.allowed :=
+            }
+          if$
+        }
+        { #0 'etal.allowed := }
+      if$
+    }
+    { sort.label 'last.sort.label :=
+      make.full.label sortify.names 'last.full.label :=
+      #1 'last.etal.allowed :=
+    }
+  if$
+}
+
+EXECUTE {initialize.confusion}
+
+ITERATE {confusion.pass}
+
+EXECUTE {initialize.confusion}
+
+REVERSE {confusion.pass}
+
+FUNCTION {initialize.last.extra.num}
+{ #0 int.to.chr$ 'last.sort.label :=
+  "" 'next.extra :=
+  #0 'last.extra.num :=
+}
+
+FUNCTION {forward.pass}
+{ last.sort.label sort.label =
+    { last.extra.num #1 + 'last.extra.num :=
+      last.extra.num int.to.chr$ 'extra.label :=
+    }
+    { "a" chr.to.int$ 'last.extra.num :=
+      "" 'extra.label :=
+      sort.label 'last.sort.label :=
+    }
+  if$
+}
+
+FUNCTION {reverse.pass}
+{ next.extra "b" =
+    { "a" 'extra.label := }
+    'skip$
+  if$
+  year empty$
+    { "n.d." extra.label emphasize * 'list.year := }
+    { year extra.label emphasize * 'list.year := }
+  if$
+  extra.label 'next.extra :=
+}
+
+ITERATE {first.presort}
+
+SORT
+
+EXECUTE {initialize.last.extra.num}
+
+ITERATE {forward.pass}
+
+REVERSE {reverse.pass}
+
+FUNCTION {second.presort}
+{ make.list.label
+  title.field field.used =
+    { sort.format.title }
+    { sortify.names }
+  if$
+  "    "
+  *
+  list.year field.or.null sortify
+  *
+  "    "
+  *
+  title.field field.used =
+    { skip$ }
+    { title field.or.null
+      sort.format.title
+      *
+    }
+  if$
+  #1 entry.max$ substring$
+  'sort.key$ :=
+}
+
+ITERATE {second.presort}
+
+SORT
+
+FUNCTION {begin.bib}
+{ preamble$ empty$
+    'skip$
+    { preamble$ write$ newline$ }
+  if$
+  "\begin{thebibliography}{xx}" write$ newline$
+}
+
+EXECUTE {begin.bib}
+
+EXECUTE {init.state.consts}
+
+ITERATE {call.type$}
+
+FUNCTION {end.bib}
+{ newline$
+  "\end{thebibliography}" write$ newline$
+}
+
+EXECUTE {end.bib}
Index: trunk/mops/oorb/doc/asteroid.bib
===================================================================
--- trunk/mops/oorb/doc/asteroid.bib	(revision 34646)
+++ trunk/mops/oorb/doc/asteroid.bib	(revision 34646)
@@ -0,0 +1,2315 @@
+@InBook{tnss,
+  ALTauthor = 	 {},
+  editor = 	 {Beatty, J. K.        and
+                  Collins Petersen, C. and
+                  Chaikin, A.             },
+  title = 	 {{The New Solar System}},
+  chapter = 	 {3},
+  publisher = 	 {{Sky Publishing Corporation and
+                  Cambridge University Press     }},
+  year = 	 {1999},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  edition = 	 {4th},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{bel1934,
+  author = 	 {Bell, E. T.},
+  title = 	 {Exponential Numbers},
+  journal = 	 {Amer. Math. Monthly},
+  year = 	 {1934},
+  OPTkey = 	 {},
+  volume = 	 {41},
+  OPTnumber = 	 {},
+  pages = 	 {411--419},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{ber,
+  author = 	 {},
+  title = 	 {},
+  journal = 	 {},
+  year = 	 {},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTpages = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{boa2001a,
+  author = 	 {Boattini, A. and
+                  D'Abramo, G. and
+                  Forti, G.    and
+                  Gal, R.},
+  title = 	 {{The Arcetri NEO Precovery Program}},
+  journal = 	 {Astron. Astrophys.},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {375},
+  OPTnumber = 	 {},
+  pages = 	 {293--307},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{bot2002a,
+  author = 	 {Bottke, W. F.  and
+                  Morbidelli, A. and
+                  Jedicke, R.    and
+                  Petit, J. M.   and
+                  Levison, H. F. and
+                  Michel, P.     and
+                  Metcalfe, T. S.   },
+  title = {{Debiased Orbital and Absolute Magnitude Distribution of
+  the Near-Earth Objects}},
+  journal = 	 {Icarus},
+  year = 	 {2002a},
+  OPTkey = 	 {},
+  volume = 	 {156},
+  number = 	 {2},
+  pages = 	 {399--433},
+  month = 	 {April},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{bot2002b,
+  author = 	 {Bottke, Jr. W. F.  and
+                  Vokrouhlick\'y, D. and
+                  Rubincam, D. P.    and
+                  Broz, M.},
+  booktitle = 	 {{Asteroids III}},
+  title = 	 {{The Effect of Yarkovsky Thermal Forces on the Dynamical Evolution of Asteroids and Meteoroids}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002b},
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {395--408},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+@InBook{bow1989a,
+  author = 	 {Bowell, E.      and
+                  Chernykh, N. S. and
+                  Marsden, B. G.},
+  title = 	 {Asteroids II},
+  chapter = 	 {{Discovery and follow up of asteroids}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {1989},
+  editor = 	 {Binzel, Richard P.        and
+                  Gehrels, Tom              and
+                  Matthews, Mildred Shapley},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {21--38},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{bow1993a,
+  author = 	 {Bowell, Edward      and
+                  Wasserman, Larry H. and
+                  Muinonen, Karri     and
+                  McNaught, Robert H.},
+  title = 	 {{A Search for the Lost Asteroid (719) Albert}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {1993},
+  OPTkey = 	 {},
+  volume = 	 {25},
+  OPTnumber = 	 {},
+  pages = 	 {1118 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{bow1994a,
+  author = 	 {Bowell, E.       and
+                  Muinonen, K.     and
+                  Wasserman, L. H.    },
+  title = 	 {{A Public-Domain Asteroid Orbit Data Base}},
+  booktitle = 	 {Asteroids, Comets, Meteors 1993},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {477},
+  year = 	 {1994},
+  editor = 	 {Milani, A.     and
+                  di Martino, M. and
+                  Cellino, A.       },
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#160},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#160},
+  publisher =    {Co-published by IAU and Kluwer Academic Publishers, Dordrecht},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{bow1994b,
+  author = 	 {Bowell, E.   and
+                  Muinonen, K.    },
+  booktitle = 	 {Hazards due to Comets and Asteroids},
+  title = 	 {{Earth-crossing asteroids and comets: groundbased search strategies}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {1994},
+  editor = 	 {Gehrels, T.},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {149--197},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{bow2003a,
+  author = 	 {Bowell, Edward   and
+                  Virtanen, Jenni  and
+                  Muinonen, Karri  and
+                  Boattini, Andrea    },
+  booktitle = 	 {{Asteroids III}},
+  title = 	 {{Asteroid Orbit Computation}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {27--43},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{bow2007a,
+  author = 	 {Bowell, Edward      and
+                  Millis, Robert L.   and
+                  Dunham, Edward W.   and
+                  Koehn, Bruce W.     and
+                  Smith, Byron W.},
+  title = 	 {{Searching for NEOs using Lowell observatorys Discovery Channel Telescope (DCT)}},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{car2003a,
+  author = 	 {Carpino, Mario     and
+                  Milani, Andrea     and
+                  Chesley, Steven R.},
+  title = 	 {Error statistics of asteroid optical astrometric observations},
+  journal = 	 {Icarus},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  volume = 	 {166},
+  number = 	 {2},
+  pages = 	 {248--270},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Misc{che2003a,
+  OPTkey = 	 {},
+  author = 	 {Chesley, Steve},
+  opturl =       {},       
+  title = 	 {{Monte Carlo uncertainty estimation}},
+  howpublished = {Minor Planet Mailing List},
+  month = 	 feb,
+  year = 	 {2003},
+  note = 	 {\texttt{http://groups.yahoo.com/group/mpml/message/9488}},
+  optannote = 	 {}
+}
+
+@Article{cho1993a,
+  author = 	 {Chodas, P.},
+  title = 	 {{Estimating the Impact Probability of a Minor Planet with the Earth}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {1993},
+  OPTkey = 	 {},
+  volume = 	 {25},
+  OPTnumber = 	 {},
+  pages = 	 {1236 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{cho2000a,
+  author = 	 {Chodas, P.},
+  title = 	 {{Estimating Impact Probability Using Monte Carlo Techniques}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {2000},
+  OPTkey = 	 {},
+  volume = 	 {32},
+  number = 	 {2},
+  pages = 	 {862 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{dav2004a,
+  author = 	 {Davis, D. R.     and
+                  Gladman, B.      and
+                  Jedicke, R.      and
+                  Williams, G.},
+  title = 	 {{SKADS: Sub-Kilometer Asteroid Diameter Survey}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {36},
+  number = 	 {4},
+  pages = 	 {1142--1143 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{edg1943a,
+  author = 	 {Edgeworth, K. E.},
+  title = 	 {The evolution of our planetary system},
+  journal = 	 {J. Br. Astron. Assoc.},
+  year = 	 {1943},
+  OPTkey = 	 {},
+  volume = 	 {53},
+  OPTnumber = 	 {},
+  pages = 	 {181--188},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{eve1968a,
+  author = 	 {Everhart, Edgar},
+  title = 	 {{Change in Total Energy of Comets Passing through the Solar System}},
+  journal = 	 {Astrophys. J.},
+  year = 	 {1968},
+  OPTkey = 	 {},
+  volume = 	 {73},
+  OPTnumber = 	 {},
+  pages = 	 {1039--1052},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{eve1972a,
+  author = 	 {Everhart, Edgar},
+  title = 	 {},
+  journal = 	 {Astrophys. Letters},
+  year = 	 {1972},
+  OPTkey = 	 {},
+  volume = 	 {10},
+  OPTnumber = 	 {},
+  pages = 	 {131},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{eve1974a,
+  author = 	 {Everhart, Edgar},
+  title = 	 {Implicit Single-Sequence Methods for Integrating Orbits},
+  journal = 	 {Cel. Mech.},
+  year = 	 {1974},
+  OPTkey = 	 {},
+  volume = 	 {10},
+  OPTnumber = 	 {},
+  pages = 	 {35--55},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{eve1985a,
+  author = 	 {Everhart, Edgar},
+  booktitle = 	 {{Dynamics of Comets: Their Origin and Evolution}},
+  title = 	 {{An efficient integrator that uses Gauss-Radau spacings}},
+  publisher = 	 {D. Reidel Publishing Company},
+  year = 	 {1985},
+  editor = 	 {Carusi, Andrea and 
+                  Valsecchi, Giovanni B.},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  address = 	 {Dordrecht},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {185--202},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{fer1999a,
+  author = 	 {Ferraz-Mello, Sylvio},
+  title = 	 {{Slow and Fast Diffusion in Asteroid Belt Resonances: A Review}},
+  journal = 	 {Cel. Mech. Dyn. Astron.},
+  year = 	 {1999},
+  OPTkey = 	 {},
+  volume = 	 {73},
+  OPTnumber = 	 {},
+  pages = 	 {25--37},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{fod2002a,
+  author = 	 {Foder\'a Serio, G. and
+                  Manara, A.         and
+                  Sicoli, A.      },
+  booktitle = 	 {Asteroids III},
+  title =        {{Giuseppe Piazzi and the Discovery of Ceres}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {17--24},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gla2005a,
+  author = 	 {Gladman, Brett},
+  title = 	 {{The Kuiper Belt and the Solar System's Comet Disk}},
+  journal = 	 {Science},
+  year = 	 {2005},
+  OPTkey = 	 {},
+  volume = 	 {307},
+  OPTnumber = 	 {},
+  pages = 	 {71--75},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2003a,
+  author = 	 {Granvik, Mikael     and
+                  Virtanen, Jenni     and
+                  Muinonen, Karri     and
+                  Bowell, Edward      and
+                  Koehn, Bruce        and
+                  Tancredi, Gonzalo},
+  title = 	 {{Transneptunian Object Ephemeris Service (TNOEPH)}},
+  journal = 	 {Earth, Moon and Planets},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  volume = 	 {92},
+  OPTnumber = 	 {},
+  pages = 	 {73--78},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@MastersThesis{gra2003b,
+  author = 	 {Granvik, Mikael},
+  title = 	 {Asteroid identification at discovery},
+  school = 	 {University of Helsinki, Department of Astronomy},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  month = 	 dec,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2004a,
+  author = 	 {Granvik, Mikael      and
+                  Muinonen, Karri      and
+                  Virtanen, Jenni      and
+                  Bowell, Edward           },
+  title = 	 {{Asteroid Identification Using LONEOS Observation Archives}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {36},
+  number = 	 {5},
+  pages = 	 {1697 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{gra2005a,
+  author = 	 {Granvik, Mikael      and
+                  Muinonen, Karri      and
+                  Virtanen, Jenni      and
+                  Delbo, Marco         and
+                  Saba, Laura          and
+                  De Sanctis, Giovanni and
+                  Morbidelli, Roberto  and
+                  Cellino, Alberto     and
+                  Tedesco, Edward},
+  title = 	 {{Linking Very Large Telescope asteroid observations}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Dynamics of Populations of Planetary Systems}},
+  pages = 	 {231--238},
+  year = 	 {2005a},
+  editor = 	 {Kne{\v z}evi{\' c}, Zoran    and
+                  Milani, Andrea},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Colloquium \#197},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Colloquium \#197},
+  publisher =    {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{gra2005b,
+  author = 	 {Granvik, Mikael      and
+                  Muinonen, Karri      and
+                  Virtanen, Jenni      and
+                  Bowell, Edward       and
+                  Wasserman, Lawrence H.},
+  title = 	 {{Linking simulated Large Synoptic Survey Telescope asteroid observations}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Astrometry in the Age of the Next Generation of Large Telescopes}},
+  OPTpages = 	 {},
+  year = 	 {2005b},
+  editor = 	 {Seidelmann, P. Kenneth    and
+                  Monet, Alice K. B.},
+  volume = 	 {338},
+  OPTnumber = 	 {},
+  series = 	 {ASP Conference Series},
+  address = 	 {Brigham Young University, Provo, UT, U.S.A.},
+  OPTmonth = 	 {},
+  OPTorganization = {ASP},
+  publisher =    {Astronomical Society of the Pacific},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2005c,
+  author = 	 {Granvik, Mikael and
+                  Muinonen, Karri},
+  title = 	 {{Asteroid identification at discovery}},
+  journal = 	 {Icarus},
+  year = 	 {2005},
+  OPTkey = 	 {},
+  volume = 	 {179},
+  number = 	 {1},
+  pages = 	 {109--127},
+  month = 	 {dec},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+@InProceedings{gra2005d,
+  author = 	 {Granvik, Mikael and
+                  Muinonen, Karri and
+                  Virtanen, Jenni and
+                  Spahr, Timothy  and
+                  Bowell, Edward},
+  title = 	 {Linking and identifying hitherto unidentified asteroid observations},
+  booktitle = 	 {Asteroids, Comets, Meteors 2005 Abstract Book},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {127},
+  year = 	 {2005b},
+  OPTeditor = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#229},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {IAU Symposium \#229},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{gra2007a,
+  author = 	 {Granvik, Mikael   and
+                  Muinonen, Karri},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  title = 	 {{Near-Earth Object Identification Over Apparitions Using $n$-body Ranging}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2007b,
+  author = 	 {Granvik, Mikael       and
+                  Muinonen, Karri       and
+                  Jones, Lynne          and
+                  Bhattacharya, Bidushi and
+                  Delb\'o, Marco        and
+                  Saba, Laura           and
+                  Cellino, Alberto      and
+                  Tedesco, Edward       and
+                  Davis, Don            and
+                  Meadows, Victoria},
+  title = 	 {{Linking Large-Parallax Spitzer-CFHT-VLT Astrometry of Asteroids}},
+  journal = 	 {Icarus},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  volume = 	 {192},
+  number = 	 {2},
+  pages = 	 {475--490},
+  month = 	 dec,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2007d,
+  author = 	 {Granvik, Mikael and
+                  Muinonen, Karri},
+  title = 	 {{Linking scarce asteroid astrometry at discovery and over apparitions}},
+  journal = 	 {Bull. Am. Astron. Soc.},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  volume = 	 {39},
+  number = 	 {3},
+  pages = 	 {514 (abstract)},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@PhdThesis{gra2007e,
+  author = 	 {Granvik,Mikael},
+  title = 	 {Asteroid identification using statistical orbital
+                  inversion methods},
+  school = 	 {Unversity of Helsinki},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{gra2008a,
+  author = 	 {Granvik, Mikael and
+                  Muinonen, Karri},
+  title = 	 {{Asteroid identification over apparitions}},
+  journal = 	 {Icarus},
+  year = 	 {2008},
+  OPTkey = 	 {},
+  OPTvolume = 	 {179},
+  OPTnumber = 	 {1},
+  OPTpages = 	 {109--127},
+  OPTmonth = 	 dec,
+  note = 	 {in press},
+  OPTannote = 	 {}
+}
+
+@Article{her1965a,
+  author = 	 {Herget, Paul},
+  title = 	 {{Computation of Preliminary Orbits}},
+  journal = 	 {Astron. J.},
+  year = 	 {1965},
+  OPTkey = 	 {},
+  volume = 	 {70},
+  number = 	 {1},
+  pages = 	 {1--2},
+  OPTmonth = 	 feb,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{hou1970a,
+  author = 	 {van Houten, C. J.         and
+                  van Houten-Groeneveld, I. and
+                  Herget, P.                and
+                  Gehrels, T},
+  title = 	 {{The Palomar-Leiden survey of faint minor planets}},
+  journal = 	 {Astron. Astrophys. Suppl. Ser.},
+  year = 	 {1970},
+  OPTkey = 	 {houten},
+  volume = 	 {2},
+  number = 	 {5},
+  pages = 	 {339--448},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{hou1984a,
+  author = 	 {van Houten, C. J.         and
+                  Herget, P.                and
+                  Marsden, B. G.},
+  title = 	 {{The Palomar-Leiden survey of faint minor planets - Conclusion}},
+  journal = 	 {Icarus},
+  year = 	 {1984},
+  OPTkey = 	 {houten},
+  volume = 	 {59},
+  OPTnumber = 	 {},
+  pages = 	 {1--19},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{hon2006a,
+  author = 	 {H\"onig, Sebastian F.},
+  title = 	 {Identification of a new short-period comet near the Sun},
+  journal = 	 {Astron. Astrophys.},
+  year = 	 {2006},
+  OPTkey = 	 {},
+  volume = 	 {445},
+  number = 	 {2},
+  pages = 	 {759--763},
+  month = 	 jan,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{ive2001a,
+  author = {Ivezi\'c, {\v Z}eljko and Tabachnik, Serge and Rafikov,
+                  Roman and Lupton, Robert H. and Quinn, Tom and
+                  Hammergren, Mark and Eyer, Laurent and Chu, Jennifer
+                  and Armstrong, John C. and Fan, Xiaohui and
+                  Finlator, Kristian and Geballe, Tom R. and Gunn,
+                  James E. and Hennessy, Gregory S. and Knapp, Gillian
+                  R. and Leggett, Sandy K. and Munn, Jeffrey A. and
+                  Pier, Jeffrey R. and Rockosi, Constance M. and
+                  Schneider, Donald P. and Strauss, Michael A. and
+                  Yanny, Brian and Brinkmann, Jonathan and Csabai,
+                  Istv\'an and Hindsley, Robert B. and Kent, Stephen and
+                  Lamb, Don Q. and Margon, Bruce and McKay, Timothy
+                  A. and Smith, J. Allyn and Waddel, Patrick and York,
+                  Donald G. and the SDSS Collaboration},
+  title = 	 {Solar system objects observed in the Sloan Digital Survey commissioning data},
+  journal = 	 {Astron. J.},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {122},
+  OPTnumber = 	 {},
+  pages = 	 {2749--2784},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{ive2007a,
+  author = 	 {Ivezi\'c, {\v Z}eljko   and
+                  Tyson, J.\ Anthony      and
+                  Juri\'c, Mario          and
+                  Kubica, Jeremy          and
+                  Connolly, Adrew         and
+                  Pierfederici, Francesco and
+                  Harris, Alan W.         and
+                  Bowell, Edward          and
+                  the LSST Collaboration},
+  title = 	 {{LSST: Comprehensive NEO detection, characterization, and orbits}},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{jed1996a,
+  author = 	 {Jedicke, Robert},
+  title = 	 {Detection of near Earth asteroids based upon their rates of motion},
+  journal = 	 {Astron. J.},
+  year = 	 {1996},
+  OPTkey = 	 {},
+  volume = 	 {111},
+  number = 	 {2},
+  pages = 	 {970--982},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{jed2003a,
+  author = 	 {Jedicke, Robert  and
+                  Larsen, Jeffrey  and
+                  Spahr, Timothy      },
+  booktitle = 	 {Asteroids III},
+  title = {{Observational Selection Effects in Asteroid Surveys and
+  Estimates of Asteroid Population Sizes}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {71--87},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{jed2007a,
+  author = 	 {Jedicke, Robert and
+                  Magnier, E. A.  and
+                  Kaiser, N.      and
+                  Chambers, K. C.},
+  title = 	 {{The next decade of Solar System discovery with Pan-STARRS}},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{jef1946a,
+  author = 	 {Jeffreys, Harold},
+  title = 	 {An invariant form for the prior probability in estimation problems},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Proceedings of the Royal Society of London},
+  pages = 	 {453--461},
+  year = 	 {1946},
+  OPTeditor = 	 {},
+  volume = 	 {186},
+  number = 	 {1007},
+  series = 	 {Series A (Mathematical and Physical Sciences)},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{jew1993a,
+  author = 	 {Jewitt, David C. and
+                  Luu, Jane X.        },
+  title = 	 {Discovery of the candidate {K}uiper belt object 1992 {QB}1},
+  journal = 	 {Nature},
+  year = 	 {1993},
+  OPTkey = 	 {},
+  volume = 	 {362},
+  number = 	 {6422},
+  pages = 	 {730--732},
+  month = 	 apr,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InBook{kir1867a,
+  author = 	 {Kirkwood, Daniel},
+  ALTeditor = 	 {},
+  title = {Meteoric astronomy: a treatise on shooting-stars,
+  fireballs, and aerolites.},
+  chapter = 	 {13},
+  publisher = 	 {J. B. Lippincott \& co.},
+  year = 	 {1867},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  address = 	 {Philadelphia},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{kra2002a,
+  author = 	 {Krasinsky, G. A and
+                  Pitjeva, E. V.  and
+                  Vasilyev, M. V. and
+                  Yagudina, E. I.    },
+  title = 	 {{Hidden Mass in the Asteroid Belt}},
+  journal = 	 {Icarus},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  volume = 	 {158},
+  number = 	 {1},
+  pages = 	 {98--105},
+  month = 	 {July},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{kri1995a,
+  author = 	 {Kristensen, L. Kahl},
+  title = 	 {Orbit determination by four observations},
+  journal = 	 {Astron. Nachr.},
+  year = 	 {1995},
+  OPTkey = 	 {},
+  volume = 	 {316},
+  number = 	 {4},
+  pages = 	 {261--266},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{kri2007a,
+  author = 	 {Kristensen, Leif Kahl},
+  title = 	 {Initial linking methods and their classification},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@PhdThesis{kub2005a,
+  author = 	 {Kubica, Jeremy},
+  title = {{Efficient Discovery of Spatial Associations and Structure
+  with Application to Asteroid Tracking}},
+  school = 	 {The Robotics Insitute, Carnegie Mellon University},
+  year = 	 {2005},
+  OPTkey = 	 {},
+  OPTtype = 	 {},
+  address = 	 {Pittsburgh, PA, USA},
+  month = 	 dec,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{kub2007a,
+  author = 	 {Kubica, Jeremy   and
+                  Denneau, Larry   and
+                  Grav, Tommy      and
+                  Heasley, James   and
+                  Jedicke, Robert  and
+                  Masiero, Joseph  and
+                  Milani, Andrea   and
+                  Moore, Andrew    and
+                  Tholen, David    and
+                  Wainscoat, Richard J.},
+  title = 	 {Efficient intra- and inter-night linking of asteroid detections using kd-trees},
+  journal = 	 {Icarus},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  volume = 	 {189},
+  number = 	 {1},
+  pages = 	 {151--168},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{kui1951a,
+  author = 	 {Kuiper, Gerard P.},
+  title = 	 {On the origin of the solar system},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Astrophysics},
+  pages = 	 {357--424},
+  year = 	 {1951},
+  editor = 	 {Hynek, J. A.},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {New York},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher =    {McGraw-Hill},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+
+@Article{kui1958a,
+  author = 	 {Kuiper, G. P.      and
+                  Fujita, Y.         and
+                  Gehrels, T.        and
+                  Groeneveld, I.     and
+                  Kent, J.           and
+                  van Biesbroeck, G. and
+                  van Houten, C. J.},
+  title = 	 {{Survey of Asteroids}},
+  journal = 	 {Astrophys. J. Suppl. Ser.},
+  year = 	 {1958},
+  OPTkey = 	 {},
+  volume = 	 {3},
+  number = 	 {32},
+  pages = 	 {289--428},
+  month = 	 jul,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{lar2007a,
+  author = 	 {Larson, Stephen},
+  title = 	 {{Current NEO surveys}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  pages = 	 {323--328},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  publisher = {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{Leo1930a,
+  author = 	 {Leonard, F. C.},
+  title = 	 {{The New Planet Pluto}},
+  journal = 	 {Leaflet Astron. Soc. Pacific},
+  year = 	 {1930},
+  OPTkey = 	 {},
+  volume = 	 {},
+  number = 	 {30},
+  pages = 	 {121--124},
+  month = 	 aug,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{lev1996a,
+  author = 	 {Levison, Harold F.},
+  title = 	 {Comet taxonomy},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Completing the Inventory of the Solar System}},
+  pages = 	 {173--191},
+  year = 	 {1996},
+  editor = 	 {Rettig, T. W. and
+                  Hahn, J. M.},
+  volume = 	 {107},
+  OPTnumber = 	 {},
+  series = 	 {ASP Conf. Ser.},
+  address = 	 {San Fransisco},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher =    {Astronomical Society of the Pacific},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+@Article{lex1777a,
+  author = 	 {Lexell, Anders Johan},
+  OPTtitle = 	 {},
+  journal = 	 {Acta Academiae Scientiarum Imperialis Petropolitanae},
+  year = 	 {1777},
+  OPTkey = 	 {},
+  volume = 	 {1},
+  OPTnumber = 	 {},
+  pages = 	 {332},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{Luu2002a,
+  author = 	 {Luu, Jane X.     and 
+                  Jewitt, David C.    },
+  title = 	 {{Kuiper Belt Objects}: {Relics} from the {Accretion Disk} of the {Sun}},
+  journal = 	 araa, 
+  year = 	 {2002},
+  OPTkey = 	 {},
+  volume = 	 {40},
+  OPTnumber = 	 {},
+  pages = 	 {63--101},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mar1980a,
+  author = 	 {Marsden, Brian},
+  title = 	 {{The Minor Planet Center}},
+  journal = 	 {Cel. Mech.},
+  year = 	 {1980},
+  OPTkey = 	 {},
+  volume = 	 {22},
+  OPTnumber = 	 {},
+  pages = 	 {63},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mar1985a,
+  author = 	 {Marsden, Brian G.},
+  title = 	 {Initial orbit determination: the pragmatist's point of view},
+  journal = 	 {Astron. J.},
+  year = 	 {1985},
+  OPTkey = 	 {},
+  volume = 	 {90},
+  number = 	 {8},
+  pages = 	 {1541--1547},
+  month = 	 aug,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mar1986a,
+  author = 	 {Marsden, Brian G.},
+  title = 	 {Identifications of minor planets},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {{Asteroids, Comets, Meteors II}},
+  pages = 	 {3--12},
+  year = 	 {1986},
+  editor = 	 {Lagerkvist, C.-I.  and
+                  Lindblad, B. A.    and
+                  Lundstedt, H.      and
+                  Rickman, H.},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher = {Uppsala universitet},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mar1991a,
+  author = 	 {Marsden, Brian G.},
+  title = 	 {The computation of orbits in indeterminate and uncertain cases},
+  journal = 	 {Astron. J.},
+  year = 	 {1991},
+  OPTkey = 	 {},
+  volume = 	 {102},
+  number = 	 {4},
+  pages = 	 {1539--1552},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mea2004a,
+  author = 	 {Meadows, V. S.     and
+                  Bhattacharya, B.   and
+                  Reach, W. T.       and
+                  Grillmair, C.      and
+                  Noriega-Crespo, A. and
+                  Ryan, E. L.        and
+                  Tyler, S. R.       and
+                  Rebull, L. M.      and
+                  Giorgini, J. D.    and
+                  Elliot, J. L.},
+  title = {{The \emph{Spitzer} First Look Survey}---{Ecliptic Plane
+  Component: Asteroids and Zodiacal Background.}},
+  journal = 	 {Astrophys. J. Suppl. Ser.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {154},
+  number = 	 {1},
+  pages = 	 {469--474},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mig2007a,
+  author = 	 {Mignard, Francois  and
+                  Cellino, Alberto   and
+                  Muinonen, Karri    and
+                  Tanga, Paolo       and
+                  Delb\'o, Marco     and
+                  Dell'Oro, Aldo     and
+                  Granvik, Mikael    and
+                  Hestroffer, Daniel and
+                  Mouret, Serge      and
+                  Thuillot, William  and
+                  Virtanen, Jenni},
+  title = 	 {{The Gaia mission: Expected applications to asteroid science}},
+  journal = 	 {EMP},
+  year = 	 {2008},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTpages = 	 {},
+  OPTmonth = 	 {},
+  note = 	 {Submitted},
+  OPTannote = 	 {}
+}
+
+@Article{mil1999a,
+  author = 	 {Milani, Andrea},
+  title = 	 {{The Asteroid Identification Problem I. Recovery of Lost Asteroids}},
+  journal = 	 {Icarus},
+  year = 	 {1999},
+  OPTkey = 	 {},
+  volume = 	 {137},
+  number = 	 {2},
+  pages = 	 {269--292},
+  month = 	 feb,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil1999b,
+  author = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B.    },
+  title = {{The Asteroid Identification Problem II. Target Plane
+  Confidence Boundaries}},
+  journal = 	 {Icarus},
+  year = 	 {1999},
+  OPTkey = 	 {},
+  volume = 	 {140},
+  number = 	 {2},
+  pages = 	 {408--423},
+  month = 	 aug,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2000a,
+  author = 	 {Milani, Andrea            and
+                  La Spina, Alessandra      and 
+                  Sansaturio, Maria Eugenia and
+                  Chesley, Steven R.           },
+  title = 	 {{The Asteroid Identification Problem III. Proposing Identifications}},
+  journal = 	 {Icarus},
+  year = 	 {2000},
+  OPTkey = 	 {},
+  volume = 	 {144},
+  number = 	 {1},
+  pages = 	 {39--53},
+  month = 	 mar,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2001a,
+  author = 	 {Milani, Andrea            and
+                  Sansaturio, Maria Eugenia and
+                  Chesley, Steven R.           },
+  title = 	 {{The Asteroid Identification Problem IV. Attributions}},
+  journal = 	 {Icarus},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {151},
+  number = 	 {2},
+  pages = 	 {150--159},
+  month = 	 jun,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2004a,
+  author = 	 {Milani, Andrea              and
+                  Gronchi, Giovanni F.        and
+                  Vitturi, Mattia De'michieli and
+                  Kne{\v z}evi{\' c}, Zoran},
+  title = 	 {{Orbit determination with very short arcs. II Admissible regions}},
+  journal = 	 {Cel. Mech. Dyn. Astron.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {90},
+  OPTnumber = 	 {},
+  pages = 	 {59--87},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2005a,
+  author = 	 {Milani, Andrea            and
+                  Gronchi, Giovanni F.      and
+                  Kne{\v z}evi{\' c}, Zoran           and
+                  Sansaturio, Maria Eugenia and
+                  Arratia, Oscar},
+  title = 	 {{Orbit determination with very short arcs. II Identifications}},
+  journal = 	 {Icarus},
+  year = 	 {2005a},
+  OPTkey = 	 {},
+  volume = 	 {179},
+  number = 	 {2},
+  pages = 	 {350--374},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2005b,
+  author = 	 {Milani, Andrea            and
+                  Sansaturio, Maria Eugenia and
+                  Tommei, Giacomo           and
+                  Arratia, Oscar            and
+                  Chesley, Steve R.},
+  title = 	 {{Multiple solutions for asteroid orbits: Computational procedure and applications}},
+  journal = 	 {Astron. Astrophys.},
+  year = 	 {2005b},
+  OPTkey = 	 {},
+  volume = 	 {431},
+  OPTnumber = 	 {},
+  pages = 	 {729--746},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2005c,
+  author = 	 {Milani, Andrea            and
+                  Chesley, Steve R.         and
+                  Sansaturio, Maria Eugenia and
+                  Tommei, Giacomo           and
+                  Valsecchi, Giovanni B.},
+  title = 	 {Nonlinear impact monitoring: line of variation searches for impactors},
+  journal = 	 {Icarus},
+  year = 	 {2005},
+  OPTkey = 	 {},
+  volume = 	 {173},
+  number = 	 {2},
+  pages = 	 {362--384},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+
+@Article{mil2007a,
+  author = 	 {Milani, Andrea             and
+                  Gronchi, Giovanni F.       and 
+                  Kne{\v z}evi{\' c}, Zoran},
+  title = 	 {{New Definition of Discovery for Solar System Objects}},
+  journal = 	 {Earth, Moon, and Planets},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  volume = 	 {100},
+  OPTnumber = 	 {},
+  pages = 	 {83--116},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mil2002a,
+  author = 	 {Millis, R. L.    and 
+                  Buie, M. W.      and
+                  Wasserman, L. H. and
+                  Elliot, J. L.    and
+                  Kern, S. D.      and
+                  Wagner, R. M.},
+  title = {{The Deep Ecliptic Survey: A search for Kuiper Belt Objects
+  and Centaurs. I. Description of the methods and initial results}},
+  journal = 	 {Astron. J.},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  volume = 	 {123},
+  OPTnumber = 	 {},
+  pages = 	 {2083--2109},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InBook{mor2003a,
+  author = 	 {Morrison, David   and
+                  Harris, Alan W.   and
+                  Sommer, Geoffrey  and
+                  Chapman, Clark R. and
+                  Carusi, Andrea       },
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  title = 	 {Asteroids III},
+  chapter = 	 {{Dealing with the Impact Hazard}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {739--754},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mor2002a,
+  author = 	 {Morbidelli, Alessandro},
+  title = 	 {{Modern Integrations of Solar System Dynamics}},
+  journal = 	 {Annu. Rev. Earth Planet. Sci.},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  volume = 	 {30},
+  OPTnumber = 	 {},
+  pages = 	 {89--112},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui1993a,
+  author = 	 {Muinonen, Karri and
+                  Bowell, Edward     },
+  title = 	 {{Asteroid orbit determination using Bayesian probabilities}},
+  journal = 	 {Icarus},
+  year = 	 {1993},
+  OPTkey = 	 {},
+  volume = 	 {104},
+  number = 	 {2},
+  pages = 	 {255--279},
+  month = 	 aug,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui1994a,
+  author = 	 {Muinonen, Karri  and
+                  Bowell, Edward   and
+                  Wasserman, L. H.    },
+  title = 	 {Orbital uncertainties of single-apparition asteroids},
+  journal = 	 {Planet. Space Sci.},
+  year = 	 {1994},
+  OPTkey = 	 {},
+  volume = 	 {42},
+  number = 	 {},
+  pages = 	 {307--313},
+  month = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui1996a,
+  author = 	 {Muinonen, Karri},
+  title = 	 {Orbital covariance eigenproblem for asteroids and comets},
+  journal = 	 {Mon. Not. R. Astron. Soc.},
+  year = 	 {1996},
+  OPTkey = 	 {},
+  volume = 	 {280},
+  OPTnumber = 	 {},
+  pages = 	 {1235--1238},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui1998a,
+  author = 	 {Muinonen, Karri},
+  title = 	 {{Discovery and follow-up simulations for small Earth-crossing asteroids}},
+  journal = 	 {Planet. Space Sci.},
+  year = 	 {1998},
+  OPTkey = 	 {},
+  volume = 	 {46},
+  OPTnumber = 	 {},
+  pages = 	 {291--297},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui1999a,
+  author = 	 {Muinonen, Karri},
+  title = 	 {Asteroid and comet encounters with the Earth},
+  booktitle = 	 {{The Dynamics of Small Bodies in the Solar System}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {127--158},
+  year = 	 {1999},
+  editor = 	 {Steves, B. A. and
+                  Roy, A. E        },
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Dordrecht Norwell, MA},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher = {Kluwer Academic},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui1999b,
+  author = 	 {Muinonen, Karri},
+  title = 	 {{Asteroid and Comet Encounters with the Earth. Impact Hazard and Collission Probability}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {{The Dynamics of Small Bodies in the Solar System}},
+  pages = 	 {127--158},
+  year = 	 {1999},
+  editor = 	 {Steves, B. A. and
+                  Roy, A. E.},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  organization = {NATO ASI},
+  publisher = {Kluwer Academic Publishers},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui2001a,
+  author = 	 {Muinonen, Karri and
+                  Virtanen, Jenni and
+                  Bowell, Edward     },
+  title = {{Collision probability for Earth-crossing asteroids using
+  orbital ranging}},
+  journal = 	 {Cel. Mech. Dyn. Astron.},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {81},
+  number = 	 {1--2},
+  pages = 	 {93--101},
+  month = 	 sep,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui2003a,
+  author = 	 {Muinonen, Karri     and
+                  Piironen, Jukka     and
+                  Shkuratov, Yurij G. and
+                  Ovcharenko, Andrej  and
+                  Clark, Beth E.},
+  booktitle = 	 {{Asteroids III}},
+  title = 	 {{Asteroid Photometric and Polarimetric Phase Effects}},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {123--138},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui2005a,
+  author = 	 {Muinonen, Karri  and
+                  Virtanen, Jenni  and
+                  Granvik, Mikael  and
+                  Laakso, Teemu},
+  title = {{Asteroid orbits with Gaia: inversion and prediction}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Three-Dimensional Universe with Gaia}},
+  pages = 	 {223--230},
+  year = 	 {2005},
+  editor = 	 {Perryman, Michael},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {Special Publications SP-576},
+  address = 	 {Noordwijk},
+  OPTmonth = 	 {},
+  organization = {ESA},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui2005b,
+  author = 	 {Muinonen, Karri   and
+                  Rantala, Jari     and
+                  Granvik, Mikael},
+  title = 	 {Exoplanet discovery and orbit computation using radial velocity data},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Research seminar: "Exoplanets and astrobiology"},
+  OPTpages = 	 {},
+  year = 	 {2005},
+  editor = 	 {Jetsu, Lauri and
+                  Palviainen, Asko},
+  volume = 	 {3},
+  OPTnumber = 	 {},
+  series = 	 {Observatory Report 2005},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  organization = {University of Helsinki},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{mui2006a,
+  author = 	 {Muinonen, Karri  and
+                  Virtanen, Jenni  and
+                  Granvik, Mikael  and
+                  Laakso, Teemu},
+  title = 	 {Asteroid orbits using phase-space volumes of variation},
+  journal = 	 {Mon. Not. R. Astron. Soc.},
+  year = 	 {2006},
+  OPTkey = 	 {},
+  volume = 	 {368},
+  number = 	 {2},
+  pages = 	 {809--818},
+  month = 	 {May},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{mui2006b,
+  author = 	 {Muinonen, Karri          and
+                  Torppa, Johanna          and
+                  Virtanen, Jenni          and
+                  Näränen, Jyri            and
+                  Niemelä, Jarkko          and
+                  Granvik, Mikael          and
+                  Laakso, Teemu            and
+                  Parviainen, Hannu        and
+                  Aksnes, Kaare            and
+                  Dai, Zhang               and
+                  Lagerkvist, Claes-Ingvar and
+                  Rickman, Hans            and
+                  Karlsson, Ola            and
+                  Hahn, Gerhard            and
+                  Michelsen, Ren\'e        and
+                  Grav, Tommy              and
+                  Pravec, Petr             and
+                  J{\o}rgensen, Uffe Gråe},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  title = 	 {{Spins, shapes, and orbits for near-Earth objects by Nordic NEON}},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {2006b},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlicky, David},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  OPTtype = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTpages = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{new1687a,
+  author = 	 {Newton, Isaac},
+  ALTeditor = 	 {},
+  title = 	 {Philosophiae naturalis principia mathematica},
+  OPTpublisher = {},
+  year = 	 {1687},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {Colonia},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{nes2002a,
+  author = 	 {Nesvorn\'y, David      and
+                  Bottke Jr., William F. and
+                  Dones, Luke            and
+                  Levison, Harold F         },
+  title = 	 {The recent breakup of an asteroid in the main-belt region},
+  journal = 	 {Nature},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  volume = 	 {417},
+  number = 	 {6890},
+  pages = 	 {720--722},
+  month = 	 jun,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{nes2004a,
+  author = 	 {Nesvorn\'y, David      and
+                  Bottke, William F.        },
+  title = {{Detection of the Yarkovsky effect for main-belt
+  asteroids}},
+  journal = 	 {Icarus},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {170},
+  OPTnumber = 	 {},
+  pages = 	 {324--342},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{oor1950a,
+  author = 	 {Oort, J. H.},
+  title = {The structure of the cloud of comets surrounding the solar
+  system and a hypothesis concerning its origin},
+  journal = 	 {Bull. Astron. Inst. Netherlands},
+  year = 	 {1950},
+  OPTkey = 	 {},
+  volume = 	 {11},
+  number = 	 {408},
+  pages = 	 {91--110},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InBook{ost1989a,
+  author = 	 {Ostro, S. J.},
+  editor = 	 {Binzel, Richard P.        and
+                  Gehrels, Tom              and
+                  Matthews, Mildred Shapley    },
+  title = 	 {Asteroids II},
+  chapter = 	 {`Radar observations of asteroids'},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {1989},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {192--212},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+
+@Article{pet2004a,
+  author = 	 {{Petit}, J.-M.  and 
+                  {Holman}, M.    and
+                  {Scholl}, H .   and
+                  {Kavelaars}, J. and
+                  {Gladman}, B.},
+  title = 	 "{A highly automated moving object detection package}",
+  journal = 	 {Mon. Not. R. Astron. Soc.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {347},
+  OPTnumber = 	 {},
+  pages = 	 {471--480},
+  month = 	 jan,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{ric2005a,
+  author = 	 {Rickman, Hans},
+  title = 	 {{Transport of comets to the Inner Solar System}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Dynamics of Populations of Planetary Systems}},
+  pages = 	 {277--288},
+  year = 	 {2005},
+  editor = 	 {Kne{\v z}evi{\' c}, Zoran and
+                  Milani, Andrea},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Colloquium \#197},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Colloquium \#197},
+  publisher =    {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{san2007a,
+  author = 	 {Sansaturio, Maria E. and
+                  Arratia, O.},
+  title = {Single and multiple solution algorithms to scan asteroid
+  databases for identifications},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  pages = 	 {269--280},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  publisher = {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{sch1982a,
+  author = 	 {Schmadel, L. D.},
+  title = 	 {{Catalogue of minor planet identities. I. Identities with planets (1)-(2297)}},
+  journal = 	 {Astron. Astrophys. Suppl. Ser.},
+  year = 	 {1982},
+  OPTkey = 	 {},
+  volume = 	 {49},
+  OPTnumber = 	 {},
+  pages = 	 {691--707},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{sit1983a,
+  author = 	 {Sitarski, G.},
+  title = 	 {Effects of General Relativity in the Motion of Minor Planets and Comets},
+  journal = 	 {Acta Astronomica},
+  year = 	 {1983},
+  OPTkey = 	 {},
+  volume = 	 {33},
+  number = 	 {2},
+  pages = 	 {295--304},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{sou1963a,
+  author = 	 {Southworth, R. B. and
+                  Hawkins, G. S.       },
+  title =        {{Statistics of Meteor Streams}},
+  journal = 	 {Smiths. Contr. Astrophys.},
+  year = 	 {1963},
+  OPTkey = 	 {},
+  volume = 	 {7},
+  OPTnumber = 	 {},
+  pages = 	 {261--285},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{sta1990a,
+  author = 	 {Standish, E. M.},
+  title = {{The observational basis for JPL's DE 200, the planetary
+  ephemerides of the Astronomical Almanac}},
+  journal = 	 {Astron. Astrophys.},
+  year = 	 {1990},
+  OPTkey = 	 {},
+  volume = 	 {233},
+  OPTnumber = 	 {},
+  pages = 	 {252--271},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@TechReport{sta1998a,
+  author = 	 {Standish, E. M.},
+  title =        {{JPL Planetary and Lunar Ephemerides, DE405/LE405}},
+  institution =  {Jet Propulsion Laboratory},
+  year = 	 {1998},
+  OPTkey = 	 {},
+  type = 	 {Interoffice Memorandum},
+  number = 	 {312.F-98-048},
+  OPTaddress = 	 {},
+  month = 	 aug,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{sta2004a,
+  author = 	 {Standish, E. M.},
+  title = {{An approximation to the errors in the planetary
+ephemerides of the Astronomical Almanac}},
+  journal = 	 {Astron. Astrophys.},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  volume = 	 {417},
+  OPTnumber = 	 {},
+  pages = 	 {1165--1171},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InBook{sto2003a,
+  author = 	 {Stokes, Grant H.   and
+                  Evans, Jenifer B.  and
+                  Larson, Stephen M.    },
+  editor = 	 {Bottke, William    and
+                  Cellino, Alberto   and
+                  Paolicchi, Paolo   and 
+                  Binzel, Richard P.    },
+  title = 	 {Asteroids III},
+  chapter = 	 {`{N}ear-{E}arth {A}steroid {S}earch {P}rograms'},
+  publisher = 	 {University of Arizona Press},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {45--54},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{stu2001a,
+  author = 	 {Stuart, Joseph Scott},
+  title = {{A Near-Earth Asteroid Population Estimate from the LINEAR
+  Survey}},
+  journal = 	 {Science},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {294},
+  number = 	 {5547},
+  pages = 	 {1691--1693},
+  month = 	 nov,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{ted2000a,
+  author = 	 {Tedesco, Edward F. and
+                  Muinonen, Karri    and
+                  Price, Stephan D.     },
+  title = {{Space-based infrared near-Earth asteroid survey
+  simulation}},
+  journal = 	 {Planet. Space Sci.},
+  year = 	 {2000},
+  OPTkey = 	 {},
+  volume = 	 {48},
+  OPTnumber = 	 {},
+  pages = 	 {801--816},
+  month = 	 apr,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{ted2006a,
+  author = 	 {Tedesco, Edward F. and
+                  Bhattacharya, Bidushi and
+                  Meadows, Victoria S. and
+                  Jones, Lynne and
+                  Davis, Don R. and 
+                  Cellino, Alberto and
+                  Delbo, Marco and
+                  Saba, Laura and
+                  Granvik, Mikael and
+                  Muinonen, Karri},
+  title = {{Spitzer-CFHT-VLT project}},
+  OPTjournal = 	 {Planet. Space Sci.},
+  year = 	 {2006},
+  OPTkey = 	 {},
+  OPTvolume = 	 {48},
+  OPTnumber = 	 {},
+  OPTpages = 	 {801--816},
+  OPTmonth = 	 apr,
+  note = 	 {In preparation},
+  OPTannote = 	 {}
+}
+
+@Article{tom2007a,
+  author = 	 {Tommei, G. and 
+                  Milani, A. and
+                  Rossi, A.},
+  title = 	 {Orbit determination of space debris: admissible regions},
+  journal = 	 {Cel. Mech. Dyn. Astron.},
+  year = 	 {2007},
+  OPTkey = 	 {},
+  volume = 	 {97},
+  OPTnumber = 	 {},
+  pages = 	 {289--304},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{tor2006a,
+  author = 	 {Torppa, Johanna         and
+                  Virtanen, Jenni         and
+                  Muinonen, Karri         and
+                  Laakso, Teemu           and
+                  Niemel\"a, Jarkko       and
+                  N\"ar\"anen, Jyri       and
+                  Granvik, Mikael         and
+                  Aksnes, Kaare           and
+                  Dai, Zheng              and
+                  Lagerkvist, Clas-Ingvar and
+                  Rickman, Hans           and
+                  Hahn, Gerhard           and
+                  Michelsen, Rene         and
+                  Grav, Tommy             and
+                  J\"orgensen, U-G},
+  title = {{Physical and Dynamical Properties of Near-Earth Objects:
+            first results from Nordic NEON}},
+  journal = 	 {Icarus},
+  year = 	 {2006},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTpages = 	 {},
+  OPTmonth = 	 {},
+  note = 	 {submitted},
+  OPTannote = 	 {}
+}
+
+@InProceedings{val2005a,
+  author = 	 {Valsecchi, Giovanni B.  and
+                  Rossi, A.               and
+                  Milani, Andrea          and
+                  Chesley, Steve R.},
+  title = 	 {{The size of collision solutions in orbital elements space}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Dynamics of Populations of Planetary Systems},
+  pages = 	 {249--254},
+  year = 	 {2005},
+  editor = 	 {Kne{\v z}evi{\' c}, Zoran  and
+                  Milani, Andrea},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Colloquium \#197},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Colloquium \#197},
+  publisher =    {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+
+@InProceedings{val2007a,
+  author = 	 {Valsecchi, Giovanni B.},
+  title = 	 {236 years ago...},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = 	 {{Near Earth Objects, our Celestial Neighbors: Opportunity and Risk}},
+  pages = 	 {xvii--xx},
+  year = 	 {2007},
+  editor = 	 {Milani, Andrea         and
+                  Valsecchi, Giovanni B. and
+                  Vokrouhlick\'y, David},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Symposium \#236},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Symposium \#236},
+  publisher = 	 {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{vir2001a,
+  author = 	 {Virtanen, Jenni and
+                  Muinonen, Karri and
+                  Bowell, Edward     },
+  title = 	 {{Statistical Ranging of Asteroid Orbits}},
+  journal = 	 {Icarus},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  volume = 	 {154},
+  number = 	 {2},
+  pages = 	 {412--431},
+  month = 	 dec,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{vir2003a,
+  author = 	 {Virtanen, Jenni   and 
+                  Tancredi, Gonzalo and 
+                  Muinonen, Karri   and 
+                  Bowell, Edward       },
+  title = 	 {Orbit computation for transneptunian objects},
+  journal = 	 {Icarus},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  volume = 	 {161},
+  number = 	 {2},
+  pages = 	 {419--430},
+  month = 	 feb,
+  optnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{vir2005a,
+  author = 	 {Virtanen, Jenni  and 
+                  Muinonen, Karri  and
+                  Mignard, Francois},
+  title =        {{Asteroid orbits with Gaia: simulated examples}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {{Three-Dimensional Universe with Gaia}},
+  pages = 	 {325--328},
+  year = 	 {2005a},
+  editor = 	 {Perryman, Michael},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {Special Publications SP-576},
+  address = 	 {Noordwijk},
+  OPTmonth = 	 {},
+  organization = {ESA},
+  OPTpublisher = {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{vir2005b,
+  author = 	 {Virtanen, Jenni   and
+                  Muinonen, Karri   and
+                  Granvik, Mikael   and
+                  Laakso, Teemu},
+  title = 	 {{Collision orbits and phase transition for 2004 AS$_1$ at discovery}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Dynamics of Populations of Planetary Systems},
+  pages = 	 {239--248},
+  year = 	 {2005},
+  editor = 	 {Kne{\v z}evi{\' c}, Zoran  and
+                  Milani, Andrea},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {IAU Colloquium \#197}},
+  address = 	 {Cambridge, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {Proceedings of IAU Colloquium \#197},
+  publisher =    {Cambridge University Press},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
+
+@PhdThesis{vir2005c,
+  author = 	 {Virtanen, Jenni},
+  title = 	 {Asteroid orbital inversion using statistical methods},
+  school = 	 {University of Helsinki},
+  year = 	 {2005},
+  OPTkey = 	 {},
+  OPTtype = 	 {},
+  OPTaddress = 	 {Finland},
+  month = 	 {June},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{vir2006a,
+  author = 	 {Virtanen, Jenni and
+                  Muinonen, Karri},
+  title = {Time evolution of orbital uncertainties at discovery for
+  the impactor candidate 2004 {AS}$_1$},
+  journal = 	 {Icarus},
+  year = 	 {2006},
+  OPTkey = 	 {},
+  volume = 	 {184},
+  number = 	 {2},
+  pages = 	 {289--301},
+  month = 	 {October},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InCollection{vir2008a,
+  author = 	 {Virtanen, Jenni    and
+                  Tancredi, Gonzalo  and
+                  Bernstein, Gary M. and
+                  Spahr, Timothy     and
+                  Muinonen, Karri},
+  title = 	 {{Transneptunian Orbit Computation}},
+  booktitle = 	 {{The Solar System Beyond Neptune}},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  pages = 	 {25--40},
+  publisher = {University of Arizona Press},
+  year = 	 {2008},
+  editor = 	 {Barucci, M. A.    and
+                  Boehnhardt, H.    and
+                  Cruikshank, D. P. and
+                  Morbidelli, A.},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTtype = 	 {},
+  OPTchapter = 	 {},
+  address = 	 {Tucson},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{vai1939a,
+  author = 	 {V\"ais\"al\"a, Yrj\"o},
+  title = 	 {{Eine einfache Methode der Bahnbestimmung}},
+  journal = 	 {Mitt. Sternw. Univ. Turku, Suomalainen Tiedeakatemia},
+  year = 	 {1939},
+  OPTkey = 	 {},
+  volume = 	 {1},
+  OPTnumber = 	 {},
+  pages = 	 {1--32},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{yeo1994a,
+  author = 	 {Yeomans, Donald K. and
+                  Chodas, Paul W.},
+  editor = 	 {Gehrels, T., and
+                  Matthews, M. S. and
+                  Schumann, A.},
+  title = 	 {Hazards due to comets and asteroids},
+  chapter = 	 {{Predicting Close Approaches of Asteroids and Comets to Earth}},
+  publisher = 	 {{University of Arizona Press}},
+  year = 	 {1994},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  series = 	 {{Space Science Series}},
+  OPTtype = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  pages = 	 {241},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
Index: trunk/mops/oorb/doc/educational.bib
===================================================================
--- trunk/mops/oorb/doc/educational.bib	(revision 34646)
+++ trunk/mops/oorb/doc/educational.bib	(revision 34646)
@@ -0,0 +1,262 @@
+@Book{cor2003a,
+  author = 	 {Cormen, Thomas H.     and
+                  Leiserson, Charles E. and
+                  Rivest, Ronald L.     and
+                  Stein, Clifford},
+  title = 	 {Introduction to Algorithms},
+  publisher = 	 {MIT Press},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Cambridge, Massachusetts, USA},
+  edition = 	 {2},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{dan1992a,
+  author = 	 {Danby, J. M. A.},
+  title = 	 {Fundamentals of Celestial Mechanics},
+  publisher = 	 {Willman-Bell, Inc.},
+  year = 	 {1992},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Richmond, Virginia, U.S.A.},
+  edition = 	 2,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{dub1961a,
+  author = 	 {Dubyago, A. D.},
+  title = 	 {The determination of orbits},
+  publisher = 	 {The Macmillan Company},
+  year = 	 {1961},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {New York, USA},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  note = {{English translation by R. D. Burke, G. Gordon,
+  L. N. Rowell, and F. T. Smith}},
+  OPTannote = 	 {}
+}
+
+@Book{ega1975a,
+  author = 	 {Egan, J. P.},
+  ALTeditor = 	 {},
+  title = 	 {Signal Detection Theory and ROC Analysis},
+  publisher = 	 {Academic Press},
+  year = 	 {1975},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {New York},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{gau1809a,
+  author = 	 {Gauss, Carl Friedrich},
+  title = 	 {{Theoria motus corporum coelisticum in sectionibus conicis solem ambientum}},
+  publisher = 	 {Perthes und Besser},
+  year = 	 {1809},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Hamburg},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  note = 	 {English translation by C.\ H.\ Davis (1857); reprint by Dover, New York (1963)},
+  OPTannote = 	 {}
+}
+
+@Book{gre1985a,
+  author = 	 {Green, Robin M.},
+  ALTeditor = 	 {},
+  title = 	 {Spherical Astronomy},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {1985},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Cambridge, UK},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{kai2004a,
+  author = 	 {Kaipio, Jari and
+                  Somersalo, Erkki},
+  editor = 	 {Antman, S. S.  and
+                  Marsden, J. E. and
+                  Sirovich, L.},
+  title = 	 {{Statistical and Computational Inverse Problems}},
+  publisher = 	 {Springer},
+  year = 	 {2004},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{kar1994a,
+  author = 	 {Karttunen, Hannu},
+  title = 	 {Datan käsittely},
+  publisher = 	 {CSC - Tieteellinen laskenta Oy},
+  year = 	 {1994},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Espoo, Finland},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{leh1988a,
+  author = 	 {Lehtinen, Markku S.},
+  title = 	 {On statistical inversion theory},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle =    {Theory and Applications of Inverse Problems},
+  pages = 	 {46--57},
+  year = 	 {1988},
+  editor = 	 {Haario, H.},
+  volume = 	 {167},
+  OPTnumber = 	 {},
+  series = 	 {Pitman Res. Notes in Math. Ser.},
+  address = 	 {Harlow, UK},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher =    {Longman Scientific and Technical},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{kar2001a,
+  author = 	 {Karttunen, Hannu},
+  title = 	 {Johdatus taivaanmekaniikkaan},
+  publisher = 	 {Tähtitieteellinen yhdistys Ursa ry},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Helsinki, Finland},
+  OPTedition = 	 {},
+  OPTmonth = 	 oct,
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{kar2003a,
+  author = 	 {Karttunen, Hannu   and
+                  Donner, Karl Johan and
+                  Kröger, Pekka      and
+                  Oja, Heikki        and
+                  Poutanen, Markku      },
+  title = 	 {Tähtitieteen perusteet},
+  publisher = 	 {Tähtitieteellinen yhdistys Ursa ry},
+  year = 	 {2003},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Helsinki, Finland},
+  edition = 	 4,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{mar1984a,
+  author = 	 {Markkanen, Tapio  and
+                  Linnaluoto, Seppo and
+                  Poutanen, Markku},
+  title = 	 {Tähtitieteen vaiheita Helsingin yliopistossa: observatorio 150 vuotta},
+  publisher = 	 {University of Helsinki},
+  year = 	 {1984},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTedition = 	 {},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  url = 	 {http://www.astro.helsinki.fi/vaiheet/}
+}
+
+@Book{roy1988a,
+  author = 	 {Roy, A. E.},
+  title = 	 {{O}rbital {M}otion},
+  publisher = 	 {Institute of Physics Publishing},
+  year = 	 {1988},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Bristol},
+  edition = 	 3,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Article{nel1965a,
+  author = 	 {Nelder, J. A. and
+                  Mead, R.},
+  title = 	 {A simplex method for function minimization},
+  journal = 	 {Computer Journal},
+  year = 	 {1965},
+  OPTkey = 	 {},
+  volume = 	 {7},
+  number = 	 {4},
+  pages = 	 {308--313},
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@InProceedings{spa1989a,
+  author = 	 {Spackman, Kent A.},
+  title = 	 {Signal detection theory: valuable tools for evaluating inductive learning},
+  OPTcrossref =  {},
+  OPTkey = 	 {},
+  booktitle = {Proceedings of the sixth international workshop on Machine learning},
+  pages = 	 {160--163},
+  year = 	 {1989},
+  OPTeditor = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  OPTmonth = 	 {},
+  OPTorganization = {},
+  publisher = {Morgan Kaufmann Publishers Inc.},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
Index: trunk/mops/oorb/doc/fortran.bib
===================================================================
--- trunk/mops/oorb/doc/fortran.bib	(revision 34646)
+++ trunk/mops/oorb/doc/fortran.bib	(revision 34646)
@@ -0,0 +1,87 @@
+@Misc{dec1997a,
+  OPTkey = 	 {},
+  author = 	 {Decyk, Viktor K.       and
+                  Norton, Charles D.     and
+                  Szymanski, Boleslaw K.    },
+  title = 	 {Introduction to {O}bject-{O}riented {C}oncepts using {F}ortran90},
+  howpublished = {\url{http://exodus.physics.ucla.edu/Fortran95/}},
+  OPTmonth = 	 {},
+  year = 	 {1997},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{haa2001a,
+  author = 	 {Haataja, Juha     and
+                  Rahola, Jussi     and
+                  Ruokolainen, Juha    },
+  title = 	 {Fortran 90/95},
+  publisher = 	 {CSC - Tieteellinen laskenta Oy},
+  year = 	 {2001},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Espoo, Finland},
+  edition = 	 3,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{met2002a,
+  author = 	 {Metcalf, Michael and
+                  Reid, John          },
+  title = 	 {Fortran 90/95 explained},
+  publisher = 	 {Oxford University Press},
+  year = 	 {2002},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  edition = 	 2,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{pre1992a,
+  author = 	 {Press, William H.      and
+                  Teukolsky, Saul A.     and
+                  Vetterling, William T. and
+                  Flannery, Brian P.        },
+  title = 	 {Numerical {R}ecipes in {F}ortran --- {T}he {A}rt of {S}cientific {C}omputing},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {1992},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  address = 	 {Cambridge, UK},
+  edition = 	 2,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+@Book{pre1999a,
+  author = 	 {Press, William H.      and
+                  Teukolsky, Saul A.     and
+                  Vetterling, William T. and
+                  Flannery, Brian P.        },
+  title = 	 {Numerical {R}ecipes in {F}ortran 90 --- {T}he {A}rt of \emph{{P}arallel} {S}cientific {C}omputing},
+  publisher = 	 {Cambridge University Press},
+  year = 	 {1999},
+  OPTkey = 	 {},
+  OPTvolume = 	 {},
+  OPTnumber = 	 {},
+  OPTseries = 	 {},
+  OPTaddress = 	 {},
+  edition = 	 2,
+  OPTmonth = 	 {},
+  OPTnote = 	 {},
+  OPTannote = 	 {}
+}
+
+
Index: trunk/mops/oorb/doc/harvard.sty
===================================================================
--- trunk/mops/oorb/doc/harvard.sty	(revision 34646)
+++ trunk/mops/oorb/doc/harvard.sty	(revision 34646)
@@ -0,0 +1,270 @@
+%% harvard.sty - harvard bibliography style Version 2.0.5
+%% Author: Peter Williams peterw@archsci.arch.su.edu.au
+%% Copyright: Peter Williams 1994
+\NeedsTeXFormat{LaTeX2e}
+\ProvidesPackage{harvard}
+\RequirePackage{ifthen}
+\IfFileExists{html.sty}{\RequirePackage{html}
+\newcommand{\harvardurl}[1]{\htmladdnormallink*{\textbf{URL:} \textit{##1}}{##1}}
+}{
+\newcommand{\harvardurl}[1]{\textbf{URL:} \textit{##1}}
+}
+\DeclareOption{full}{\citationmode{full}}
+\DeclareOption{abbr}{\citationmode{abbr}}
+\DeclareOption{default}{\citationmode{default}}
+\DeclareOption{agsmcite}{\citationstyle{agsm}}
+\DeclareOption{dcucite}{\citationstyle{dcu}}
+\DeclareOption{round}{\harvardparenthesis{round}\harvardyearparenthesis{round}}
+\DeclareOption{curly}{\harvardparenthesis{curly}\harvardyearparenthesis{curly}}
+\DeclareOption{angle}{\harvardparenthesis{angle}\harvardyearparenthesis{angle}}
+\DeclareOption{square}{\harvardparenthesis{square}\harvardyearparenthesis{square}}
+\DeclareOption{none}{\harvardparenthesis{none}\harvardyearparenthesis{none}}
+\DeclareOption*{
+  \global\edef\HAR@tmp{\CurrentOption}
+%% Berwin A. Turlach <berwin@alphasun.anu.edu.au>
+  \AtEndDocument{\bibliographystyle{\HAR@tmp}}
+}
+
+%% Kristoffer H. Rose <kris@diku.dk> 1995/03/01:
+%%   do not expand macros in citations: put definitions on .aux file instead.
+{\catcode`\:=12 \catcode`\-=12 \catcode`\>=12 \catcode`\<=12 %
+ \gdef\codeof#1{\expandafter\codeof@\meaning#1<-:}%
+ \gdef\codeof@#1:->#2<-:{#2}}
+
+\def\harvardpreambletext{\catcode`\#=12 \harvardpreambletext@}
+\def\harvardpreambletext@#1{\def\next{#1}\catcode`\#=6 %
+  \immediate\write\@auxout{\string\harvardpreambledefs{%
+      \string\AtBeginDocument{\codeof\next}}}}
+
+\def\harvardpreambledefs#1{#1\gdef\harvardpreambledefs##1{}}
+
+\newcommand{\harvarditem}[4][\null]{\item[]%
+\if@filesw{ \def\protect##1{\string ##1\space}%
+\ifthenelse{\equal{#1}{\null}}
+  {\def\next{{#4}{#2}{#2}{#3}}}
+  {\def\next{{#4}{#2}{#1}{#3}}}
+\immediate\write\@auxout{\string\harvardcite\codeof\next}%
+}\fi%
+\protect\hspace*{-\labelwidth}\protect\hspace*{-\labelsep}\ignorespaces%
+}
+
+\newcommand{\harvardcite}[4]{
+  \global\@namedef{HAR@fn@#1}{#2}
+  \global\@namedef{HAR@an@#1}{#3}
+  \global\@namedef{HAR@yr@#1}{#4}
+  \global\@namedef{HAR@df@#1}{\csname HAR@fn@#1\endcsname}
+}
+
+\newcommand{\citationmode}[1]{
+  \renewcommand{\HAR@citemode}{\csname HAR@cite@#1\endcsname}
+}
+
+\newcommand{\HAR@cite@full}{HAR@fn@}
+\newcommand{\HAR@cite@abbr}{HAR@an@}
+\newcommand{\HAR@cite@default}{HAR@df@}
+\newcommand{\HAR@citemode}{\HAR@cite@default}
+
+\newcommand{\HAR@citetoaux}[1]{%
+  \if@filesw\immediate\write\@auxout{\string\citation{#1}}\fi%
+}
+
+\newcommand{\HAR@checkdef}[2]{\@ifundefined{HAR@df@#1}%
+  {\textbf{?}\@warning{Citation '#1' on page \thepage \space undefined}}%
+  {#2}%
+}
+
+\newcommand{\HAR@dolist}[2]{\def\@citea{\null}\@for\@citeb:=#1\do%
+{\@citea\def\@citea{\HAR@hisep\penalty\@m\ }\HAR@checkdef{\@citeb}%
+{#2{\@citeb}\HAR@hysep\penalty\@m\ %
+\HAR@year{\@citeb}\HAR@setd{\@citeb}}}%
+}
+
+\def\@enamedef#1{\expandafter\def\csname #1\expandafter\endcsname\expandafter}
+\newcommand{\HAR@name}[1]{\csname \HAR@citemode#1\endcsname}
+\newcommand{\HAR@fname}[1]{\csname HAR@fn@#1\endcsname}
+\newcommand{\HAR@aname}[1]{\csname HAR@an@#1\endcsname}
+\newcommand{\HAR@year}[1]{\csname HAR@yr@#1\endcsname}
+\newcommand{\HAR@setd}[1]{%
+\global\@enamedef{HAR@df@#1}{\csname HAR@an@#1\endcsname}%
+}
+
+%% Berwin A. Turlach <berwin@alphasun.anu.edu.au>
+\global\@namedef{HAR@df@*}{\csname HAR@fn@*\endcsname}
+\renewcommand{\nocite}[1]{\HAR@citetoaux{#1}%
+\@for\@citeb:=#1\do%
+{\HAR@checkdef{\@citeb}{}}}%
+
+\renewcommand{\cite}{\@ifstar{\@ifstar{\HAR@acite}{\HAR@fcite}}{\HAR@dcite}}
+
+\newcommand{\HAR@dcite}[2][\null]{\HAR@citetoaux{#2}%
+{\harvardleft\HAR@dolist{#2}{\HAR@name}\ifthenelse{\equal{#1}{\null}}%
+  {}{, #1}\harvardright}%
+}
+
+\newcommand{\HAR@acite}[2][\null]{\HAR@citetoaux{#2}%
+{\harvardleft\HAR@dolist{#2}{\HAR@aname}\ifthenelse{\equal{#1}{\null}}%
+  {}{, #1}\harvardright}%
+}
+
+\newcommand{\HAR@fcite}[2][\null]{\HAR@citetoaux{#2}%
+{\harvardleft\HAR@dolist{#2}{\HAR@fname}\ifthenelse{\equal{#1}{\null}}%
+  {}{, #1}\harvardright}%
+}
+
+\newcommand{\citeaffixed}{\@ifstar{\@ifstar{\HAR@aciteaff}{\HAR@fciteaff}}%
+{\HAR@dciteaff}%
+}
+
+\newcommand{\HAR@fciteaff}[3][\null]{\HAR@citetoaux{#2}%
+{\harvardleft#3\ \HAR@dolist{#2}{\HAR@fname}\ifthenelse{\equal{#1}{\null}}%
+    {}{, #1}\harvardright}%
+}
+
+\newcommand{\HAR@aciteaff}[3][\null]{\HAR@citetoaux{#2}%
+{\harvardleft#3\ \HAR@dolist{#2}{\HAR@aname}\ifthenelse{\equal{#1}{\null}}%
+    {}{, #1}\harvardright}%
+}
+
+\newcommand{\HAR@dciteaff}[3][\null]{\HAR@citetoaux{#2}%
+{\harvardleft#3\ \HAR@dolist{#2}{\HAR@name}\ifthenelse{\equal{#1}{\null}}%
+    {}{, #1}\harvardright}%
+}
+
+\newcommand{\citeasnoun}{\@ifstar{\@ifstar{\HAR@aciteasn}{\HAR@fciteasn}}%
+{\HAR@dciteasn}%
+}
+
+\newcommand{\HAR@fciteasn}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@fname{#2}\ \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\HAR@aciteasn}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@aname{#2}\ \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\HAR@dciteasn}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@name{#2}\ \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\possessivecite}{\@ifstar{\@ifstar{\HAR@acitepos}{\HAR@fcitepos}}%
+{\HAR@dcitepos}%
+}
+
+\newcommand{\HAR@fcitepos}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@fname{#2}'s \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\HAR@acitepos}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@aname{#2}'s \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\HAR@dcitepos}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@name{#2}'s \harvardyearleft\HAR@year{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{, #1}\harvardyearright}\HAR@setd{#2}}%
+}
+
+\newcommand{\citename}{\@ifstar{\@ifstar{\HAR@acitenam}\HAR@fcitenam}%
+{\HAR@dcitenam}%
+}
+
+\newcommand{\HAR@fcitenam}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@fname{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{\ \harvardleft#1\harvardright}}}%
+}
+
+\newcommand{\HAR@acitenam}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@aname{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{\ \harvardleft#1\harvardright}}}%
+}
+
+\newcommand{\HAR@dcitenam}[2][\null]{\HAR@citetoaux{#2}\HAR@checkdef{#2}{%
+{\HAR@name{#2}\ifthenelse{\equal{#1}{\null}}
+    {}{\ \harvardleft#1\harvardright}}}%
+}
+
+\newcommand{\citeyear}{\@ifstar{\HAR@citeyrnb}{\HAR@citeyr}}
+
+\newcommand{\HAR@citeyrnb}[2][\null]{\HAR@citetoaux{#2}%
+{\def\@citea{\null}\@for\@citeb:=#2\do%
+{\@citea\def\@citea{\HAR@hisep\penalty\@m\ }\HAR@checkdef{\@citeb}%
+{\HAR@year{\@citeb}}}\ifthenelse{\equal{#1}{\null}}%
+{}{, #1}}%
+}
+
+\newcommand{\HAR@citeyr}[2][\null]{\HAR@citetoaux{#2}%
+{\harvardleft\def\@citea{\null}\@for\@citeb:=#2\do%
+{\@citea\def\@citea{\HAR@hisep\penalty\@m\ }\HAR@checkdef{\@citeb}%
+{\HAR@year{\@citeb}}}\ifthenelse{\equal{#1}{\null}}%
+{}{, #1}\harvardright}%
+}
+
+\newcommand{\HAR@hysep@apsr}{\null}
+\newcommand{\HAR@hisep@apsr}{;}
+\newcommand{\HAR@hysep@agsm}{\null}
+\newcommand{\HAR@hisep@agsm}{,}
+\newcommand{\HAR@hysep@dcu}{,}
+\newcommand{\HAR@hisep@dcu}{;}
+\newcommand{\HAR@and@agsm}{\&}
+\newcommand{\HAR@and@dcu}{and}
+\newcommand{\HAR@and@apsr}{and}
+\newcommand{\HAR@hysep}{\HAR@hysep@agsm}
+\newcommand{\HAR@hisep}{\HAR@hisep@agsm}
+\newcommand{\harvardand}{\HAR@and@agsm}
+\newcommand{\citationstyle}[1]{%
+  \renewcommand{\HAR@hysep}{\csname HAR@hysep@#1\endcsname}
+  \renewcommand{\HAR@hisep}{\csname HAR@hisep@#1\endcsname}
+  \renewcommand{\harvardand}{\csname HAR@and@#1\endcsname}
+}
+
+\newcommand{\HAR@bl@round}{(}
+\newcommand{\HAR@br@round}{)}
+\newcommand{\HAR@bl@square}{[}
+\newcommand{\HAR@br@square}{]}
+\newcommand{\HAR@bl@curly}{\{}
+\newcommand{\HAR@br@curly}{\}}
+\newcommand{\HAR@bl@angle}{$<$}
+\newcommand{\HAR@br@angle}{$>$}
+\newcommand{\HAR@bl@none}{}
+\newcommand{\HAR@br@none}{}
+\newcommand{\harvardleft}{\HAR@bl@round}
+\newcommand{\harvardright}{\HAR@br@round}
+\newcommand{\harvardparenthesis}[1]{
+  \renewcommand{\harvardleft}{\csname HAR@bl@#1\endcsname}
+  \renewcommand{\harvardright}{\csname HAR@br@#1\endcsname}
+  \harvardyearparenthesis{#1}
+}
+
+\newcommand{\harvardyearleft}{\HAR@bl@round}
+\newcommand{\harvardyearright}{\HAR@br@round}
+\newcommand{\harvardyearparenthesis}[1]{
+  \renewcommand{\harvardyearleft}{\csname HAR@bl@#1\endcsname}
+  \renewcommand{\harvardyearright}{\csname HAR@br@#1\endcsname}
+}
+
+\newcommand{\HAR@checkcitations}[4]{
+  \def\HAR@tempa{#2}\expandafter
+  \ifx \csname HAR@fn@#1\endcsname \HAR@tempa
+    \def\HAR@tempa{#3}\expandafter
+    \ifx \csname HAR@an@#1\endcsname \HAR@tempa
+      \def\HAR@tempa{#4}\expandafter
+      \ifx \csname HAR@yr@#1\endcsname \HAR@tempa
+      \else
+        \@tempswatrue
+      \fi
+    \else
+      \@tempswatrue
+    \fi
+  \else
+    \@tempswatrue
+  \fi
+}
+ 
+\AtEndDocument{\renewcommand{\harvardcite}{\HAR@checkcitations}}
+
+\ExecuteOptions{agsm,agsmcite,default,round}
+\ProcessOptions*
Index: trunk/mops/oorb/doc/misc.bib
===================================================================
--- trunk/mops/oorb/doc/misc.bib	(revision 34646)
+++ trunk/mops/oorb/doc/misc.bib	(revision 34646)
@@ -0,0 +1,12 @@
+@Unpublished{dec1997a,
+  author = 	 {Decyk, Viktor K.       and
+                  Norton, Charles D.     and
+                  Szymanski, Boleslaw K.    },
+  title = 	 {'Introduction to {O}bject-{O}riented {C}oncepts using {F}ortran90'},
+  OPTnote = 	 {http://www.cs.rpi.edu/~szymansk/OOF90/F90_Objects.html},
+  OPTkey = 	 {},
+  OPTmonth = 	 {},
+  year = 	 {1997},
+  OPTannote = 	 {}
+}
+
Index: trunk/mops/oorb/doc/web.bib
===================================================================
--- trunk/mops/oorb/doc/web.bib	(revision 34646)
+++ trunk/mops/oorb/doc/web.bib	(revision 34646)
@@ -0,0 +1,49 @@
+{LOWELL_AST,
+  key = 	 {{AST_LOWELL}},
+  OPTauthor = 	 {},
+  title = 	 {{Asteroid Observing Services provided by Lowell Observatory}},
+  URL =          {http://asteroid.lowell.edu/},
+  OPTmonth = 	 {},
+  OPTyear = 	 {},
+  note = 	 {http://asteroid.lowell.edu/},
+  OPTannote = 	 {}
+}
+
+@Misc{MPC,
+  key = 	 {MPC},
+  author = 	 {},
+  OPTtitle = 	 {},
+  URL =          {http://cfa-www.harvard.edu/iau/mpc.html},
+  OPTmonth = 	 {},
+  OPTyear = 	 {},
+  OPTnote = 	 {http://cfa-www.harvard.edu/iau/mpc.html},
+  OPTannote = 	 {}
+}
+
+@Misc{PSPLOT,
+  key = 	 {{Kohler}},
+  author = 	 {Kevin E. Kohler},
+  title = 	 {{PSPLOT --- A Free Fortran-callable PostScript Plotting Library}},
+  URL =          {http://www.nova.edu/ocean/psplot.html},
+  OPTmonth = 	 {},
+  year = 	 {1997},
+  note = 	 {http://www.nova.edu/ocean/psplot.html},
+  OPTannote = 	 {}
+}
+
+@Misc{TNOEPH,
+  key = 	 {{TNOEPH}},
+  author = 	 {Jenni Virtanen and Mikael Granvik},
+  title = 	 {Transneptunian object ephemeris generator {(TNOEPH)}},
+  URL =          {http://asteroid.lowell.edu/cgi-bin/virtanen/tnoeph},
+  month = 	 jan,
+  year = 	 {2003},
+  note = 	 {http://asteroid.lowell.edu/cgi-bin/virtanen/tnoeph},
+  OPTannote = 	 {}
+}
+
+
+
+
+
+
Index: trunk/mops/oorb/gnuplot/cos_plot_car.gp
===================================================================
--- trunk/mops/oorb/gnuplot/cos_plot_car.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/cos_plot_car.gp	(revision 34646)
@@ -0,0 +1,75 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Cartesian phase space.
+#
+# Author:  MG
+# Version: 2011-04-13
+#
+reset
+set terminal postscript eps enhanced linewidth 1.0 8.0
+set out 'cos_results.eps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set lmargin 12
+set rmargin 2
+set tmargin 1
+set bmargin 3
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'x [AU]'
+set ylabel 'y [AU]'
+plot 'cos_orbits.out' using 1:2 pt 7
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'x [AU]'
+set ylabel 'z [AU]'
+plot 'cos_orbits.out' using 1:3 pt 7
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'x [AU]'
+set ylabel 'dx/dt [AU/d]'
+plot 'cos_orbits.out' using 1:4 pt 7
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'x [AU]'
+set ylabel 'dy/dt [AU/d]'
+plot 'cos_orbits.out' using 1:5 pt 7
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'x [AU]'
+set ylabel 'dz/dt [AU/d]'
+plot 'cos_orbits.out' using 1:6 pt 7
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'x [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+set logscale y
+set format y '10^{%L}'
+plot 'cos_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/cos_plot_kep.gp
===================================================================
--- trunk/mops/oorb/gnuplot/cos_plot_kep.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/cos_plot_kep.gp	(revision 34646)
@@ -0,0 +1,75 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Keplerian phase space.
+#
+# Author:  MG
+# Version: 2011-04-13
+#
+reset
+set terminal postscript eps enhanced linewidth 1.0 12.0
+set out 'cos_results.eps'
+unset key
+set pointsize 0.3
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set lmargin 11
+set rmargin 2
+set tmargin 1
+set bmargin 3
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'a [AU]'
+set ylabel 'e'
+plot 'cos_orbits.out' using 1:2 pt 7
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'a [AU]'
+set ylabel '{/Symbol i} [deg]'
+plot 'cos_orbits.out' using 1:3 pt 7
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol O} [deg]'
+plot 'cos_orbits.out' using 1:4 pt 7
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol o} [deg]'
+plot 'cos_orbits.out' using 1:5 pt 7
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'a [AU]'
+set ylabel 'M [deg]'
+plot 'cos_orbits.out' using 1:6 pt 7
+set logscale y
+set format y '10^{%L}'
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'a [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'cos_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/ls_plot.gp
===================================================================
--- trunk/mops/oorb/gnuplot/ls_plot.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/ls_plot.gp	(revision 34646)
@@ -0,0 +1,39 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Part of a Gnuplot script for plotting the elements and uncertainty
+# ellipsoids resulting from a least-squares fit.
+#
+# Author:  MG
+# Version: 2008-08-12
+#
+reset
+set terminal postscript eps enhanced linewidth 1.0 8.0
+set out 'ls_results.eps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set size 0.5,0.33
+set origin 0.0,0.66
Index: trunk/mops/oorb/gnuplot/sor_plot_car.gp
===================================================================
--- trunk/mops/oorb/gnuplot/sor_plot_car.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/sor_plot_car.gp	(revision 34646)
@@ -0,0 +1,75 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Cartesian phase space.
+#
+# Author:  MG
+# Version: 2011-08-18
+#
+reset
+set terminal postscript eps enhanced linewidth 1.0 8.0
+set out 'sor_results.eps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set lmargin 12
+set rmargin 2
+set tmargin 1
+set bmargin 3
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'x [AU]'
+set ylabel 'y [AU]'
+plot 'sor_orbits.out' using 1:2 pt 7
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'x [AU]'
+set ylabel 'z [AU]'
+plot 'sor_orbits.out' using 1:3 pt 7
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'x [AU]'
+set ylabel 'dx/dt [AU/d]'
+plot 'sor_orbits.out' using 1:4 pt 7
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'x [AU]'
+set ylabel 'dy/dt [AU/d]'
+plot 'sor_orbits.out' using 1:5 pt 7
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'x [AU]'
+set ylabel 'dz/dt [AU/d]'
+plot 'sor_orbits.out' using 1:6 pt 7
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'x [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+set logscale y
+set format y '10^{%L}'
+plot 'sor_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/sor_plot_kep.gp
===================================================================
--- trunk/mops/oorb/gnuplot/sor_plot_kep.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/sor_plot_kep.gp	(revision 34646)
@@ -0,0 +1,76 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Keplerian phase space.
+#
+# Author:  MG
+# Version: 2011-08-18
+#
+reset
+set terminal postscript eps enhanced linewidth 1.0 12.0
+set out 'sor_results.eps'
+set logscale x
+unset key
+set pointsize 0.3
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set lmargin 11
+set rmargin 2
+set tmargin 1
+set bmargin 3
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'a [AU]'
+set ylabel 'e'
+plot 'sor_orbits.out' using 1:2 pt 7
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'a [AU]'
+set ylabel '{/Symbol i} [deg]'
+plot 'sor_orbits.out' using 1:3 pt 7
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol O} [deg]'
+plot 'sor_orbits.out' using 1:4 pt 7
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol o} [deg]'
+plot 'sor_orbits.out' using 1:5 pt 7
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'a [AU]'
+set ylabel 'M [deg]'
+plot 'sor_orbits.out' using 1:6 pt 7
+set logscale y
+set format y '10^{%L}'
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'a [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'sor_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/vomcmc_plot_car.gp
===================================================================
--- trunk/mops/oorb/gnuplot/vomcmc_plot_car.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/vomcmc_plot_car.gp	(revision 34646)
@@ -0,0 +1,80 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Cartesian phase space overlaid by the VoV mapping
+# ranges.
+#
+# Author:  MG
+# Version: 2011-10-13
+#
+reset
+set terminal postscript enhanced portrait linewidth 1.0 8.0
+set out 'vomcmc_results.ps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'x [AU]'
+set ylabel 'y [AU]'
+plot 'vomcmc_orbits.out' using 1:2 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:2 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:2:7:8 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'x [AU]'
+set ylabel 'z [AU]'
+plot 'vomcmc_orbits.out' using 1:3 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:3 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:3:9:10 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'x [AU]'
+set ylabel 'dx/dt [AU/d]'
+plot 'vomcmc_orbits.out' using 1:4 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:4 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:4:11:12 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'x [AU]'
+set ylabel 'dy/dt [AU/d]'
+plot 'vomcmc_orbits.out' using 1:5 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:5 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:5:13:14 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'x [AU]'
+set ylabel 'dz/dt [AU/d]'
+plot 'vomcmc_orbits.out' using 1:6 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:6 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:6:15:16 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'x [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'vomcmc_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/vomcmc_plot_kep.gp
===================================================================
--- trunk/mops/oorb/gnuplot/vomcmc_plot_kep.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/vomcmc_plot_kep.gp	(revision 34646)
@@ -0,0 +1,80 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Keplerian phase space overlaid by the VoV mapping
+# ranges.
+#
+# Author:  MG
+# Version: 2011-10-13
+#
+reset
+set terminal postscript enhanced portrait linewidth 1.0 8.0
+set out 'vomcmc_results.ps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'a [AU]'
+set ylabel 'e'
+plot 'vomcmc_orbits.out' using 1:2 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:2 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:2:7:8 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'a [AU]'
+set ylabel 'i [deg]'
+plot 'vomcmc_orbits.out' using 1:3 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:3 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:3:9:10 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol O} [deg]'
+plot 'vomcmc_orbits.out' using 1:4 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:4 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:4:11:12 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol o} [deg]'
+plot 'vomcmc_orbits.out' using 1:5 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:5 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:5:13:14 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'a [AU]'
+set ylabel 'M [deg]'
+plot 'vomcmc_orbits.out' using 1:6 pt 7, \
+'vomcmc_nominal_orbit.out' using 1:6 with points pt 3 ps 3.0, \
+'vomcmc_sampling_grid.out' using 1:6:15:16 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'a [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'vomcmc_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/vov_plot_car.gp
===================================================================
--- trunk/mops/oorb/gnuplot/vov_plot_car.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/vov_plot_car.gp	(revision 34646)
@@ -0,0 +1,80 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Cartesian phase space overlaid by the VoV mapping
+# ranges.
+#
+# Author:  MG
+# Version: 2011-09-16
+#
+reset
+set terminal postscript enhanced portrait linewidth 1.0 8.0
+set out 'vov_results.ps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'x [AU]'
+set ylabel 'y [AU]'
+plot 'vov_orbits.out' using 1:2 pt 7, \
+'vov_nominal_orbit.out' using 1:2 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:2:7:8 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'x [AU]'
+set ylabel 'z [AU]'
+plot 'vov_orbits.out' using 1:3 pt 7, \
+'vov_nominal_orbit.out' using 1:3 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:3:9:10 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'x [AU]'
+set ylabel 'dx/dt [AU/d]'
+plot 'vov_orbits.out' using 1:4 pt 7, \
+'vov_nominal_orbit.out' using 1:4 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:4:11:12 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'x [AU]'
+set ylabel 'dy/dt [AU/d]'
+plot 'vov_orbits.out' using 1:5 pt 7, \
+'vov_nominal_orbit.out' using 1:5 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:5:13:14 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'x [AU]'
+set ylabel 'dz/dt [AU/d]'
+plot 'vov_orbits.out' using 1:6 pt 7, \
+'vov_nominal_orbit.out' using 1:6 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:6:15:16 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'x [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'vov_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/gnuplot/vov_plot_kep.gp
===================================================================
--- trunk/mops/oorb/gnuplot/vov_plot_kep.gp	(revision 34646)
+++ trunk/mops/oorb/gnuplot/vov_plot_kep.gp	(revision 34646)
@@ -0,0 +1,80 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Gnuplot script for plotting the orbital-element probability-density
+# function in Keplerian phase space overlaid by the VoV mapping
+# ranges.
+#
+# Author:  MG
+# Version: 2011-09-16
+#
+reset
+set terminal postscript enhanced portrait linewidth 1.0 8.0
+set out 'vov_results.ps'
+unset key
+set pointsize 0.2
+set size 1.0,1.0
+set origin 0.0,0.0
+set multiplot
+set size 0.5,0.33
+set origin 0.0,0.66
+set xlabel 'a [AU]'
+set ylabel 'e'
+plot 'vov_orbits.out' using 1:2 pt 7, \
+'vov_nominal_orbit.out' using 1:2 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:2:7:8 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.66
+set xlabel 'a [AU]'
+set ylabel 'i [deg]'
+plot 'vov_orbits.out' using 1:3 pt 7, \
+'vov_nominal_orbit.out' using 1:3 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:3:9:10 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol O} [deg]'
+plot 'vov_orbits.out' using 1:4 pt 7, \
+'vov_nominal_orbit.out' using 1:4 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:4:11:12 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.33
+set xlabel 'a [AU]'
+set ylabel '{/Symbol o} [deg]'
+plot 'vov_orbits.out' using 1:5 pt 7, \
+'vov_nominal_orbit.out' using 1:5 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:5:13:14 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.0,0.0
+set xlabel 'a [AU]'
+set ylabel 'M [deg]'
+plot 'vov_orbits.out' using 1:6 pt 7, \
+'vov_nominal_orbit.out' using 1:6 with points pt 3 ps 3.0, \
+'vov_sampling_grid.out' using 1:6:15:16 with yerrorbars lt 1
+set size 0.5,0.33
+set origin 0.5,0.0
+set xlabel 'a [AU]'
+set ylabel 'Unnormalized discrete p.d.f.'
+plot 'vov_orbits.out' using 1:7 pt 7
+unset multiplot
+reset
Index: trunk/mops/oorb/lib/Makefile
===================================================================
--- trunk/mops/oorb/lib/Makefile	(revision 34646)
+++ trunk/mops/oorb/lib/Makefile	(revision 34646)
@@ -0,0 +1,44 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Makefile for building the OOrb library.
+#
+# Author: MG
+# Date:   2009-11-13
+
+include ../make.config
+include ../Makefile.include
+
+
+# Make everything:
+all: liboorb
+
+liboorb: io
+	$(FC) $(FCOPTIONS) $(FC_SHARED) -o liboorb.$(LIBEXT) \
+	`ls ../$(MODULEPATH)/*.o ../$(CLASSPATH)/*.o ../$(MAINPATH)/*.o`
+
+io:
+	cd ../$(MAINPATH) ; make io.o
+
+clean:
+	rm -f *~ *.$(LIBEXT)
Index: trunk/mops/oorb/main/Makefile
===================================================================
--- trunk/mops/oorb/main/Makefile	(revision 34646)
+++ trunk/mops/oorb/main/Makefile	(revision 34646)
@@ -0,0 +1,81 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Makefile for main programs.
+#
+# Author: MG
+# Date:   2009-11-09
+
+include ../make.config
+include ../Makefile.include
+
+IOMOD = io
+
+all: $(ORBITBIN)
+
+# Compile and link classes to the orbit program:
+$(ORBITBIN): classes $(IOMOD).o
+	$(FC) $(FCOPTIONS) $(ORBITSRC) -o $(ORBITBIN) \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	$(IOMOD).o ../$(CLASSPATH)/*.o \
+	../$(MODULEPATH)/*.o
+
+tico: classes
+	$(FC) $(FCOPTIONS) tico.f90 -o tico \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	../$(CLASSPATH)/*.o ../$(MODULEPATH)/*.o
+
+oorb4mops: classes $(IOMOD).o
+	$(FC) $(FCOPTIONS) oorb4mops.f90 -o oorb4mops \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	$(IOMOD).o ../$(CLASSPATH)/*.o \
+	../$(MODULEPATH)/*.o
+
+oorb4neossat: classes $(IOMOD).o
+	$(FC) $(FCOPTIONS) oorb4neossat.f90 -o oorb4neossat \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	$(IOMOD).o ../$(CLASSPATH)/*.o \
+	../$(MODULEPATH)/*.o
+
+oorb4research: classes $(IOMOD).o
+	$(FC) $(FCOPTIONS) oorb4research.f90 -o oorb4research \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	$(IOMOD).o ../$(CLASSPATH)/*.o \
+	../$(MODULEPATH)/*.o
+
+$(IOMOD).o: classes $(IOMOD).f90
+	$(FC) -c $(FCOPTIONS) $(FC_INC)../$(CLASSPATH) \
+	$(FC_INC)../$(MODULEPATH) $(IOMOD).f90
+
+classes:
+	cd ../$(CLASSPATH) ; $(MAKE) all
+
+
+modules:
+	cd ../$(MODULEPATH) ; $(MAKE) all
+
+
+# Remove program binaries and trash:
+clean:
+	rm -f *~ *.o *.mod $(ORBITBIN) \
+	tico oorb4mops oorb4research oorb4neossat
Index: trunk/mops/oorb/main/io.f90
===================================================================
--- trunk/mops/oorb/main/io.f90	(revision 34646)
+++ trunk/mops/oorb/main/io.f90	(revision 34646)
@@ -0,0 +1,5118 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains routines for IO of options, orbits and residuals. To be
+!! called from main programs.
+!!
+!! @author  MG, JV
+!! @version 2012-02-15
+!!
+MODULE io
+
+  USE Base_cl
+  USE File_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  USE Orbit_cl
+  USE StochasticOrbit_cl
+
+  USE utilities
+  IMPLICIT NONE
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Decodes an encoded MPC type date.
+  !!
+  !! Example:
+  !!
+  !! K01AM -> 2001 11 22
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE decodeMPCDate(encoded_date, year, month, day)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: encoded_date
+    INTEGER, INTENT(out) :: year, month
+    REAL(bp), INTENT(out) :: day
+
+    REAL(bp) :: tmp
+    INTEGER :: i
+
+    CALL removeLeadingBlanks(encoded_date)
+    CALL toInt(encoded_date(2:3), year, error)
+    IF (encoded_date(1:1) == "J") THEN
+       year = year + 1900
+    ELSE IF (encoded_date(1:1) == "K") THEN
+       year = year + 2000
+    END IF
+    DO i=0,SIZE(mpc_conv_table)-1
+       IF (mpc_conv_table(i) == encoded_date(4:4)) THEN
+          EXIT
+       END IF
+    END DO
+    month = i
+    DO i=0,SIZE(mpc_conv_table)-1
+       IF (mpc_conv_table(i) == encoded_date(5:5)) THEN
+          EXIT
+       END IF
+    END DO
+    day = REAL(i,bp)
+    IF (LEN_TRIM(encoded_date) > 5) THEN
+       CALL toReal("0." // TRIM(encoded_date(6:)), tmp, error)
+       day = day + tmp
+    END IF
+
+  END SUBROUTINE decodeMPCDate
+
+
+
+
+
+  SUBROUTINE makeResidualStamps(storb, obss, fname, compute, residuals)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: storb
+    TYPE (Observations), INTENT(in) :: obss
+    CHARACTER(len=*), INTENT(in) :: fname
+    LOGICAL, INTENT(in), OPTIONAL :: compute
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: residuals
+
+    TYPE (Orbit), DIMENSION(:), POINTER  :: orb_arr
+    TYPE (File) :: tmpfile
+    TYPE (Time) :: t
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: observed_scoords, &
+         computed_scoords
+    TYPE (Observation), DIMENSION(:), POINTER :: obs_arr
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), ALLOCATABLE :: codes
+    CHARACTER(len=32), DIMENSION(:), ALLOCATABLE :: dates
+    CHARACTER(len=DESIGNATION_LEN) :: id
+    CHARACTER(len=64) :: str, str1, str2
+    REAL(bp), DIMENSION(:,:,:), POINTER :: residuals_
+    REAL(bp), DIMENSION(:,:), POINTER :: res_accept_prm, stdevs
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: observed_coords, &
+         computed_coords
+    REAL(bp) :: day, xsize, ysize
+    INTEGER :: i, j, k, l, nobs, err, nrow, nrow_max, ncolumn_max, page, &
+         year, month
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL :: compute_
+
+    ! NOTE: info on obs_mask is not output, should it be?.
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / makeResidualStamps", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / makeResidualStamps", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(compute)) THEN
+       compute_ = compute
+    ELSE
+       compute_ = .FALSE.
+    END IF
+    IF (.NOT. compute_) THEN
+       residuals_ => getResidualDistribution(storb)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "Residuals are not available.", 1)
+          RETURN
+       END IF
+    ELSE
+       ! Compute residuals
+       observed_scoords => getObservationSCoords(obss)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       obsy_ccoords => getObservatoryCCoords(obss)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       nobs = SIZE(observed_scoords,dim=1)
+       orb_arr => getSampleOrbits(storb)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       ALLOCATE(residuals_(SIZE(orb_arr,dim=1),nobs,6), &
+            observed_coords(nobs,6), computed_coords(nobs,6), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / makeResidualStamps", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+       DO j=1,SIZE(orb_arr, dim=1)
+          CALL getEphemerides(orb_arr(j), obsy_ccoords, &
+               computed_scoords)
+          IF (error) THEN
+             CALL errorMessage("io / makeResidualStamps", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+          observed_coords = 0.0_bp
+          computed_coords = 0.0_bp
+          DO i=1,nobs
+             observed_coords(i,:) = getCoordinates(observed_scoords(i))
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (25)", 1)
+                RETURN
+             END IF
+             computed_coords(i,:) = getCoordinates(computed_scoords(i))
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (30)", 1)
+                RETURN
+             END IF
+          END DO
+          residuals_(j,1:nobs,1:6) = observed_coords(1:nobs,1:6) - &
+               computed_coords(1:nobs,1:6)        
+          residuals_(j,1:nobs,2) = residuals_(j,1:nobs,2) * &
+               COS(observed_coords(1:nobs,3))
+          DEALLOCATE(computed_scoords, stat=err)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("io / makeResidualStamps", &
+                  "Could not deallocate memory (5).", 1)
+             RETURN
+          END IF
+       END DO
+       DO i=1,SIZE(orb_arr)
+          CALL NULLIFY(orb_arr(i))
+       END DO
+       DEALLOCATE(observed_coords, computed_coords, observed_scoords, &
+            obsy_ccoords, orb_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / makeResidualStamps", &
+               "Could not deallocate memory (10).", 1)
+          DEALLOCATE(observed_coords, stat=err)
+          DEALLOCATE(computed_coords, stat=err)
+          DEALLOCATE(observed_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    obs_arr => getObservations(obss)
+    IF (error) THEN
+       CALL errorMessage("io / makeResidualStamps", &
+            "TRACE BACK (35)", 1)
+       RETURN
+    END IF
+    nobs = SIZE(obs_arr, dim=1)
+
+    ALLOCATE(dates(nobs), codes(nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / makeResidualStamps", &
+            "Could not allocate memory (10).", 1)
+       RETURN
+    END IF
+
+    DO i=1,nobs
+       t = getTime(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (40)", 1)
+          RETURN
+       END IF
+       CALL getCalendarDate(t, "TT", year, month, day)
+       IF (year >= 1972) THEN
+          dates(i) = getCalendarDateString(t, "UTC")
+       ELSE
+          dates(i) = getCalendarDateString(t, "UT1")
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       codes(i) = getCode(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (50)", 1)
+          RETURN
+       END IF
+    END DO
+
+    id = getID(obss)
+    IF (error) THEN
+       CALL errorMessage("io / makeResidualStamps", &
+            "TRACE BACK (55)", 1)
+       RETURN
+    END IF
+    CALL toString(nobs, str, error)
+    IF (error) THEN
+       CALL errorMessage("io / makeResidualStamps", &
+            "TRACE BACK (60)", 1)
+       RETURN
+    END IF
+
+    CALL getParameters(storb, res_accept=res_accept_prm)
+    IF (error) THEN
+       CALL errorMessage("io / makeResidualStamps", &
+            "Will use a default stamp size instead (+-5-sigma).", 1)
+       error = .FALSE.
+       stdevs => getStandardDeviations(obss)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (65)", 1)
+          RETURN
+       END IF
+       ALLOCATE(res_accept_prm(SIZE(stdevs,dim=1),6))
+       DO i=1,SIZE(stdevs,dim=1)
+          res_accept_prm(i,:) = 5.0_bp*stdevs(i,:)
+       END DO
+       DEALLOCATE(stdevs)
+    END IF
+    obs_masks => getObservationMasks(storb)
+    IF (error) THEN
+       CALL errorMessage("io / makeResidualStamps", &
+            "TRACE BACK (70)", 1)
+       RETURN
+    END IF
+
+    nrow_max = 4
+    ncolumn_max = 4
+    nrow = CEILING(nobs/REAL(ncolumn_max))
+
+    str = " "
+    str = TRIM(id) // "_" // TRIM(str) // "resid_stamp.gp"
+    CALL system("echo set terminal postscript eps enhanced color linewidth 1.0 8.0 > " // TRIM(str))
+    CALL system("echo set out \'residual_stamps.eps\' >> " // TRIM(str))
+    CALL system("echo unset key >> " // TRIM(str))
+    CALL system("echo set pointsize 0.2 >> " // TRIM(str))
+    IF (nrow >= nrow_max) THEN
+       xsize = 1.0
+       ysize = 1.0
+       CALL system("echo set size 1.0,1.0 >> " // TRIM(str))
+    ELSE IF (nrow < nrow_max) THEN
+       IF (nobs > ncolumn_max) THEN
+          xsize = 1.0
+          ysize = 1.0/nrow_max*nrow
+          CALL toString(ysize, str1, error)
+          IF (error) THEN
+             CALL errorMessage("io / makeResidualStamps", &
+                  "TRACE BACK (80)", 1)
+             RETURN
+          END IF
+          CALL system("echo set size 1.0," // TRIM(str1) // " >> " // TRIM(str))
+       ELSE
+          xsize = 1.0/ncolumn_max*nobs
+          ysize = 1.0/nrow_max*nrow
+          CALL toString(xsize, str1, error)
+          IF (error) THEN
+             CALL errorMessage("io / makeResidualStamps", &
+                  "TRACE BACK (80)", 1)
+             RETURN
+          END IF
+          CALL toString(ysize, str2, error)
+          IF (error) THEN
+             CALL errorMessage("io / makeResidualStamps", &
+                  "TRACE BACK (80)", 1)
+             RETURN
+          END IF
+          CALL system("echo set size " // TRIM(str1) // "," // &
+               TRIM(str2) // " >> " // TRIM(str))
+       END IF
+    END IF
+    CALL system("echo set origin 0.0,0.0 >> " // TRIM(str))
+    page = 1
+
+    DO
+       !       CALL system('echo set multiplot title \"'  // TRIM(id) // &
+       !            '\" >> ' // TRIM(str))
+       CALL system('echo set multiplot >> ' // TRIM(str))
+       CALL toString(1.0/ncolumn_max, str1, error)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (75)", 1)
+          RETURN
+       END IF
+       CALL toString(1.0/nrow_max, str2, error)
+       IF (error) THEN
+          CALL errorMessage("io / makeResidualStamps", &
+               "TRACE BACK (80)", 1)
+          RETURN
+       END IF
+       CALL system("echo set size " // TRIM(str1) // &
+            "," // TRIM(str2) // " >> " // TRIM(str))
+       DO i=1,nrow
+          DO j=1,ncolumn_max
+             k = (page-1)*nrow_max*ncolumn_max + (i-1)*ncolumn_max + j
+             IF (k > MIN(nobs,page*nrow_max*ncolumn_max)) THEN
+                ! All residuals plotted for this page or overall
+                EXIT
+             END IF
+             IF (nobs >= ncolumn_max) THEN
+                CALL toString((j-1)*(xsize/ncolumn_max), str1, error)
+             ELSE
+                CALL toString((j-1)*(xsize/nobs), str1, error)                
+             END IF
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (85)", 1)
+                RETURN
+             END IF
+             CALL toString(ysize-i*(1.0/nrow_max), str2, error)
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (90)", 1)
+                RETURN
+             END IF
+             CALL system("echo set origin " // TRIM(str1) // &
+                  "," // TRIM(str2) // " >> " // TRIM(str))
+             CALL system("echo set size square >> " // TRIM(str))
+             CALL system("echo set xzeroaxis >> " // TRIM(str))
+             CALL system("echo set yzeroaxis >> " // TRIM(str))
+             CALL toString(res_accept_prm(k,2)/rad_asec, &
+                  str2, error)
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (95)", 1)
+                RETURN
+             END IF
+             str1 = "-" // TRIM(str2)
+             CALL system("echo set xrange [" // TRIM(str1) // &
+                  ":" // TRIM(str2) // "] >> " // TRIM(str))          
+             CALL toString(res_accept_prm(k,3)/rad_asec, &
+                  str2, error)
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (100)", 1)
+                RETURN
+             END IF
+             str1 = "-" // TRIM(str2)
+             CALL system("echo set yrange [" // TRIM(str1) // &
+                  ":" // TRIM(str2) // "] >> " // TRIM(str))
+             !             CALL system('echo set title \"' // TRIM(id) // "\\" // "n" // &
+             CALL system('echo set title \"' // TRIM(codes(k)) // " " &
+                  // TRIM(dates(k)) // '\" >> ' // TRIM(str))
+             CALL system("echo set xlabel \'{/Symbol D}RA [asec]\' >> " // &
+                  TRIM(str))
+             CALL system("echo set ylabel \'{/Symbol D}Dec [asec]\' >> " // &
+                  TRIM(str))
+             CALL toString(k, str1, error)
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (105)", 1)
+                RETURN
+             END IF
+             str1 = TRIM(str) // "_tmp" // TRIM(str1)
+             CALL NEW(tmpfile, TRIM(str1))
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (110)", 1)
+                RETURN
+             END IF
+             CALL OPEN(tmpfile)
+             IF (error) THEN
+                CALL errorMessage("io / makeResidualStamps", &
+                     "TRACE BACK (115)", 1)
+                RETURN
+             END IF
+             DO l=1,SIZE(residuals_,dim=1)
+                WRITE(getUnit(tmpfile),*) residuals_(l,k,2:3)/rad_asec
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / makeResidualStamps", &
+                        "Write error (15).", 1)
+                   RETURN
+                END IF
+             END DO
+             CALL NULLIFY(tmpfile)
+             IF (ALL(obs_masks(k,2:3))) THEN
+                CALL system("echo plot \'" // TRIM(str1) // &
+                     "\' using 1:2 pt 0 >> " // TRIM(str))
+             ELSE
+                CALL system("echo plot \'" // TRIM(str1) // &
+                     "\' using 1:2 pt 1 >> " // TRIM(str))
+             END IF
+          END DO
+       END DO
+       CALL system("echo unset multiplot >> " // TRIM(str))
+       IF (nobs > page*nrow_max*ncolumn_max) THEN
+          ! Turn to next page if there is stamps to plot
+          page = page + 1
+       ELSE
+          ! All stamps have been plotted
+          EXIT
+       END IF
+    END DO
+    CALL system("gnuplot " // TRIM(str))
+    CALL system("mv residual_stamps.eps " // TRIM(fname))
+    CALL system("rm -f " // TRIM(str) // " " // TRIM(str) // "_tmp*")
+
+    IF (PRESENT(residuals)) THEN
+       IF (ASSOCIATED(residuals)) THEN
+          DEALLOCATE(residuals, stat=err)
+       END IF
+       ALLOCATE(residuals(SIZE(residuals_,dim=1),nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / makeResidualStamps", &
+               "Could not allocate memory (15).", 1)
+          RETURN
+       END IF
+       residuals = residuals_
+    END IF
+
+    DEALLOCATE(obs_arr, residuals_, dates, codes, res_accept_prm, &
+         obs_masks, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / makeResidualStamps", &
+            "Could not deallocate memory (15).", 1)
+       DEALLOCATE(obs_arr, stat=err)
+       DEALLOCATE(residuals_, stat=err)
+       DEALLOCATE(dates, stat=err)
+       DEALLOCATE(codes, stat=err)
+       DEALLOCATE(res_accept_prm, stat=err)
+       DEALLOCATE(obs_masks, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE makeResidualStamps
+
+
+
+
+
+  SUBROUTINE readConfigurationFile(config_file, &
+       info_verb, err_verb, planetary_ephemeris_fname, &
+       task, &
+       t0, &
+       multiple_ids, &
+       obs_stdev_arr, &
+       element_type_comp, &
+       element_type_out, &
+       observation_format_out, orbit_format_out, &
+       plot_results, &
+       plot_open, &
+       dyn_model, perturbers, integrator, integration_step, relativity, &
+       dyn_model_init, integrator_init, integration_step_init, &
+       accwin_multiplier, &
+       dchi2_rejection, dchi2_max, regularized_pdf, chi2_min, & 
+       outlier_rejection, outlier_multiplier, &
+       apriori_a_min, apriori_a_max, apriori_periapsis_min, &
+       apriori_periapsis_max, apriori_apoapsis_min, &
+       apriori_apoapsis_max, apriori_rho_min, apriori_rho_max, &
+       sor_type, sor_2point_method, sor_2point_method_sw, sor_norb, &
+       sor_ntrial, sor_norb_sw, sor_ntrial_sw, sor_niter, &
+       sor_random_obs, sor_rho_init, generat_multiplier, &
+       sor_genwin_offset, sor_rho_gauss, sor_rho_init2, &
+       sor_rho_gauss2, sor_iterate_bounds, &
+       vov_type, vov_norb, vov_ntrial, vov_niter, vov_norb_iter, &
+       vov_ntrial_iter, vov_nmap, vov_mapping_mask, vov_scaling, &
+       vomcmc_type, vomcmc_norb, vomcmc_ntrial, vomcmc_niter, vomcmc_norb_iter, &
+       vomcmc_ntrial_iter, vomcmc_nmap, vomcmc_mapping_mask, vomcmc_scaling, &
+       ls_type, ls_element_mask, ls_correction_factor, ls_rchi2_acceptable, &
+       ls_niter_major_max, ls_niter_major_min, ls_niter_minor, &
+       cos_nsigma, cos_norb, cos_ntrial, cos_gaussian, &
+       smplx_tol, smplx_niter, smplx_force, smplx_similarity_tol, &
+       os_norb, os_ntrial, os_sampling_type, generat_gaussian_deviates, & 
+       pp_H_estimation, pp_G, pp_G_unc, &
+       eph_lt_correction, eph_dt_since_last_obs, eph_obsy_code, &
+       eph_date, &
+       masked_obs, write_residuals, &
+       sor_rhofname)
+
+    IMPLICIT NONE
+    TYPE (File), INTENT(in) :: &
+         config_file
+    TYPE (Time), DIMENSION(:), POINTER, OPTIONAL :: &
+         eph_date
+    TYPE (Time), INTENT(inout), OPTIONAL :: &
+         t0
+    CHARACTER(len=*), DIMENSION(:), POINTER, OPTIONAL :: &
+         eph_obsy_code
+    CHARACTER(len=*), INTENT(inout), OPTIONAL :: &
+         sor_rhofname, &
+         element_type_comp, &
+         element_type_out, &
+         dyn_model, &
+         dyn_model_init, &
+         integrator, &
+         integrator_init, &
+         sor_2point_method, &
+         sor_2point_method_sw, &
+         observation_format_out, &
+         orbit_format_out, &
+         planetary_ephemeris_fname
+    REAL(bp), DIMENSION(6,2), INTENT(inout), OPTIONAL :: &
+         vov_scaling, &
+         vomcmc_scaling
+    REAL(bp), DIMENSION(:), POINTER, OPTIONAL :: &
+         eph_dt_since_last_obs
+    REAL(bp), DIMENSION(6), INTENT(inout), OPTIONAL :: &
+         obs_stdev_arr
+    REAL(bp), DIMENSION(4), INTENT(inout), OPTIONAL :: &
+         sor_rho_init, &
+         sor_rho_init2, &
+         sor_genwin_offset
+    REAL(bp), INTENT(inout), OPTIONAL :: &
+         accwin_multiplier, &
+         outlier_multiplier, &
+         generat_multiplier, &
+         ls_correction_factor, &
+         ls_rchi2_acceptable, &
+         cos_nsigma, &
+         smplx_tol, &
+         smplx_similarity_tol, &
+         integration_step, &
+         integration_step_init, &
+         dchi2_max, &
+         chi2_min, &
+         apriori_a_min, &
+         apriori_a_max, &
+         apriori_periapsis_min, &
+         apriori_periapsis_max, &
+         apriori_apoapsis_min, &
+         apriori_apoapsis_max, &
+         apriori_rho_min, &
+         apriori_rho_max, &
+         pp_G, pp_G_unc
+    INTEGER, INTENT(inout), OPTIONAL :: &
+         info_verb, &
+         err_verb, &
+         task, &
+         sor_type, &
+         sor_norb, &
+         sor_ntrial, &
+         sor_norb_sw, &
+         sor_ntrial_sw, &
+         sor_niter, &
+         vov_type, &
+         vov_norb, &
+         vov_ntrial, &
+         vov_niter, &
+         vov_norb_iter, &
+         vov_ntrial_iter, &
+         vov_nmap, &
+         vomcmc_type, &
+         vomcmc_norb, &
+         vomcmc_ntrial, &
+         vomcmc_niter, &
+         vomcmc_norb_iter, &
+         vomcmc_ntrial_iter, &
+         vomcmc_nmap, &
+         ls_type, &
+         ls_niter_major_max, &
+         ls_niter_major_min, &
+         ls_niter_minor, &
+         cos_norb, &
+         cos_ntrial, &
+         smplx_niter, &
+         os_norb, &
+         os_ntrial, &
+         os_sampling_type
+    LOGICAL, DIMENSION(:), POINTER, OPTIONAL :: &
+         eph_lt_correction, &
+         perturbers
+    LOGICAL, DIMENSION(6), INTENT(inout), OPTIONAL :: &
+         ls_element_mask, &
+         vov_mapping_mask, &
+         vomcmc_mapping_mask
+    LOGICAL, DIMENSION(4), INTENT(inout), OPTIONAL :: &
+         sor_iterate_bounds
+    LOGICAL, INTENT(inout), OPTIONAL :: &
+         plot_results, &
+         plot_open, &
+         multiple_ids, &
+         relativity, &
+         dchi2_rejection, &
+         regularized_pdf, &
+         masked_obs, &
+         outlier_rejection, &
+         sor_random_obs, &
+         sor_rho_gauss, sor_rho_gauss2, &
+         cos_gaussian, &
+         smplx_force, &
+         generat_gaussian_deviates, &
+         write_residuals, &
+         pp_H_estimation
+
+    CHARACTER(len=256) :: line, par_id, par_val
+    REAL(bp) :: day, jd, mjd
+    INTEGER :: err, i, indx, indx1, indx2, year, month
+    LOGICAL :: last
+
+    REWIND(getUnit(config_file))
+    DO
+       READ(getUnit(config_file),"(A)", iostat=err) line
+       IF (err > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readConfigurationFile", &
+               "Error while reading option file.", 1)
+          RETURN
+       ELSE IF (err < 0) THEN ! end-of-file
+          EXIT
+       END IF
+       IF (LEN_TRIM(line) == 0 .OR. line(1:1) == "#") THEN
+          CYCLE
+       END IF
+       indx = INDEX(line,":")
+       par_id = line(1:indx-1)
+       par_val = line(indx+1:LEN_TRIM(line))
+       CALL removeLeadingBlanks(par_val)
+       indx = INDEX(par_id,".",back=.TRUE.)
+       IF (IACHAR(par_id(indx+1:indx+1)) >= 48 .AND. &
+            IACHAR(par_id(indx+1:indx+1)) <= 57) THEN
+          CALL toInt(TRIM(par_id(indx+1:)), i, error)          
+          par_id = par_id(1:indx-1)
+       ELSE
+          i = 0
+       END IF
+       SELECT CASE(TRIM(par_id))
+
+          ! GENERAL PARAMETERS
+       CASE ("verbose.info")
+          IF (PRESENT(info_verb)) THEN
+             CALL toInt(TRIM(par_val), info_verb, error)
+          END IF
+       CASE ("verbose.error")
+          IF (PRESENT(err_verb)) THEN
+             CALL toInt(TRIM(par_val), err_verb, error)
+          END IF
+       CASE ("planetary_ephemeris_fname")
+          IF (PRESENT(planetary_ephemeris_fname)) THEN
+             planetary_ephemeris_fname = TRIM(par_val)
+          END IF
+       CASE ("task")
+          IF (PRESENT(task)) THEN
+             CALL toInt(TRIM(par_val), task, error)
+          END IF
+       CASE ("write.residuals")
+          IF (PRESENT(write_residuals)) THEN
+             write_residuals = .TRUE.
+          END IF
+       CASE ("plot.results")
+          IF (PRESENT(plot_results)) THEN
+             READ(par_val, *, iostat=err) plot_results
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (23).", 1)
+             END IF
+          END IF
+       CASE ("plot.open")
+          IF (PRESENT(plot_open)) THEN
+             READ(par_val, *, iostat=err) plot_open
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (23).", 1)
+             END IF
+          END IF
+       CASE ("element_type_out")
+          IF (PRESENT(element_type_out)) THEN
+             CALL locase(par_val, error)
+             IF (error) THEN
+                CALL errorMessage("io / readConfigurationFile", &
+                     "The type of output orbital elements " // &
+                     "string contains forbidden characters.", 1)
+             END IF
+             IF (par_val /= "cartesian" .AND. &
+                  par_val /= "keplerian" .AND. &
+                  par_val /= "cometary") THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Type of output orbital elements " // &
+                     "is not recognized: " // TRIM(par_val) &
+                     // ".", 1)
+             END IF
+             element_type_out = TRIM(par_val)
+          END IF
+       CASE ("observation.format.out")
+          IF (PRESENT(observation_format_out)) THEN
+             observation_format_out = TRIM(par_val)
+          END IF
+       CASE ("orbit.format.out")
+          IF (PRESENT(orbit_format_out)) THEN
+             orbit_format_out = TRIM(par_val)
+          END IF
+
+          ! INPUT OBSERVATION PARAMETERS:
+       CASE ("sor.rhofname")
+          IF (PRESENT(sor_rhofname)) THEN
+             sor_rhofname = TRIM(par_val)
+          END IF
+       CASE ("stdev.ra")
+          IF (PRESENT(obs_stdev_arr)) THEN
+             CALL toReal(TRIM(par_val), obs_stdev_arr(2), error)
+             obs_stdev_arr(2) = obs_stdev_arr(2)*rad_asec
+          END IF
+       CASE ("stdev.dec")
+          IF (PRESENT(obs_stdev_arr)) THEN
+             CALL toReal(TRIM(par_val), obs_stdev_arr(3), error)
+             obs_stdev_arr(3) = obs_stdev_arr(3)*rad_asec
+          END IF
+       CASE ("multiple_ids")
+          IF (PRESENT(multiple_ids)) THEN
+             multiple_ids = .TRUE.
+          END IF
+
+
+          ! GENERAL INVERSION PARAMETERS
+       CASE ("element_type_comp")
+          IF (PRESENT(element_type_comp)) THEN
+             CALL locase(par_val, error)
+             IF (error) THEN
+                CALL errorMessage("io / readConfigurationFile", &
+                     "The type of computation orbital " // &
+                     "elements string contains forbidden characters.", 1)
+             END IF
+             IF (par_val /= "cartesian" .AND. &
+                  par_val /= "keplerian" .AND. &
+                  par_val /= "cometary") THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Type of orbital elements to be used in computations " // &
+                     "is not recognized: " // TRIM(par_val) &
+                     // ".", 1)
+             END IF
+             element_type_comp = TRIM(par_val)
+          END IF
+       CASE ("epoch.cal")
+          IF (PRESENT(t0)) THEN
+             indx1 = INDEX(TRIM(par_val),"/")
+             indx2 = INDEX(TRIM(par_val),"/",back=.TRUE.)
+             CALL toInt(par_val(1:indx1-1), year, error)
+             CALL toInt(par_val(indx1+1:indx2-1), month, error)
+             CALL toReal(par_val(indx2+1:), day, error)
+             IF (exist(t0)) THEN
+                CALL NULLIFY(t0)
+             END IF
+             CALL NEW(t0, year, month, day, "tdt")
+          END IF
+       CASE ("epoch.mjd")
+          IF (PRESENT(t0)) THEN
+             CALL toReal(TRIM(par_val), mjd, error)
+             IF (exist(t0)) THEN
+                CALL NULLIFY(t0)
+             END IF
+             CALL NEW(t0, mjd, "tdt")
+          END IF
+       CASE ("epoch.jd")
+          IF (PRESENT(t0)) THEN
+             CALL toReal(TRIM(par_val), jd, error)
+             IF (exist(t0)) THEN
+                CALL NULLIFY(t0)
+             END IF
+             CALL NEW(t0, jd-2400000.5_bp, "tdt")
+          END IF
+       CASE ("outlier_rejection")
+          IF (PRESENT(outlier_rejection)) THEN
+             outlier_rejection = .TRUE.
+          END IF
+       CASE ("outlier.multiplier")
+          IF (PRESENT(outlier_multiplier)) THEN
+             CALL toReal(TRIM(par_val), outlier_multiplier, error)
+          END IF
+       CASE ("generation.multiplier")
+          IF (PRESENT(generat_multiplier)) THEN
+             CALL toReal(TRIM(par_val), generat_multiplier, error)
+          END IF
+       CASE ("generation.gaussian_deviates")
+          IF (PRESENT(generat_gaussian_deviates)) THEN
+             READ(par_val, *, iostat=err) generat_gaussian_deviates
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (23).", 1)
+             END IF
+          END IF
+       CASE ("accwin.multiplier")
+          IF (PRESENT(accwin_multiplier)) THEN
+             CALL toReal(TRIM(par_val), accwin_multiplier, error)
+          END IF
+
+
+          ! PROPAGATION PARAMETERS:
+       CASE ("dynamical_model")
+          IF (PRESENT(dyn_model)) THEN
+             dyn_model = TRIM(par_val)
+          END IF
+       CASE ("perturber.Mercury")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(1) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(1) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Venus")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(2) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(2) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Earth")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(3) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(3) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Mars")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(4) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(4) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Jupiter")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(5) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(5) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Saturn")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(6) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(6) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Uranus")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(7) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(7) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Neptune")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(8) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(8) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Pluto")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(9) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(9) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("perturber.Moon")
+          IF (PRESENT(perturbers)) THEN
+             IF (.NOT.ASSOCIATED(perturbers)) THEN
+                ALLOCATE(perturbers(10), stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not allocate perturbers array.", 1)
+                END IF
+             END IF
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   perturbers(10) = .TRUE.
+                CASE ("f", "F")
+                   perturbers(10) = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("integrator")
+          IF (PRESENT(integrator)) THEN
+             integrator = TRIM(par_val)
+          END IF
+       CASE ("integration_step")
+          IF (PRESENT(integration_step)) THEN
+             CALL toReal(TRIM(par_val), integration_step, error)
+             IF (integration_step <= 0.0_bp) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Integration step must be larger than zero.", 1)
+             END IF
+          END IF
+       CASE ("relativity")
+          IF (PRESENT(relativity)) THEN
+             IF (.NOT.error) THEN
+                SELECT CASE (ADJUSTL(par_val))
+                CASE ("t", "T")
+                   relativity = .TRUE.
+                CASE ("f", "F")
+                   relativity = .FALSE.
+                CASE default
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Cannot understand logical value: " // &
+                        TRIM(ADJUSTL(par_val)) // ".", 1)
+                END SELECT
+             END IF
+          END IF
+       CASE ("dynamical_model_init")
+          IF (PRESENT(dyn_model_init)) THEN
+             dyn_model_init = TRIM(par_val)
+          END IF
+       CASE ("integrator_init")
+          IF (PRESENT(integrator_init)) THEN
+             integrator_init = TRIM(par_val)
+          END IF
+       CASE ("integration_step_init")
+          IF (PRESENT(integration_step_init)) THEN
+             CALL toReal(TRIM(par_val), integration_step_init, error)
+             IF (integration_step_init <= 0.0_bp) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Integration step must be larger than zero.", 1)
+             END IF
+          END IF
+
+
+          ! STATISTICAL PARAMETERS
+       CASE ("dchi2_rejection")
+          IF (PRESENT(dchi2_rejection)) THEN
+             READ(par_val, *, iostat=err) dchi2_rejection
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (21).", 1)
+             END IF
+          END IF
+       CASE ("dchi2.max")
+          IF (PRESENT(dchi2_max)) THEN
+             CALL toReal(par_val, dchi2_max, error)
+          END IF
+       CASE ("reg.pdf")
+          IF (PRESENT(regularized_pdf)) THEN
+             READ(par_val, *, iostat=err) regularized_pdf
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (21).", 1)
+             END IF
+          END IF
+       CASE ("obs.mask")
+          IF (PRESENT(masked_obs)) THEN
+             READ(par_val, *, iostat=err) masked_obs
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (21).", 1)
+             END IF
+          END IF
+       CASE ("chi2_min.init")
+          IF (PRESENT(chi2_min)) THEN
+             CALL toReal(par_val, chi2_min, error)
+          END IF
+
+
+          ! BAYESIAN (INFORMATIVE) A PRIORI PARAMETERS
+       CASE ("apriori.a.min")
+          IF (PRESENT(apriori_a_min)) THEN
+             CALL toReal(par_val, apriori_a_min, error)
+          END IF
+       CASE ("apriori.a.max")
+          IF (PRESENT(apriori_a_max)) THEN
+             CALL toReal(par_val, apriori_a_max, error)
+          END IF
+       CASE ("apriori.q.min")
+          IF (PRESENT(apriori_periapsis_min)) THEN
+             CALL toReal(par_val, apriori_periapsis_min, error)
+          END IF
+       CASE ("apriori.q.max")
+          IF (PRESENT(apriori_periapsis_max)) THEN
+             CALL toReal(par_val, apriori_periapsis_max, error)
+          END IF
+       CASE ("apriori.Q.min")
+          IF (PRESENT(apriori_apoapsis_min)) THEN
+             CALL toReal(par_val, apriori_apoapsis_min, error)
+          END IF
+       CASE ("apriori.Q.max")
+          IF (PRESENT(apriori_apoapsis_max)) THEN
+             CALL toReal(par_val, apriori_apoapsis_max, error)
+          END IF
+       CASE ("apriori.rho.min")
+          IF (PRESENT(apriori_rho_min)) THEN
+             CALL toReal(par_val, apriori_rho_min, error)
+          END IF
+       CASE ("apriori.rho.max")
+          IF (PRESENT(apriori_rho_max)) THEN
+             CALL toReal(par_val, apriori_rho_max, error)
+          END IF
+
+
+          ! STATISTICAL ORBITAL RANGING PARAMETERS:
+       CASE ("sor.type")
+          IF (PRESENT(sor_type)) THEN
+             CALL toInt(TRIM(par_val), sor_type, error)
+          END IF
+       CASE ("sor.two_point_method")
+          IF (PRESENT(sor_2point_method)) THEN
+             sor_2point_method = TRIM(par_val)
+          END IF
+       CASE ("sor.norb")
+          IF (PRESENT(sor_norb)) THEN
+             CALL toInt(TRIM(par_val), sor_norb, error)
+          END IF
+       CASE ("sor.ntrial")
+          IF (PRESENT(sor_ntrial)) THEN
+             CALL toInt(TRIM(par_val), sor_ntrial, error)
+          END IF
+       CASE ("sor.two_point_method_sw")
+          IF (PRESENT(sor_2point_method_sw)) THEN
+             sor_2point_method_sw = TRIM(par_val)
+          END IF
+       CASE ("sor.norb.sw")
+          IF (PRESENT(sor_norb_sw)) THEN
+             CALL toInt(TRIM(par_val), sor_norb_sw, error)
+          END IF
+       CASE ("sor.ntrial.sw")
+          IF (PRESENT(sor_ntrial_sw)) THEN
+             CALL toInt(TRIM(par_val), sor_ntrial_sw, error)
+          END IF
+       CASE ("sor.niter")
+          IF (PRESENT(sor_niter)) THEN
+             CALL toInt(TRIM(par_val), sor_niter, error)
+          END IF
+       CASE ("sor.ran.obs")
+          IF (PRESENT(sor_random_obs)) THEN
+             sor_random_obs = .TRUE.
+          END IF
+       CASE ("sor.rho.gauss")
+          IF (PRESENT(sor_rho_gauss)) THEN
+             sor_rho_gauss = .TRUE.
+          END IF
+       CASE ("sor.rho.gauss2")
+          IF (PRESENT(sor_rho_gauss2)) THEN
+             sor_rho_gauss2 = .TRUE.
+          END IF
+       CASE ("sor.rho11.init")
+          IF (PRESENT(sor_rho_init)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init(1), error)
+          END IF
+       CASE ("sor.rho12.init")
+          IF (PRESENT(sor_rho_init)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init(2), error)
+          END IF
+       CASE ("sor.rho21.init")
+          IF (PRESENT(sor_rho_init)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init(3), error)
+          END IF
+       CASE ("sor.rho22.init")
+          IF (PRESENT(sor_rho_init)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init(4), error)
+          END IF
+       CASE ("sor.genwin.offset")
+          IF (PRESENT(sor_genwin_offset)) THEN
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             i = 0
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (i > 4) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Too many input values for sor.genwin.offset; only 4 allowed!.", 1)
+                   RETURN
+                END IF
+                CALL toReal(TRIM(par_val(indx1:indx1+indx2-1)), sor_genwin_offset(i), error)
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+             sor_genwin_offset = sor_genwin_offset*rad_asec
+          END IF
+       CASE ("sor.rho11.init2")
+          IF (PRESENT(sor_rho_init2)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init2(1), error)
+          END IF
+       CASE ("sor.rho12.init2")
+          IF (PRESENT(sor_rho_init2)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init2(2), error)
+          END IF
+       CASE ("sor.rho21.init2")
+          IF (PRESENT(sor_rho_init2)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init2(3), error)
+          END IF
+       CASE ("sor.rho22.init2")
+          IF (PRESENT(sor_rho_init2)) THEN
+             CALL toReal(TRIM(par_val), sor_rho_init2(4), error)
+          END IF
+       CASE ("sor.iterate_bounds")
+          IF (PRESENT(sor_iterate_bounds)) THEN
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             i = 0
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (i > 4) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Too many input values for sor.iterate_bounds; only 4 allowed!.", 1)
+                   RETURN
+                END IF
+                READ(par_val(indx1:indx1+indx2-1),"(L1)") sor_iterate_bounds(i)
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+          END IF
+
+          ! VOLUME-OF-VARIATION PARAMETERS:
+       CASE ("vov.type")
+          IF (PRESENT(vov_type)) THEN
+             CALL toInt(TRIM(par_val), vov_type, error)
+          END IF
+       CASE ("vov.norb")
+          IF (PRESENT(vov_norb)) THEN
+             CALL toInt(TRIM(par_val), vov_norb, error)
+          END IF
+       CASE ("vov.ntrial")
+          IF (PRESENT(vov_ntrial)) THEN
+             CALL toInt(TRIM(par_val), vov_ntrial, error)
+          END IF
+       CASE ("vov.niter")
+          IF (PRESENT(vov_niter)) THEN
+             CALL toInt(TRIM(par_val), vov_niter, error)
+          END IF
+       CASE ("vov.norb_iter")
+          IF (PRESENT(vov_norb_iter)) THEN
+             CALL toInt(TRIM(par_val), vov_norb_iter, error)
+          END IF
+       CASE ("vov.ntrial_iter")
+          IF (PRESENT(vov_ntrial_iter)) THEN
+             CALL toInt(TRIM(par_val), vov_ntrial_iter, error)
+          END IF
+       CASE ("vov.nmap")
+          IF (PRESENT(vov_nmap)) THEN
+             CALL toInt(TRIM(par_val), vov_nmap, error)
+          END IF
+       CASE ("vov.mapping_mask")
+          IF (PRESENT(vov_mapping_mask)) THEN
+             vov_mapping_mask = .TRUE.
+             READ(par_val, *, iostat=err) vov_mapping_mask
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (5).", 1)
+             END IF
+          END IF
+       CASE ("vov.scaling.lo")
+          IF (PRESENT(vov_scaling)) THEN
+             READ(par_val, *, iostat=err) vov_scaling(:,1)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (10).", 1)
+             END IF
+          END IF
+       CASE ("vov.scaling.hi")
+          IF (PRESENT(vov_scaling)) THEN
+             READ(par_val, *, iostat=err) vov_scaling(:,2)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (15).", 1)
+             END IF
+          END IF
+
+
+          ! VIRTUAL-OBSERVATION-MCMC PARAMETERS:
+       CASE ("vomcmc.type")
+          IF (PRESENT(vomcmc_type)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_type, error)
+          END IF
+       CASE ("vomcmc.norb")
+          IF (PRESENT(vomcmc_norb)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_norb, error)
+          END IF
+       CASE ("vomcmc.ntrial")
+          IF (PRESENT(vomcmc_ntrial)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_ntrial, error)
+          END IF
+       CASE ("vomcmc.niter")
+          IF (PRESENT(vomcmc_niter)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_niter, error)
+          END IF
+       CASE ("vomcmc.norb_iter")
+          IF (PRESENT(vomcmc_norb_iter)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_norb_iter, error)
+          END IF
+       CASE ("vomcmc.ntrial_iter")
+          IF (PRESENT(vomcmc_ntrial_iter)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_ntrial_iter, error)
+          END IF
+       CASE ("vomcmc.nmap")
+          IF (PRESENT(vomcmc_nmap)) THEN
+             CALL toInt(TRIM(par_val), vomcmc_nmap, error)
+          END IF
+       CASE ("vomcmc.mapping_mask")
+          IF (PRESENT(vomcmc_mapping_mask)) THEN
+             vomcmc_mapping_mask = .TRUE.
+             READ(par_val, *, iostat=err) vomcmc_mapping_mask
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (5).", 1)
+             END IF
+          END IF
+       CASE ("vomcmc.scaling.lo")
+          IF (PRESENT(vomcmc_scaling)) THEN
+             READ(par_val, *, iostat=err) vomcmc_scaling(:,1)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (10).", 1)
+             END IF
+          END IF
+       CASE ("vomcmc.scaling.hi")
+          IF (PRESENT(vomcmc_scaling)) THEN
+             READ(par_val, *, iostat=err) vomcmc_scaling(:,2)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (15).", 1)
+             END IF
+          END IF
+
+
+          ! LEAST SQUARES PARAMETERS:
+       CASE ("ls.type")
+          IF (PRESENT(ls_type)) THEN
+             CALL toInt(TRIM(par_val), ls_type, error)
+          END IF
+       CASE ("ls.correction_factor")
+          IF (PRESENT(ls_correction_factor)) THEN
+             CALL toReal(TRIM(par_val), ls_correction_factor, error)
+          END IF
+       CASE ("ls.rchi2.acceptable")
+          IF (PRESENT(ls_rchi2_acceptable)) THEN
+             CALL toReal(TRIM(par_val), ls_rchi2_acceptable, error)
+          END IF
+       CASE ("ls.element_mask")
+          IF (PRESENT(ls_element_mask)) THEN
+             ls_element_mask = .TRUE.
+             READ(par_val, *, iostat=err) ls_element_mask
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (20).", 1)
+             END IF
+          END IF
+       CASE ("ls.niter_major.max")
+          IF (PRESENT(ls_niter_major_max)) THEN
+             CALL toInt(TRIM(par_val), ls_niter_major_max, error)
+          END IF
+       CASE ("ls.niter_major.min")
+          IF (PRESENT(ls_niter_major_min)) THEN
+             CALL toInt(TRIM(par_val), ls_niter_major_min, error)
+          END IF
+       CASE ("ls.niter_minor")
+          IF (PRESENT(ls_niter_minor)) THEN
+             CALL toInt(TRIM(par_val), ls_niter_minor, error)
+          END IF
+
+
+          ! COVARIANCE SAMPLING PARAMETERS:
+       CASE ("cos.nsigma")
+          IF (PRESENT(cos_nsigma)) THEN
+             CALL toReal(TRIM(par_val), cos_nsigma, error)
+          END IF
+       CASE ("cos.norb")
+          IF (PRESENT(cos_norb)) THEN
+             CALL toInt(TRIM(par_val), cos_norb, error)
+          END IF
+       CASE ("cos.ntrial")
+          IF (PRESENT(cos_ntrial)) THEN
+             CALL toInt(TRIM(par_val), cos_ntrial, error)
+          END IF
+       CASE ("cos.gaussian")
+          IF (PRESENT(cos_gaussian)) THEN
+             READ(par_val, *, iostat=err) cos_gaussian
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (21).", 1)
+             END IF
+          END IF
+
+
+          ! SIMPLEX OPTIMIZATION PARAMETERS:
+       CASE ("smplx.tol")
+          IF (PRESENT(smplx_tol)) THEN
+             CALL toReal(TRIM(par_val), smplx_tol, error)
+          END IF
+       CASE ("smplx.niter")
+          IF (PRESENT(smplx_niter)) THEN
+             CALL toInt(TRIM(par_val), smplx_niter, error)
+          END IF
+       CASE ("smplx.force")
+          IF (PRESENT(smplx_force)) THEN
+             READ(par_val, *, iostat=err) smplx_force
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (22).", 1)
+             END IF
+          END IF
+       CASE ("smplx.similarity.tol")
+          IF (PRESENT(smplx_similarity_tol)) THEN
+             CALL toReal(TRIM(par_val), smplx_similarity_tol, error)
+          END IF
+
+
+          ! OBSERVATION SAMPLING PARAMETERS:
+       CASE ("os.norb")
+          IF (PRESENT(os_norb)) THEN
+             CALL toInt(TRIM(par_val), os_norb, error)
+          END IF
+       CASE ("os.ntrial")
+          IF (PRESENT(os_ntrial)) THEN
+             CALL toInt(TRIM(par_val), os_ntrial, error)
+          END IF
+       CASE ("os.sampling_type")
+          IF (PRESENT(os_sampling_type)) THEN
+             CALL toInt(TRIM(par_val), os_sampling_type, error)
+          END IF
+
+
+          ! PHYSICAL PARAMETERS:
+       CASE ("pp.H_estimation")
+          IF (PRESENT(pp_H_estimation)) THEN
+             READ(par_val, *, iostat=err) pp_H_estimation
+             IF (err /= 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "Could not read parameter value (25).", 1)
+             END IF
+          END IF
+       CASE ("pp.G")
+          IF (PRESENT(pp_G)) THEN
+             CALL toReal(TRIM(par_val), pp_G, error)
+          END IF
+       CASE ("pp.G_unc")
+          IF (PRESENT(pp_G_unc)) THEN
+             CALL toReal(TRIM(par_val), pp_G_unc, error)
+          END IF
+
+
+          ! PREDICTION PARAMETERS:
+       CASE ("eph.observatory.code")
+          IF (PRESENT(eph_obsy_code)) THEN
+             IF (LEN_TRIM(par_val) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "No codes specified for option 'eph.observatory.code'.", 1)
+                RETURN
+             END IF
+             i = 0
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (.NOT.ASSOCIATED(eph_obsy_code)) THEN
+                   ALLOCATE(eph_obsy_code(i), stat=err)
+                   IF (err /= 0) THEN
+                      error = .TRUE.
+                      CALL errorMessage("io / readConfigurationFile", &
+                           "Could not allocate memory.", 1)
+                      RETURN
+                   END IF
+                ELSE IF (SIZE(eph_obsy_code,dim=1) < i) THEN
+                   eph_obsy_code => reallocate(eph_obsy_code, 2*i)
+                END IF
+                eph_obsy_code(i) = TRIM(par_val(indx1:indx1+indx2-1))
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+             eph_obsy_code => reallocate(eph_obsy_code, i)
+          END IF
+
+       CASE ("eph.date")
+          IF (PRESENT(eph_date)) THEN
+             IF (LEN_TRIM(par_val) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "No dates specified for option 'eph.date'.", 1)
+                RETURN
+             END IF
+             i = 0
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (.NOT.ASSOCIATED(eph_date)) THEN
+                   ALLOCATE(eph_date(i), stat=err)
+                   IF (err /= 0) THEN
+                      error = .TRUE.
+                      CALL errorMessage("io / readConfigurationFile", &
+                           "Could not allocate memory.", 1)
+                      RETURN
+                   END IF
+                ELSE IF (SIZE(eph_date,dim=1) < i) THEN
+                   eph_date => reallocate(eph_date, 2*i)
+                END IF
+                CALL toInt(TRIM(par_val(indx1:indx1+3)), year, error)
+                CALL toInt(TRIM(par_val(indx1+4:indx1+5)), month, error)
+                CALL toReal(TRIM(par_val(indx1+6:indx1+indx2-1)), day, error)
+                IF (year >= 1972) THEN
+                   CALL NEW(eph_date(i), year, month, day, "UTC")
+                ELSE
+                   CALL NEW(eph_date(i), year, month, day, "UT1")
+                END IF
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+             eph_date => reallocate(eph_date, i)
+          END IF
+
+       CASE ("eph.dt_since_last_obs")
+          IF (PRESENT(eph_dt_since_last_obs)) THEN
+             IF (LEN_TRIM(par_val) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "No dt's specified for option 'eph.dt_since_last_obs'.", 1)
+                RETURN
+             END IF
+             i = 0
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (.NOT.ASSOCIATED(eph_dt_since_last_obs)) THEN
+                   ALLOCATE(eph_dt_since_last_obs(i), stat=err)
+                   IF (err /= 0) THEN
+                      error = .TRUE.
+                      CALL errorMessage("io / readConfigurationFile", &
+                           "Could not allocate memory.", 1)
+                      RETURN
+                   END IF
+                ELSE IF (SIZE(eph_dt_since_last_obs,dim=1) < i) THEN
+                   eph_dt_since_last_obs => reallocate(eph_dt_since_last_obs, 2*i)
+                END IF
+                CALL toReal(TRIM(par_val(indx1:indx1+indx2-1)), eph_dt_since_last_obs(i), error)
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+             eph_dt_since_last_obs => reallocate(eph_dt_since_last_obs, i)
+          END IF
+
+       CASE ("eph.lt_correction")
+          IF (PRESENT(eph_lt_correction)) THEN
+             ! Check for missing parameters
+             IF (LEN_TRIM(par_val) == 0) THEN
+                error = .TRUE.
+                CALL errorMessage("io / readConfigurationFile", &
+                     "No values specified for option 'eph.lt_correction'.", 1)
+                RETURN
+             END IF
+             i = 0
+             indx1 = 1
+             last = .FALSE.
+             CALL removeLeadingBlanks(par_val)
+             DO WHILE (.NOT.last)
+                ! Find the location of the next space: 
+                indx2 = INDEX(TRIM(par_val(indx1:))," ")
+                IF (indx2 == 0) THEN
+                   ! No more spaces left -> last parameter
+                   last = .TRUE.
+                   indx2 = LEN_TRIM(par_val(indx1:))
+                END IF
+                i = i + 1
+                IF (.NOT.ASSOCIATED(eph_lt_correction)) THEN
+                   ALLOCATE(eph_lt_correction(i), stat=err)
+                   IF (err /= 0) THEN
+                      error = .TRUE.
+                      CALL errorMessage("io / readConfigurationFile", &
+                           "Could not allocate memory.", 1)
+                      RETURN
+                   END IF
+                ELSE IF (SIZE(eph_lt_correction,dim=1) < i) THEN
+                   eph_lt_correction => reallocate(eph_lt_correction, 2*i)
+                END IF
+                READ(par_val(indx1:indx1+indx2-1), *, iostat=err) eph_lt_correction(i)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   CALL errorMessage("io / readConfigurationFile", &
+                        "Could not read parameter value (30).", 1)
+                   RETURN
+                END IF
+                ! Move starting index to the next parameter 
+                indx1 = indx1 + indx2
+                CALL removeLeadingBlanks(par_val(indx1:))
+             END DO
+             eph_lt_correction => reallocate(eph_lt_correction, i)
+          END IF
+
+       END SELECT
+       IF (error) THEN
+          CALL errorMessage("io / readConfigurationFile", &
+               "Problems with the following line:", 1)
+          IF (err_verb >= 1) THEN
+             WRITE(stderr,"(A)") TRIM(line)
+          END IF
+          RETURN
+       END IF
+    END DO
+
+  END SUBROUTINE readConfigurationFile
+
+
+
+
+
+  SUBROUTINE readDESOrbitFile(lu, norb, header, id_arr, orb_arr, H_arr)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: lu
+    INTEGER, INTENT(out) :: norb
+    CHARACTER(len=*), INTENT(out) :: header
+    CHARACTER(len=*), DIMENSION(:), INTENT(out) :: id_arr
+    TYPE (Orbit), DIMENSION(:), INTENT(out) :: orb_arr
+    REAL(bp), DIMENSION(:), INTENT(out) :: H_arr
+    TYPE (Time) :: epoch
+    CHARACTER(len=16) :: compcode, str
+    CHARACTER(len=8) :: frmt
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp) :: mjd_epoch, moid
+    INTEGER :: err, indx_, npar
+
+    IF (LEN(header) < 128) THEN
+       error = .TRUE.
+       CALL errorMessage("io / readDESOrbitFile", &
+            "Length of header variable must be at least 128 characters.", 1)
+       RETURN       
+    END IF
+
+    ! Read header if not yet known:
+    READ(lu, "(A)", iostat=err) header
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / readDESOrbitFile", &
+            "Could not read 1st header line of orbit file.", 1)
+       RETURN
+    END IF
+    IF (.NOT.(header(1:2) == "!!" .OR. header(1:1) == "#")) THEN
+       REWIND(lu)
+       header = " "
+    END IF
+
+    norb = 0
+    DO WHILE (norb + 1 <= SIZE(id_arr))
+       ! Read parameters found on a single line
+       READ(lu, *, iostat=err) id_arr(norb+1), frmt, elements, &
+            H_arr(norb+1), mjd_epoch, indx_, npar, moid, compcode
+       IF (err > 0) THEN
+          CALL toString(norb+1, str, error)
+          error = .TRUE.
+          CALL errorMessage("io / readDESOrbitFile", &
+               "Problem reading line #" // TRIM(str) // " of the data file.", 1)
+          RETURN
+       ELSE IF (err < 0) THEN
+          EXIT
+       ELSE IF (id_arr(norb+1)(1:1) == "#") THEN
+          CYCLE
+       END IF
+       CALL removeLeadingBlanks(id_arr(norb+1))
+       CALL NEW(epoch, mjd_epoch, "TT")
+       IF (error) THEN
+          CALL errorMessage("io / readDESOrbitFile", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       IF (frmt == "COM") THEN
+          elements(3:5) = elements(3:5)*rad_deg
+          CALL NEW(orb_arr(norb+1), elements, "cometary", "ecliptic", epoch)
+       ELSE IF (frmt == "COT") THEN
+          elements(3:6) = elements(3:6)*rad_deg
+          CALL NEW(orb_arr(norb+1), elements, "cometary_ta", "ecliptic", epoch)
+       ELSE IF (frmt == "KEP") THEN
+          elements(3:6) = elements(3:6)*rad_deg
+          CALL NEW(orb_arr(norb+1), elements, "keplerian", "ecliptic", epoch)
+       ELSE IF (frmt == "CAR") THEN
+          CALL NEW(orb_arr(norb+1), elements, "cartesian", "ecliptic", epoch)
+       ELSE IF (frmt == "CAREQ") THEN
+          CALL NEW(orb_arr(norb+1), elements, "cartesian", "equatorial", epoch)
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("io / readDESOrbitFile", &
+               "No such option available: " // TRIM(frmt), 1)
+          RETURN          
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / readDESOrbitFile", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(epoch)
+       norb = norb + 1
+    END DO
+
+  END SUBROUTINE readDESOrbitFile
+
+
+
+
+
+  SUBROUTINE readMPCOrbitFile(lu, norb, id_arr, orb_arr, HG_arr, arc_arr)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: lu
+    INTEGER, INTENT(out) :: norb
+    CHARACTER(len=*), DIMENSION(:), INTENT(out) :: id_arr
+    TYPE (Orbit), DIMENSION(:), INTENT(out) :: orb_arr
+    REAL(bp), DIMENSION(:,:), INTENT(out) :: HG_arr
+    REAL(bp), DIMENSION(:), INTENT(out) :: arc_arr
+
+    TYPE (Time) :: epoch
+    CHARACTER(len=256) :: line
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp) :: day, n
+    INTEGER :: err, y1, y2, year, month, nlines
+
+    ! Jump over header:
+    line = ""
+    nlines = 0
+    DO WHILE (line(1:5) /= "-----")
+       READ(lu, "(A)", iostat=err) line
+       IF (err > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "Could not jump over header line of MPC orbit file.", 1)
+          RETURN
+       ELSE IF (err < 0 .AND. nlines > 0) THEN
+          ! Probably no header present, let's try rewinding to
+          ! beginning of file and read orbits:
+          REWIND(lu)
+          EXIT
+       END IF
+       nlines = nlines + 1
+    END DO
+
+    norb = 0
+    DO WHILE (norb + 1 <= SIZE(id_arr))
+       ! Read parameters found on a single line
+       READ(lu, "(A)", iostat=err) line
+       IF (err > 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "Read error.", 1)
+          RETURN
+       ELSE IF (err < 0) THEN
+          EXIT
+       ELSE IF (line(1:1) == "#") THEN
+          CYCLE
+       ELSE IF (LEN_TRIM(line) == 0) THEN
+          CYCLE
+       END IF
+       norb = norb + 1
+       ! Designation or number
+       id_arr(norb) = line(1:7)
+       ! H
+       IF (LEN_TRIM(line(9:13)) == 0) THEN
+          HG_arr(norb,1) = 99.9_bp
+       ELSE
+          CALL toReal(line(9:13), HG_arr(norb,1), error)
+       END IF
+       ! G
+       IF (LEN_TRIM(line(15:19)) == 0) THEN
+          HG_arr(norb,2) = 9.9_bp
+       ELSE
+          CALL toReal(line(15:19), HG_arr(norb,2), error)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       ! Epoch
+       CALL decodeMPCDate(line(21:25), year, month, day)
+       CALL NEW(epoch, year, month, day, "TT")
+       IF (error) THEN
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       ! M
+       CALL toReal(line(27:35), elements(6), error)
+       ! ap
+       CALL toReal(line(38:46), elements(5), error)
+       ! an
+       CALL toReal(line(49:57), elements(4), error)
+       ! i
+       CALL toReal(line(60:68), elements(3), error)
+       ! e
+       CALL toReal(line(71:79), elements(2), error)
+       ! n
+       CALL toReal(line(81:91), n, error)       
+       ! a
+       CALL toReal(line(93:103), elements(1), error)
+       elements(3:6) = elements(3:6)*rad_deg
+       elements(4:6) = MODULO(elements(4:6),two_pi)
+       CALL NEW(orb_arr(norb), elements, "keplerian", "ecliptic", epoch)
+       IF (error) THEN
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "TRACE BACK (15):", 1)
+          WRITE(stderr,"(A)") TRIM(line)
+          RETURN
+       END IF
+       CALL NULLIFY(epoch)
+       IF (line(132:132) == "-") THEN
+          CALL toInt(line(128:131), y1, error)
+          CALL toInt(line(133:136), y2, error)
+          arc_arr(norb) = REAL(y2-y1)*day_year
+       ELSE
+          CALL toReal(line(128:131), arc_arr(norb), error)          
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / readMPCOrbitFile", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+    END DO
+
+  END SUBROUTINE readMPCOrbitFile
+
+
+
+
+
+  SUBROUTINE readOpenOrbOrbitFile(lu, header, element_type_in, id, orb, &
+       element_type_pdf, cov, pdf, rchi2, reg_apr, jac_sph_inv, &
+       jac_car_kep, jac_equ_kep, H, G, rho1, rho2, repetitions)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: lu
+    CHARACTER(len=*), DIMENSION(4), INTENT(inout) :: header
+    CHARACTER(len=*), INTENT(out) :: element_type_in
+    CHARACTER(len=*), INTENT(out) :: id
+    TYPE (Orbit), INTENT(out) :: orb
+    CHARACTER(len=*), INTENT(out), OPTIONAL :: element_type_pdf
+    REAL(bp), DIMENSION(:,:), INTENT(out), OPTIONAL :: cov
+    REAL(bp), INTENT(out), OPTIONAL :: pdf, rchi2, &
+         reg_apr, jac_sph_inv, jac_car_kep, jac_equ_kep, H, G, &
+         rho1, rho2
+    INTEGER, INTENT(out), OPTIONAL :: repetitions
+
+    TYPE (Time) :: t
+    CHARACTER(len=128) :: str
+    REAL(bp), DIMENSION(15) :: correlation
+    REAL(bp), DIMENSION(6) :: elements, stdev
+    REAL(bp) :: day, r, mjd
+    INTEGER :: year, month, err, i
+
+    correlation = 2.0_bp
+
+    IF (LEN(header(1)(:)) < 1024) THEN
+       error = .TRUE.
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "Length of header variable must be at least 1024.", 1)
+       RETURN       
+    END IF
+
+    ! Read header if not yet known:
+    IF (LEN_TRIM(header(1)) == 0) THEN
+       READ(lu, "(A)", iostat=err) header(1)(:)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Could not read 1st header line of orbit file.", 1)
+          RETURN
+       END IF
+       READ(lu, "(A)", iostat=err) header(2)(:)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Could not read 2nd header line of orbit file.", 1)
+          RETURN
+       END IF
+       READ(lu, "(A)", iostat=err) header(3)(:)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Could not read 3rd header line of orbit file.", 1)
+          RETURN
+       END IF
+       READ(lu, "(A)", iostat=err) header(4)(:)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Could not read 4th header line of orbit file.", 1)
+          RETURN
+       END IF
+    END IF
+
+    ! Read id, elements, and epoch
+    READ(lu,"(A16,6(1X,E21.14))", advance="no", iostat=err) id, &
+         elements
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "Read error (5).", 1)
+       RETURN
+    END IF
+    CALL removeLeadingBlanks(id)
+    DO i=1,LEN(id)
+       IF (IACHAR(id(i:i)) == 0) THEN
+          id(i:i) = CHAR(32)
+       END IF
+    END DO
+    IF (INDEX(header(4),"-0008-") /= 0) THEN
+       READ(lu,"(1X,I4,1X,I2,1X,F8.5)", advance="no", iostat=err) year, &
+            month, day
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (6).", 1)
+          RETURN
+       END IF
+       CALL NEW(t, year, month, day, "TT")
+    ELSE IF (INDEX(header(4),"-0074-") /= 0) THEN
+       READ(lu,"(1X,F16.10)", advance="no", iostat=err) mjd
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (7).", 1)
+          RETURN
+       END IF
+       CALL NEW(t, mjd, "TT")
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "Epoch not given or given in wrong format.", 1)
+       RETURN       
+    END IF
+    IF (error) THEN
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    IF (INDEX(header(4),"-0002-") /= 0 .AND. &
+         INDEX(header(4),"-0003-") /= 0 .AND. &
+         INDEX(header(4),"-0004-") /= 0 .AND. &
+         INDEX(header(4),"-0005-") /= 0 .AND. &
+         INDEX(header(4),"-0006-") /= 0 .AND. &
+         INDEX(header(4),"-0007-") /= 0) THEN
+       element_type_in = "keplerian"
+       elements(3:6) = elements(3:6)*rad_deg
+    ELSE IF (INDEX(header(4),"-0075-") /= 0 .AND. &
+         INDEX(header(4),"-0003-") /= 0 .AND. &
+         INDEX(header(4),"-0004-") /= 0 .AND. &
+         INDEX(header(4),"-0005-") /= 0 .AND. &
+         INDEX(header(4),"-0006-") /= 0 .AND. &
+         INDEX(header(4),"-0076-") /= 0) THEN
+       element_type_in = "cometary"
+       elements(3:5) = elements(3:5)*rad_deg
+    ELSE IF (INDEX(header(4),"-0039-") /= 0 .AND. &
+         INDEX(header(4),"-0040-") /= 0 .AND. &
+         INDEX(header(4),"-0041-") /= 0 .AND. &
+         INDEX(header(4),"-0042-") /= 0 .AND. &
+         INDEX(header(4),"-0043-") /= 0 .AND. &
+         INDEX(header(4),"-0044-") /= 0) THEN
+       element_type_in = "cartesian"
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "Orbital elements are unknown to the software.", 1)       
+       RETURN
+    END IF
+    CALL NEW(orb, elements, element_type_in, "ecliptic", copy(t))
+    IF (error) THEN
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t)
+    IF (INDEX(header(4),"-0038-") /= 0) THEN
+       str = " "
+       READ(lu,"(1X,A12)", advance="no", iostat=err) str(1:12)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (10).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(element_type_pdf)) THEN
+          element_type_pdf = str(1:12)
+       END IF
+    END IF
+    stdev = -1.0_bp
+    IF (INDEX(header(4),"-0009-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(1)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (10).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0010-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(2)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (15).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0011-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(3)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (20).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0012-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(4)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (25).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0013-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(5)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (30).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0014-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) stdev(6)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (35).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0015-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(1)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (40).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0016-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(2)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (45).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0017-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(3)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (50).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0018-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(4)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (55).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0019-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(5)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (60).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0020-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(6)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (65).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0021-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(7)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (70).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0022-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(8)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (75).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0023-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(9)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (80).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0024-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(10)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (85).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0025-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(11)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (90).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0026-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(12)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (95).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0027-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(13)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (100).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0028-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(14)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (105).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0029-") /= 0) THEN
+       READ(lu,"(1X,E15.7)", advance="no", iostat=err) correlation(15)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (110).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(cov)) THEN
+       IF (INDEX(header(4),"-0009-") /= 0) THEN
+          ! Standard deviations appear to be present, so build the
+          ! covariance using the available information.
+          IF (element_type_in == "keplerian") THEN
+             stdev(3:6) = stdev(3:6)*rad_deg
+          END IF
+          DO i=1,6
+             cov(i,i) = stdev(i)**2
+          END DO
+          cov(1,2:6) = stdev(1)*stdev(2:6)*correlation(1:5)
+          cov(2:6,1) = cov(1,2:6)
+          cov(2,3:6) = stdev(2)*stdev(3:6)*correlation(6:9)
+          cov(3:6,2) = cov(2,3:6)
+          cov(3,4:6) = stdev(3)*stdev(4:6)*correlation(10:12)
+          cov(4:6,3) = cov(3,4:6)
+          cov(4,5:6) = stdev(4)*stdev(5:6)*correlation(13:14)
+          cov(5:6,4) = cov(4,5:6)
+          cov(5,6) = stdev(5)*stdev(6)*correlation(15)
+          cov(6,5) = cov(5,6)
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0030-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (115).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(pdf)) THEN
+          pdf = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0031-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (120).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(rchi2)) THEN
+          rchi2 = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0032-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (125).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(reg_apr)) THEN
+          reg_apr = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0033-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (130).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(jac_sph_inv)) THEN
+          jac_sph_inv = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0034-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (135).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(jac_car_kep)) THEN
+          jac_car_kep = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0035-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (140).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(jac_equ_kep)) THEN
+          jac_equ_kep = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0036-") /= 0) THEN
+       !READ(lu,"(1X,F9.6)", advance="no", iostat=err) r
+       READ(lu, "(1X,A9)", advance="no", iostat=err) str(1:9)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (145).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(H)) THEN
+          CALL toReal(str(1:9), H, error)
+          IF (error) THEN
+             CALL errorMessage("io / readOpenOrbOrbitFile", &
+                  "Conversion error (145).", 1)
+             RETURN
+          END IF
+          !          H = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0037-") /= 0) THEN
+       READ(lu,"(1X,F9.6)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (150).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(G)) THEN
+          G = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0070-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (150).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(rho1)) THEN
+          rho1 = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0071-") /= 0) THEN
+       READ(lu,"(1X,E18.10)", advance="no", iostat=err) r
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (155).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(rho2)) THEN
+          rho2 = r
+       END IF
+    END IF
+    IF (INDEX(header(4),"-0077-") /= 0) THEN
+       READ(lu,"(1X,I9)", advance="no", iostat=err) i
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / readOpenOrbOrbitFile", &
+               "Read error (155).", 1)
+          RETURN
+       END IF
+       IF (PRESENT(repetitions)) THEN
+          repetitions = i
+       END IF
+    END IF
+    READ(lu,"(1X)",iostat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / readOpenOrbOrbitFile", &
+            "Read error (160).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE readOpenOrbOrbitFile
+
+
+
+
+
+  SUBROUTINE writeDESOrbitFile(lu, print_header, element_type_out, &
+       id, orb, H, indx, npar, moid, compcode)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: lu
+    LOGICAL, INTENT(in) :: print_header
+    CHARACTER(len=*), INTENT(in) :: element_type_out
+    CHARACTER(len=*), INTENT(in) :: id
+    TYPE (Orbit), INTENT(in) :: orb
+    REAL(bp), INTENT(in) :: H
+    INTEGER, INTENT(in), OPTIONAL :: indx, npar
+    REAL(bp), INTENT(in), OPTIONAL :: moid
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: compcode
+
+    TYPE (Time) :: epoch
+    CHARACTER(len=32) :: compcode_
+    CHARACTER(len=3) :: frmt
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp) :: mjd_tt, moid_
+    INTEGER :: err, indx_, npar_
+
+    elements = getElements(orb, element_type_out, "ecliptic")
+    IF (error) THEN
+       CALL errorMessage("io / writeDESOrbitFile", &
+            "TRACE BACK", 1)
+       RETURN       
+    END IF
+    IF (element_type_out == "cometary") THEN
+       frmt = "COM"
+       elements(3:5) = elements(3:5)/rad_deg
+    ELSE IF (element_type_out == "keplerian") THEN
+       frmt = "KEP"
+       elements(3:6) = elements(3:6)/rad_deg
+    ELSE IF (element_type_out == "cartesian") THEN
+       frmt = "CAR"
+    ELSE
+       error = .TRUE.
+       CALL errorMessage("io / writeDESOrbitFile", &
+            "Element type '" // TRIM(element_type_out) // &
+            "' not yet supported (5).", 1)
+       RETURN
+    END IF
+    epoch = getTime(orb)
+    mjd_tt = getMJD(epoch, "TT")
+    CALL NULLIFY(epoch)
+    IF (PRESENT(indx)) THEN
+       indx_ = indx
+    ELSE
+       indx_ = 1
+    END IF
+    IF (PRESENT(npar)) THEN
+       npar_ = npar
+    ELSE
+       npar_ = 6
+    END IF
+    IF (PRESENT(moid)) THEN
+       moid_ = moid
+    ELSE
+       moid_ = -1.0_bp
+    END IF
+    IF (PRESENT(compcode)) THEN
+       compcode_ = compcode
+    ELSE
+       compcode_ = "OPENORB"
+    END IF
+    IF (print_header) THEN
+       SELECT CASE (element_type_out)
+       CASE ("cometary")
+          WRITE(lu,"(A)") "!!OID FORMAT q e i node argperi t_p H t_0 INDEX N_PAR MOID COMPCODE"
+       CASE ("keplerian")
+          WRITE(lu,"(A)") "!!OID FORMAT a e i node argperi M H t_0 INDEX N_PAR MOID COMPCODE"
+       CASE ("cartesian")
+          WRITE(lu,"(A)") "!!OID FORMAT x y z dx/dt dy/dt dz/dt H t_0 INDEX N_PAR MOID COMPCODE"
+       CASE default
+          error = .TRUE.
+          CALL errorMessage("io / writeDESOrbitFile", &
+               "Element type '" // TRIM(element_type_out) // &
+               "' not yet supported (10).", 1)
+          RETURN
+       END SELECT
+    END IF
+    WRITE(lu,"(2(A,1X),8(E22.15,1X),2(I0,1X),E22.15,1X,A)",iostat=err) &
+         TRIM(id), TRIM(frmt), elements, H, mjd_tt, indx_, npar_, &
+         moid_, TRIM(compcode_)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeDESOrbitFile", &
+            "Write error (5).", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE writeDESOrbitFile
+
+
+
+
+
+  SUBROUTINE writeNominalSolution(storb, obss, element_type, lu)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)            :: storb
+    TYPE (Observations), INTENT(in)                  :: obss
+    CHARACTER(len=*), INTENT(in)                     :: element_type
+    INTEGER, INTENT(in)                              :: lu
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t
+    CHARACTER(len=DESIGNATION_LEN) :: &
+         id
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: &
+         element_type_
+    CHARACTER(len=DYN_MODEL_LEN) :: &    
+         dyn_model
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         integrator
+    CHARACTER(len=64) :: &
+         str
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         inform_mat_obs_bd
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         residuals
+    REAL(bp), DIMENSION(6,6)   :: cov, corr
+    REAL(bp), DIMENSION(6)     :: elements, sigmas
+    REAL(bp) :: obsarc, rchi2
+    INTEGER :: k, l, err
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL, DIMENSION(6) :: ls_element_mask
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeNominalSolution", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeNominalSolution", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    orb = getNominalOrbit(storb)
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (105)", 1)
+       RETURN
+    END IF
+    t = getTime(orb)
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (110)", 1)
+       RETURN
+    END IF
+
+    element_type_ = TRIM(element_type)
+    str = "#CAR  "
+    elements = getElements(orb, TRIM(element_type_))
+    IF (error .AND. TRIM(element_type_) == "cartesian") THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (111)", 1)
+       RETURN       
+    ELSE IF (error .AND. TRIM(element_type_) == "keplerian") THEN
+       error = .FALSE.
+       element_type_ = "cartesian"
+       elements = getElements(orb, TRIM(element_type_), "ecliptic")
+    ELSE IF (.NOT.error .AND. TRIM(element_type_) == "keplerian") THEN
+       elements(3:6) = elements(3:6)/rad_deg
+       str = "#KEP  "
+    END IF
+    id = getID(obss)
+!!$    obsarc = getObservationalTimespan(obss)
+!!$    WRITE(lu,"(A,F14.4)") "#Observational arc = ",obsarc
+
+    CALL getParameters(orb, dyn_model=dyn_model, integrator=integrator)
+    WRITE(lu,"(A,A)") "#DYNAMICAL MODEL = ", TRIM(dyn_model)
+    IF (TRIM(dyn_model) == 'n-body') THEN
+       WRITE(lu,"(A,A)") "#INTEGRATOR = ", TRIM(integrator)
+    END IF
+    WRITE(lu,"(A)") "#"
+
+    IF (element_type_ == "keplerian") THEN
+       WRITE(lu,"(A6,2X,A7,1X,7(3X,A12,2X))") str(1:6), id(1:7), & 
+            "a [AU]", "e", "i [deg]", "node [deg]", "ap [deg]", & 
+            "M [deg]", "Epoch"
+    ELSE
+       WRITE(lu,"(A6,2X,A7,1X,7(3X,A12,2X))") str(1:6), id(1:7), & 
+            "x [AU]", "y [AU]", "z [AU]", "dx/dt [AU/d]", & 
+            "dy/dt [AU/d]", "dz/dt [AU/d]", "Epoch" 
+    END IF
+    WRITE(lu,"(A6,2X,A7,1X,6(F16.12,1X),A,'TT')") &
+         str(1:6), id(1:7), elements, getCalendarDateString(t,"tt")
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (115)", 1)
+       RETURN
+    END IF
+    CALL NULLIFY(t)
+    WRITE(lu,"(A)") "#"
+    ! STANDARD DEVIATIONS:
+    WRITE(lu,"(A6,2X,A7,1X)",advance="no") "#STDEV", id(1:7)
+    IF (TRIM(element_type_) == "keplerian") THEN
+       cov = getCovarianceMatrix(storb, TRIM(element_type_))
+    ELSE
+       cov = getCovarianceMatrix(storb, TRIM(element_type_), "ecliptic")
+    END IF
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (116)", 1)
+       RETURN
+    END IF
+    DO l=1,6
+       sigmas(l) = SQRT(cov(l,l))
+       IF (TRIM(element_type_) == "keplerian" .AND. l >= 3) THEN
+          WRITE(lu,"(F16.12,1X)",advance="no") sigmas(l)/rad_deg
+       ELSE
+          WRITE(lu,"(F16.12,1X)",advance="no") sigmas(l)
+       END IF
+    END DO
+    WRITE(lu,*)
+    WRITE(lu,"(A)") "#"
+    ! CORRELATIONS:
+    DO l=1,6
+       DO k=1,6
+          corr(l,k) = cov(l,k) / &
+               (sigmas(l)*sigmas(k))
+       END DO
+    END DO
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(1,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(2,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(3,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(4,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(5,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,F16.12))") &
+         "#CORR ", id(1:7), corr(6,1:6)
+    WRITE(lu,"(A)") "#"
+    ! COVARIANCE:
+    IF (TRIM(element_type_) == "keplerian") THEN
+       cov(3:6,:) = cov(3:6,:)/rad_deg
+       cov(:,3:6) = cov(:,3:6)/rad_deg
+    END IF
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(1,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(2,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(3,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(4,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(5,1:6)
+    WRITE(lu,"(A6,2X,A7,6(1X,E16.8))") &
+         "#COV  ", id(1:7), cov(6,1:6)
+    WRITE(lu,"(A)") "#"
+    ! WRITE RESIDUAL BLOCK:
+    obs_masks => getObservationMasks(storb)
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (120)", 1)
+       RETURN
+    END IF
+    WRITE(str,"(A6,2X,A7)") "#RES  ", id(1:7)
+    CALL writeResidualBlock(orb, obss, obs_masks, &
+         TRIM(str), lu, residuals)
+    IF (error) THEN
+       CALL errorMessage("io / writeNominalSolution", &
+            "TRACE BACK (125)", 1)
+       RETURN
+    END IF
+    WRITE(lu,"(A)") "#"
+    ! WRITE RMS:
+    WRITE(lu,"(A6,2X,A7,3X,2(F11.6,1X))") "#RMS  ", id(1:7), &
+         SQRT(SUM(residuals(:,2)**2.0_bp,obs_masks(:,2) &
+         .AND. obs_masks(:,3))/COUNT(obs_masks(:,2) &
+         .AND. obs_masks(:,3)))/rad_asec, &
+         SQRT(SUM(residuals(:,3)**2.0_bp,obs_masks(:,2) &
+         .AND. obs_masks(:,3))/COUNT(obs_masks(:,2) &
+         .AND. obs_masks(:,3)))/rad_asec
+    WRITE(lu,"(A)") "#"
+    ! WRITE REDUCED CHI2:
+    CALL getParameters(storb, ls_element_mask=ls_element_mask)
+    inform_mat_obs_bd => getBlockDiagInformationMatrix(obss)
+    rchi2 = chi_square(residuals, inform_mat_obs_bd, obs_masks, errstr) - &
+         COUNT(obs_masks)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeNominalSolution", &
+            "Could not compute chi2. " // TRIM(errstr), 1)
+       errstr = ""
+       RETURN
+    END IF
+    WRITE(lu,"(A6,2X,A7,1X,F14.6)") "#RCHI2", id(1:7), rchi2
+    WRITE(lu,"(A)") "#"
+    DEALLOCATE(inform_mat_obs_bd, stat=err)
+    ! WRITE OBSERVATIONAL TIMESPAN:
+    obsarc = getObservationalTimespan(obss)
+    WRITE(lu,"(A7,1X,A7,1X,F14.4)") "#OBSARC", id(1:7), obsarc
+    WRITE(lu,*)
+
+    DEALLOCATE(obs_masks, stat=err)
+    DEALLOCATE(residuals, stat=err)
+    CALL NULLIFY(orb)
+
+  END SUBROUTINE writeNominalSolution
+
+
+
+
+
+!!$  subroutine writeMercuryOrbitFile(lu, print_header, type, &
+!!$       element_type_out, id, orb, mass, close_encounter_threshold,)
+!!$
+!!$    implicit none
+!!$    
+!!$    if (print_header) then
+!!$       write(lu,"(A)") ")O+_06 Big-body initial data  (WARNING: Do not delete this line!!)"
+!!$       write(lu,"(A)") ") Lines beginning with `)' are ignored."
+!!$       write(lu,"(A)") ")---------------------------------------------------------------------"
+!!$       write(lu,"(A)") " style (Cartesian, Asteroidal, Cometary) = Cartesian"
+!!$       write(lu,"(A)") " epoch (in days) = 2451000.5"
+!!$       write(lu,"(A)") ")---------------------------------------------------------------------"
+!!$    end if
+!!$    write(lu,"(A,1X,'m=',F)") trim(id), , 
+!!$    
+!!$
+!!$  end subroutine writeMercuryOrbitFile
+
+
+
+
+
+  SUBROUTINE writeOpenOrbOrbitFile(lu, print_header, element_type_out, &
+       id, orb, element_type_pdf, cov, pdf, rchi2, reg_apr, &
+       jac_sph_inv, jac_car_kep, jac_equ_kep, H, G, rho1, rho2, &
+       rms, npdf, mjd, repetitions)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: lu
+    LOGICAL, INTENT(in) :: print_header
+    CHARACTER(len=*), INTENT(in) :: element_type_out
+    CHARACTER(len=*), INTENT(in) :: id
+    TYPE (Orbit), INTENT(in) :: orb
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: element_type_pdf
+    REAL(bp), DIMENSION(:,:), INTENT(in), OPTIONAL :: cov
+    REAL(bp), INTENT(in), OPTIONAL :: pdf, rchi2, reg_apr, &
+         jac_sph_inv, jac_car_kep, jac_equ_kep, H, G, rho1, rho2, &
+         rms, npdf
+    INTEGER, INTENT(in), OPTIONAL :: repetitions
+    LOGICAL, INTENT(in), OPTIONAL :: mjd
+
+    TYPE (Time) :: t
+    CHARACTER(len=1024), DIMENSION(4) :: header
+    REAL(bp), DIMENSION(6) :: elements, stdev
+    REAL(bp) :: day, jac, mjd_tt
+    INTEGER :: year, month, err, indx, i, j
+
+    ! Define format for output and construct header:
+    IF (print_header) THEN
+       indx = 1
+       header(1:4)(1:LEN(header(1))) = " "
+       header(1)(indx:indx+16) = "#    Number     "
+       header(2)(indx:indx+16) = "#      or       "
+       header(3)(indx:indx+16) = "#  designation  "
+       header(4)(indx:indx+16) = "#-----0001-----<"
+       indx = indx + 16
+       IF (element_type_out == "keplerian" .OR. element_type_out == "cometary") THEN
+          IF (element_type_out == "keplerian") THEN
+             header(1)(indx:indx+22) = "   Semimajor axis a   "
+             header(2)(indx:indx+22) = "                      "
+             header(3)(indx:indx+22) = "         [AU]         "
+             header(4)(indx:indx+22) = ">--------0002--------<"
+          ELSE ! cometary
+             header(1)(indx:indx+22) = " Periapsis distance q "
+             header(2)(indx:indx+22) = "                      "
+             header(3)(indx:indx+22) = "         [AU]         "
+             header(4)(indx:indx+22) = ">--------0075--------<"
+          END IF
+          indx = indx + 22
+          header(1)(indx:indx+22) = "    Eccentricity e    "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">---------0003-------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "     Inclination i    "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0004--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "     Longitude of     "
+          header(2)(indx:indx+22) = "   Ascending Node O   "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0005--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "      Argument of     "
+          header(2)(indx:indx+22) = "      Periapsis o     "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0006--------<"
+          indx = indx + 22
+          IF (element_type_out == "keplerian") THEN
+             header(1)(indx:indx+22) = "     Mean Anomaly M   "
+             header(2)(indx:indx+22) = "                      "
+             header(3)(indx:indx+22) = "         [deg]        "
+             header(4)(indx:indx+22) = ">--------0007--------<"
+          ELSE ! cometary
+             header(1)(indx:indx+22) = " Time of periapsis t0 "
+             header(2)(indx:indx+22) = "                      "
+             header(3)(indx:indx+22) = "         [MJD]        "
+             header(4)(indx:indx+22) = ">--------0076--------<"             
+          END IF
+          indx = indx + 22
+       ELSE IF (element_type_out == "cartesian") THEN
+          header(1)(indx:indx+22) = "      Ecliptic x      "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [AU]         "
+          header(4)(indx:indx+22) = ">--------0039--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "      Ecliptic y      "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [AU]         "
+          header(4)(indx:indx+22) = ">--------0040--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "      Ecliptic z      "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [AU]         "
+          header(4)(indx:indx+22) = ">--------0041--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "    Ecliptic dx/dt    "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "        [AU/d]        "
+          header(4)(indx:indx+22) = ">--------0042--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "    Ecliptic dy/dt    "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "        [AU/d]        "
+          header(4)(indx:indx+22) = ">--------0043--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "    Ecliptic dz/dt    "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "        [AU/d]        "
+          header(4)(indx:indx+22) = ">--------0044--------<"
+          indx = indx + 22
+       ELSE IF (element_type_out == "delaunay") THEN
+          !!   l      = Mean Motion (Mean Anomaly)
+          !!   g      = Argument of Periapsis
+          !!   &theta = Longitude of the Ascending Node
+          !!   L      = sqrt(mu*(Semimajor Axis)) = related to the 
+          !!                                        two-body orbital energy
+          !!   G      = L*sqrt(1-Eccentricity^2)  = magnitude of the orbital 
+          !!                                        angular momentum
+          !!   &Theta = G*cos(Inclination)        = z-component of the orbital 
+          !!                                        angular momentum
+          header(1)(indx:indx+22) = "           l          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0045--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           g          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0046--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "         theta        "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0047--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           L          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0048--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           G          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0049--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "         Theta        "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0050--------<"
+          indx = indx + 22
+       ELSE IF (element_type_out == "poincare") THEN
+          !! Output Poincaré elements calculated from Delaunay's
+          !! elements. The mass of the target body is assumed to be negligible
+          !! compared to the mass of the Sun.
+          !  (&radic = square root)
+          !!
+          !! &Lambda = L
+          !! &xi     = &radic(2(L - G)) * cos(g + &theta)
+          !! p       = &radic(2(G - &Theta)) * cos(&theta)
+          !! &lambda = l + g + &theta
+          !! &eta    = -&radic(2(L - G)) * sin(g + &theta)
+          !! q       = -&radic(2(G - &Theta)) * sin(&theta)
+          header(1)(indx:indx+22) = "        Lambda        "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0051--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "          xi          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0052--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           p          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0053--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "        lambda        "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0054--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "          eta         "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0055--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           q          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0056--------<"
+          indx = indx + 22
+       ELSE IF (element_type_out == "equinoctial") THEN
+          !! Output equinoctial elements.
+          header(1)(indx:indx+22) = "   Semimajor axis a   "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "         [AU]         "
+          header(4)(indx:indx+22) = ">--------0057--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           h          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0058--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           k          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0059--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           p          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0060--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "           q          "
+          header(2)(indx:indx+22) = "                      "
+          header(3)(indx:indx+22) = "                      "
+          header(4)(indx:indx+22) = ">--------0061--------<"
+          indx = indx + 22
+          header(1)(indx:indx+22) = "    Mean longitude    "
+          header(2)(indx:indx+22) = "        lambda        "
+          header(3)(indx:indx+22) = "         [deg]        "
+          header(4)(indx:indx+22) = ">--------0062--------<"
+          indx = indx + 22
+       ELSE
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Output orbital elements are unknown to the software.", 1)       
+          RETURN          
+       END IF
+       IF (PRESENT(mjd)) THEN
+          IF (mjd) THEN
+             header(1)(indx:indx+17) = "    Epoch (TT)   "
+             header(2)(indx:indx+17) = "       MJD       "
+             header(3)(indx:indx+17) = "                 "
+             header(4)(indx:indx+17) = ">------0074-----<"
+             indx = indx + 17             
+          ELSE
+             header(1)(indx:indx+17) = "    Epoch (TT)   "
+             header(2)(indx:indx+17) = " YYYY MM DD.ddddd"
+             header(3)(indx:indx+17) = "                 "
+             header(4)(indx:indx+17) = ">------0008-----<"
+             indx = indx + 17
+          END IF
+       ELSE
+          header(1)(indx:indx+17) = "    Epoch (TT)   "
+          header(2)(indx:indx+17) = " YYYY MM DD.ddddd"
+          header(3)(indx:indx+17) = "                 "
+          header(4)(indx:indx+17) = ">------0008-----<"
+          indx = indx + 17
+       END IF
+       IF (PRESENT(element_type_pdf)) THEN
+          header(1)(indx:indx+13) = "  Inversion  "
+          header(2)(indx:indx+13) = "   orbital   "
+          header(3)(indx:indx+13) = "  elements   "
+          header(4)(indx:indx+13) = ">----0038---<"
+          indx = indx + 13
+       END IF
+       IF (PRESENT(cov)) THEN
+          header(1)(indx:indx+16) = "    sigma e1    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0009-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "    sigma e2    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0011-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "    sigma e3    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0010-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "    sigma e4    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0012-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "    sigma e5    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0013-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "    sigma e6    "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0014-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e1,e2)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0015-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e1,e3)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0016-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e1,e4)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0017-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e1,e5)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0018-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e1,e6)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0019-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e2,e3)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0020-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e2,e4)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0021-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e2,e5)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0022-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e2,e6)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0023-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e3,e4)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0024-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e3,e5)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0025-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e3,e6)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0026-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e4,e5)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0027-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e4,e6)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0028-----<"
+          indx = indx + 16
+          header(1)(indx:indx+16) = "   cor(e5,e6)   "
+          header(2)(indx:indx+16) = "                "
+          header(3)(indx:indx+16) = "                "
+          header(4)(indx:indx+16) = ">-----0029-----<"
+          indx = indx + 16
+       END IF
+       IF (PRESENT(pdf)) THEN
+          header(1)(indx:indx+19) = "    Unnormalized   "
+          header(2)(indx:indx+19) = "       p.d.f       "
+          header(3)(indx:indx+19) = "                   "
+          header(4)(indx:indx+19) = ">-------0030------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(rchi2)) THEN
+          header(1)(indx:indx+19) = "    Reduced chi2   "
+          header(2)(indx:indx+19) = "                   "
+          header(3)(indx:indx+19) = "                   "
+          header(4)(indx:indx+19) = ">-------0031------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(reg_apr)) THEN
+          header(1)(indx:indx+19) = "    Regularizing   "
+          header(2)(indx:indx+19) = "       apriori     "
+          header(3)(indx:indx+19) = "                   "
+          header(4)(indx:indx+19) = ">-------0032------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(jac_sph_inv)) THEN
+          header(1)(indx:indx+19) = "    Determinant    "
+          header(2)(indx:indx+19) = "    of Jacobian    "
+          header(3)(indx:indx+19) = "    (sph/inv.elm.) "
+          header(4)(indx:indx+19) = ">-------0033------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(jac_car_kep)) THEN
+          header(1)(indx:indx+19) = "    Determinant    "
+          header(2)(indx:indx+19) = "    of Jacobian    "
+          header(3)(indx:indx+19) = "     (car/kep)     "
+          header(4)(indx:indx+19) = ">-------0034------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(jac_equ_kep)) THEN
+          header(1)(indx:indx+19) = "    Determinant    "
+          header(2)(indx:indx+19) = "    of Jacobian    "
+          header(3)(indx:indx+19) = "     (equ/kep)     "
+          header(4)(indx:indx+19) = ">-------0035------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(H)) THEN
+          header(1)(indx:indx+10) = " Absolute "
+          Header(2)(indx:indx+10) = " magnitude"
+          header(3)(indx:indx+10) = "     H    "
+          header(4)(indx:indx+10) = ">---0036-<"
+          indx = indx + 10
+       END IF
+       IF (PRESENT(G)) THEN
+          header(1)(indx:indx+10) = "  Slope   "
+          header(2)(indx:indx+10) = " parameter"
+          header(3)(indx:indx+10) = "     G    "
+          header(4)(indx:indx+10) = ">---0037-<"
+          indx = indx + 10
+       END IF
+       IF (PRESENT(rho1)) THEN
+          header(1)(indx:indx+19) = "    Distance at    "
+          header(2)(indx:indx+19) = "    first epoch    "
+          header(3)(indx:indx+19) = "    in Ranging     "
+          header(4)(indx:indx+19) = ">-------0070------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(rho2)) THEN
+          header(1)(indx:indx+19) = "    Distance at    "
+          header(2)(indx:indx+19) = "    second epoch   "
+          header(3)(indx:indx+19) = "    in Ranging     "
+          header(4)(indx:indx+19) = ">-------0071------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(rms)) THEN
+          header(1)(indx:indx+13) = "  O-C resid. "
+          header(2)(indx:indx+13) = "     RMS     "
+          header(3)(indx:indx+13) = "   [arcsec]  "
+          header(4)(indx:indx+13) = ">----0072---<"
+          indx = indx + 13
+       END IF
+       IF (PRESENT(npdf)) THEN
+          header(1)(indx:indx+19) = "     Normalized    "
+          header(2)(indx:indx+19) = "       p.d.f.      "
+          header(3)(indx:indx+19) = "                   "
+          header(4)(indx:indx+19) = ">-------0073------<"
+          indx = indx + 19
+       END IF
+       IF (PRESENT(repetitions)) THEN
+          header(1)(indx:indx+12) = " Repeated "
+          header(2)(indx:indx+12) = "  in MCMC "
+          header(3)(indx:indx+12) = " sampling "
+          header(4)(indx:indx+12) = ">--0077--<"
+          indx = indx + 10
+       END IF
+
+       WRITE(lu, "(A)", iostat=err) TRIM(header(1))
+       WRITE(lu, "(A)", iostat=err) TRIM(header(2))
+       WRITE(lu, "(A)", iostat=err) TRIM(header(3))
+       WRITE(lu, "(A)", iostat=err) TRIM(header(4))
+    END IF
+    elements = getElements(orb, element_type_out, frame="ecliptic")
+    IF (error) THEN
+       CALL errorMessage("io / writeOpenOrbOrbitFile", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    IF (element_type_out == "keplerian") THEN
+       elements(3:6) = elements(3:6)/rad_deg
+    ELSE IF (element_type_out == "cometary") THEN
+       elements(3:5) = elements(3:5)/rad_deg
+    ELSE IF (element_type_out == "delaunay") THEN
+       elements(1:3) = elements(1:3)/rad_deg
+    ELSE IF (element_type_out == "poincare") THEN
+       elements(4) = elements(4)/rad_deg
+    ELSE IF (element_type_out == "equinoctial") THEN
+       elements(6) = elements(6)/rad_deg
+    END IF
+    t = getTime(orb)
+    IF (error) THEN
+       CALL errorMessage("io / writeOpenOrbOrbitFile", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    IF (PRESENT(mjd)) THEN
+       IF (mjd) THEN
+          mjd_tt = getMJD(t, "TT")
+          WRITE(lu, "(A16,6(1X,E21.14),1X,F16.8)", &
+               advance="no", iostat=err) id, elements(1:6), mjd_tt
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeOpenOrbOrbitFile", &
+                  "Write error (4).", 1)
+             RETURN
+          END IF
+          CALL NULLIFY(t)
+       END IF
+    END IF
+    IF (exist(t)) THEN ! MJD not requested...
+       CALL getCalendarDate(t, "tdt", year, month, day)
+       IF (error) THEN
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(t)
+       WRITE(lu, "(A16,6(1X,E21.14),1X,I4,1X,I2,1X,F8.5)", &
+            advance="no", iostat=err) id, elements(1:6), year, month, &
+            day
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (5).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(element_type_pdf)) THEN
+       IF (LEN_TRIM(element_type_pdf) > 12) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Type description of orbital elements used in inversion too long.", 1)
+          RETURN
+       END IF
+       WRITE(lu, "(1X,A12)", advance="no", iostat=err) element_type_pdf
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (20).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(cov)) THEN
+       stdev = (/ (SQRT(cov(i,i)), i=1,6) /)
+       IF (element_type_out == "keplerian") THEN
+          WRITE(lu, "(6(1X,E15.7))", advance="no", iostat=err) &
+               stdev(1:2), stdev(3:6)/rad_deg
+       ELSE
+          WRITE(lu, "(6(1X,E15.7))", advance="no", iostat=err) &
+               stdev(1:6)
+       END IF
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (10).", 1)
+          RETURN
+       END IF
+       DO i=1,5
+          DO j=i+1,6
+             IF (stdev(i) == 0.0_bp .OR. stdev(j) == 0.0_bp) THEN
+                WRITE(lu, "(1X,E15.7)", advance="no", iostat=err) 0.0_bp
+             ELSE                
+                WRITE(lu, "(1X,E15.7)", advance="no", iostat=err) cov(i,j)/(stdev(i)*stdev(j))
+             END IF
+          END DO
+       END DO
+    END IF
+    IF (PRESENT(pdf)) THEN
+       jac = 1.0_bp
+       IF (PRESENT(element_type_pdf)) THEN
+          IF (element_type_pdf == "cartesian" .AND. &
+               element_type_out == "keplerian") THEN
+             IF (PRESENT(jac_car_kep)) THEN
+                jac = jac_car_kep
+             ELSE
+                error = .TRUE.
+                CALL errorMessage("io / writeOpenOrbOrbitFile", &
+                     "Jacobian between Cartesian and Keplerian " // &
+                     "elements needed, but missimg.", 1)
+                RETURN
+             END IF
+          ELSE IF (element_type_pdf == "keplerian" .AND. &
+               element_type_out == "cartesian") THEN
+             IF (PRESENT(jac_car_kep)) THEN
+                jac = 1.0_bp/jac_car_kep
+             ELSE
+                error = .TRUE.
+                CALL errorMessage("io / writeOpenOrbOrbitFile", &
+                     "Jacobian between Cartesian and Keplerian " // &
+                     "elements needed, but missimg.", 1)
+                RETURN
+             END IF
+          END IF
+          WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) pdf*jac
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeOpenOrbOrbitFile", &
+                  "Write error (15).", 1)
+             RETURN
+          END IF
+       ELSE          
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Missing type of orbital elements corresponding to p.d.f.", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(rchi2)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) rchi2
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (20).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(reg_apr)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) reg_apr
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (25).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jac_sph_inv)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) jac_sph_inv
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (30).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jac_car_kep)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) jac_car_kep
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (35).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(jac_equ_kep)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) jac_equ_kep
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (40).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(H)) THEN
+       WRITE(lu, "(1X,F9.5)", advance="no", iostat=err) H
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (45).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(G)) THEN
+       WRITE(lu, "(1X,F9.6)", advance="no", iostat=err) G
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (50).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(rho1)) THEN
+       WRITE(lu, '(1X,E18.10)', advance='no', iostat=err) rho1
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (55).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(rho2)) THEN
+       WRITE(lu, '(1X,E18.10)', advance='no', iostat=err) rho2
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (60).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(rms)) THEN
+       WRITE(lu, '(1X,E12.4)', advance='no', iostat=err) rms/rad_asec
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (65).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(npdf)) THEN
+       WRITE(lu, "(1X,E18.10)", advance="no", iostat=err) npdf
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (70).", 1)
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(repetitions)) THEN
+       WRITE(lu, "(1X,I9)", advance="no", iostat=err) repetitions
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeOpenOrbOrbitFile", &
+               "Write error (75).", 1)
+          RETURN
+       END IF
+    END IF
+    WRITE(lu,"(A)") ""
+
+  END SUBROUTINE writeOpenOrbOrbitFile
+
+
+
+
+
+  SUBROUTINE writeProbabilities(storb, lu, apriori)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)          :: storb
+    INTEGER, INTENT(in)                            :: lu
+    REAL(bp), DIMENSION(:,:), INTENT(in), OPTIONAL :: apriori
+
+    CHARACTER(len=16), DIMENSION(:), POINTER :: group_arr
+    REAL(bp), DIMENSION(:), POINTER :: probability_arr, apriori_pdf
+    INTEGER :: err
+
+    IF (PRESENT(apriori)) THEN
+       CALL getAPrioriWeights(storb, apriori, apriori_pdf)
+       IF (error) THEN
+          CALL errorMessage("io / writeProbabilities", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       CALL getGroupWeights(storb, probability_arr, group_arr, apriori_pdf)
+    ELSE
+       CALL getGroupWeights(storb, probability_arr, group_arr)
+    END IF
+    IF (error) THEN
+       CALL errorMessage("io / writeProbabilities", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    WRITE(lu,"('#')")
+    WRITE(lu,"('#',3X,A)") &
+         "Probabilities of belonging to one of the following groups"
+    IF (PRESENT(apriori)) THEN
+       WRITE(lu,"('#',3X,A)") &
+            "(in %, using a priori information):" 
+    ELSE
+       WRITE(lu,"('#',3X,A)") &
+            "(in %, without using a priori information):" 
+    END IF
+    probability_arr = 100.0_bp*probability_arr
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(1), probability_arr(1)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(2), probability_arr(2)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(3), probability_arr(3)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(4), probability_arr(4)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(5), probability_arr(5)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(6), probability_arr(6)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(7), probability_arr(7)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(8), probability_arr(8)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(9), probability_arr(9)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(10), probability_arr(10)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(11), probability_arr(11)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(12), probability_arr(12)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(13), probability_arr(13)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(14), probability_arr(14)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(15), probability_arr(15)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(16), probability_arr(16)
+    WRITE(lu,"('#',5X,A16,2X,'=',2X,F9.4)") group_arr(17), probability_arr(17)
+    WRITE(lu,"('#')")
+    WRITE(lu,"('#',3X,A,2X,'=',2X,F9.5)") &
+         "PHA probability (without prior knowledge and size requirement)", &
+         100.0_bp*getPHAProbability(storb)
+    IF (error) THEN
+       CALL errorMessage("io / writeProbabilities", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    DEALLOCATE(probability_arr, group_arr, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeProbabilities", &
+            "TRACE BACK (20)", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE writeProbabilities
+
+
+
+
+
+  SUBROUTINE writeResidualBlock(orb, obss, obs_mask, str, lu, residuals)
+
+    IMPLICIT NONE
+    TYPE (Orbit), INTENT(in) :: orb
+    TYPE (Observations), INTENT(in) :: obss
+    CHARACTER(len=*) :: str
+    INTEGER, INTENT(in) :: lu
+    LOGICAL, DIMENSION(:,:), INTENT(in) :: obs_mask
+    REAL(bp), DIMENSION(:,:), POINTER, OPTIONAL :: residuals
+
+    TYPE (Time) :: t
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: observed_scoords, &
+         computed_scoords
+    TYPE (Observation), DIMENSION(:), POINTER :: obs_arr
+    CHARACTER(len=64), DIMENSION(:,:), ALLOCATABLE :: residual_block
+    CHARACTER(len=64), DIMENSION(:), ALLOCATABLE :: residual_arr 
+    CHARACTER(len=2) :: month_str, day_str
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: residuals_, observed_coords, &
+         computed_coords
+    REAL(bp) :: day
+    INTEGER :: i, j, nobs, year, month, err
+
+    ! Compute residuals
+    observed_scoords => getObservationSCoords(obss)
+    IF (error) THEN
+       CALL errorMessage("io / writeResidualBlock", &
+            "TRACE BACK (5)", 1)
+       RETURN
+    END IF
+    obsy_ccoords => getObservatoryCCoords(obss)
+    IF (error) THEN
+       CALL errorMessage("io / writeResidualBlock", &
+            "TRACE BACK (10)", 1)
+       RETURN
+    END IF
+    nobs = SIZE(observed_scoords,dim=1)
+    ALLOCATE(residuals_(nobs,6), observed_coords(nobs,6), &
+         computed_coords(nobs,6), residual_arr(CEILING(nobs/3.0)*3), &
+         residual_block(CEILING(nobs/3.0),3), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResidualBlock", &
+            "Could not allocate memory (5).", 1)
+       RETURN
+    END IF
+    CALL getEphemerides(orb, obsy_ccoords, computed_scoords)
+    IF (error) THEN
+       CALL errorMessage("io / writeResidualBlock", &
+            "TRACE BACK (15)", 1)
+       RETURN
+    END IF
+    observed_coords = 0.0_bp
+    computed_coords = 0.0_bp
+    DO i=1,nobs
+       observed_coords(i,:) = getCoordinates(observed_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (20)", 1)
+          RETURN
+       END IF
+       computed_coords(i,:) = getCoordinates(computed_scoords(i))
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (25)", 1)
+          RETURN
+       END IF
+    END DO
+    residuals_(1:nobs,1:6) = observed_coords(1:nobs,1:6) - &
+         computed_coords(1:nobs,1:6)        
+    residuals_(1:nobs,2) = residuals_(1:nobs,2) * &
+         COS(observed_coords(1:nobs,3))
+    obs_arr => getObservations(obss)
+    IF (error) THEN
+       CALL errorMessage("io / writeResidualBlock", &
+            "TRACE BACK (30)", 1)
+       RETURN
+    END IF
+    residual_arr = " "
+    DO i=1,nobs
+       t = getTime(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (35)", 1)
+          RETURN
+       END IF
+       CALL getCalendarDate(t, "TT", year, month, day)
+       IF (year >= 1972) THEN
+          CALL getCalendarDate(t, "UTC", year, month, day)
+       ELSE
+          CALL getCalendarDate(t, "UT1", year, month, day)
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (40)", 1)
+          RETURN
+       END IF
+       CALL NULLIFY(t)
+       CALL toString(month, month_str, error)
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       IF (LEN_TRIM(month_str) == 1) THEN
+          month_str = "0" // TRIM(month_str)
+       END IF
+       CALL toString(FLOOR(day), day_str, error)
+       IF (error) THEN
+          CALL errorMessage("io / writeResidualBlock", &
+               "TRACE BACK (50)", 1)
+          RETURN
+       END IF
+       IF (LEN_TRIM(day_str) == 1) THEN
+          day_str = "0" // TRIM(day_str)
+       END IF
+       IF (ALL(obs_mask(i,2:3))) THEN
+          WRITE(residual_arr(i), &
+               "(I4,2(A2),2X,A4,2X,2(F9.5,1X))", iostat=err) &
+               year, month_str, day_str, &
+               getCode(obs_arr(i)), &
+               residuals_(i,2:3)/rad_asec
+       ELSE
+          WRITE(residual_arr(i), &
+               "(I4,2(A2),2X,A4,1X,A1,2(F9.5,1X),A1)",iostat=err) &
+               year, month_str, day_str, &
+               getCode(obs_arr(i)), "(", &
+               residuals_(i,2:3)/rad_asec, ")"
+       END IF
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResidualBlock", &
+               "Write error (5).", 1)
+          RETURN
+       END IF
+    END DO
+    residual_block = " "
+    residual_block = RESHAPE(residual_arr, &
+         SHAPE(residual_block))
+    DO i=1,SIZE(residual_block,dim=1)
+       WRITE(lu,"(A,2X)",advance="no",iostat=err) TRIM(str)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResidualBlock", &
+               "Write error (10).", 1)
+          RETURN
+       END IF
+       DO j=1,SIZE(residual_block,dim=2)
+          WRITE(lu,"(A,2X)",advance="no",iostat=err) &
+               residual_block(i,j)(1:37)
+          IF (err /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeResidualBlock", &
+                  "Write error (15).", 1)
+             RETURN
+          END IF
+       END DO
+       WRITE(lu,*,iostat=err)
+    END DO
+
+    IF (PRESENT(residuals)) THEN
+       ALLOCATE(residuals(nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResidualBlock", &
+               "Could not allocate memory (10).", 1)
+          RETURN
+       END IF
+       residuals = residuals_
+    END IF
+    DEALLOCATE(observed_coords, stat=err)
+    DEALLOCATE(computed_coords, stat=err)
+    DEALLOCATE(observed_scoords, stat=err)
+    DEALLOCATE(obsy_ccoords, stat=err)
+    DEALLOCATE(computed_scoords, stat=err) 
+    DEALLOCATE(obs_arr, stat=err)
+    DEALLOCATE(residual_arr, stat=err)
+    DEALLOCATE(residual_block, stat=err)
+    DEALLOCATE(residuals_, stat=err)
+
+  END SUBROUTINE writeResidualBlock
+
+
+
+
+
+  SUBROUTINE writeResiduals(storb, obss, lu, residuals, compute)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(in) :: storb
+    TYPE (Observations), INTENT(in) :: obss
+    INTEGER, INTENT(in) :: lu
+    LOGICAL, INTENT(in), OPTIONAL :: compute
+    REAL(bp), DIMENSION(:,:,:), POINTER, OPTIONAL :: residuals
+
+    TYPE (Orbit), DIMENSION(:), POINTER  :: orb_arr
+    TYPE (Time) :: t
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: obsy_ccoords
+    TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: observed_scoords, &
+         computed_scoords
+    TYPE (Observation), DIMENSION(:), POINTER :: obs_arr
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), ALLOCATABLE :: codes
+    CHARACTER(len=DESIGNATION_LEN) :: id
+    CHARACTER(len=10) :: str
+    REAL(bp), DIMENSION(:,:,:), POINTER :: residuals_
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: observed_coords, &
+         computed_coords
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: jds
+    REAL(bp) :: day
+    INTEGER :: i, j, nobs, err, year, month
+    LOGICAL :: compute_
+
+    ! NOTE: info on obs_mask is not output, should it be?.
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(compute)) THEN
+       compute_ = compute
+    ELSE
+       compute_ = .FALSE.
+    END IF
+
+    IF (.NOT. compute_) THEN
+       residuals_ => getResidualDistribution(storb)
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "Residuals are not available.", 1)
+          RETURN
+       END IF
+    ELSE
+       ! Compute residuals
+       observed_scoords => getObservationSCoords(obss)
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (5)", 1)
+          RETURN
+       END IF
+       obsy_ccoords => getObservatoryCCoords(obss)
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (10)", 1)
+          RETURN
+       END IF
+       nobs = SIZE(observed_scoords,dim=1)
+
+       orb_arr => getSampleOrbits(storb)
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (15)", 1)
+          RETURN
+       END IF
+
+       ALLOCATE(residuals_(SIZE(orb_arr,dim=1),nobs,6), &
+            observed_coords(nobs,6), computed_coords(nobs,6), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResiduals", &
+               "Could not allocate memory (5).", 1)
+          RETURN
+       END IF
+
+       DO j=1,SIZE(orb_arr, dim=1)
+          IF (ASSOCIATED(computed_scoords)) THEN
+             NULLIFY(computed_scoords)
+          END IF
+          CALL getEphemerides(orb_arr(j), obsy_ccoords, &
+               computed_scoords)
+          IF (error) THEN
+             CALL errorMessage("io / writeResiduals", &
+                  "TRACE BACK (20)", 1)
+             RETURN
+          END IF
+          observed_coords = 0.0_bp
+          computed_coords = 0.0_bp
+          DO i=1,nobs
+             observed_coords(i,:) = getCoordinates(observed_scoords(i))
+             IF (error) THEN
+                CALL errorMessage("io / writeResiduals", &
+                     "TRACE BACK (25)", 1)
+                RETURN
+             END IF
+             computed_coords(i,:) = getCoordinates(computed_scoords(i))
+             IF (error) THEN
+                CALL errorMessage("io / writeResiduals", &
+                     "TRACE BACK (30)", 1)
+                RETURN
+             END IF
+          END DO
+          residuals_(j,1:nobs,1:6) = observed_coords(1:nobs,1:6) - &
+               computed_coords(1:nobs,1:6)        
+          residuals_(j,1:nobs,2) = residuals_(j,1:nobs,2) * &
+               COS(observed_coords(1:nobs,3))
+       END DO
+
+       DEALLOCATE(observed_coords, computed_coords, observed_scoords, &
+            obsy_ccoords, computed_scoords, orb_arr, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResiduals", &
+               "Could not deallocate memory (5).", 1)
+          DEALLOCATE(observed_coords, stat=err)
+          DEALLOCATE(computed_coords, stat=err)
+          DEALLOCATE(observed_scoords, stat=err)
+          DEALLOCATE(obsy_ccoords, stat=err)
+          DEALLOCATE(computed_scoords, stat=err)
+          DEALLOCATE(orb_arr, stat=err)
+          RETURN
+       END IF
+
+    END IF
+
+    obs_arr => getObservations(obss)
+    IF (error) THEN
+       CALL errorMessage("io / writeResiduals", &
+            "TRACE BACK (35)", 1)
+       RETURN
+    END IF
+    nobs = SIZE(obs_arr, dim=1)
+
+    ALLOCATE(jds(nobs), codes(nobs), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "Could not allocate memory (10).", 1)
+       RETURN
+    END IF
+
+    DO i=1,nobs
+       t = getTime(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (40)", 1)
+          RETURN
+       END IF
+       CALL getCalendarDate(t, "TT", year, month, day)
+       IF (year >= 1972) THEN
+          jds(i) = getJD(t, "UTC")
+       ELSE
+          jds(i) = getJD(t, "UT1")
+       END IF
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (45)", 1)
+          RETURN
+       END IF
+       codes(i) = getCode(obs_arr(i))
+       IF (error) THEN
+          CALL errorMessage("io / writeResiduals", &
+               "TRACE BACK (50)", 1)
+          RETURN
+       END IF
+    END DO
+
+    id = getID(obss)
+    IF (error) THEN
+       CALL errorMessage("io / writeResiduals", &
+            "TRACE BACK (52)", 1)
+       RETURN
+    END IF
+    CALL toString(nobs, str, error)
+    IF (error) THEN
+       CALL errorMessage("io / writeResiduals", &
+            "TRACE BACK (55)", 1)
+       RETURN
+    END IF
+
+    WRITE(lu, "('#',4X,'ID',4X,"//TRIM(str)//"(7X,F16.8,5X))", iostat=err) jds
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "Write error (5).", 1)
+       RETURN
+    END IF
+    WRITE(lu, "('#',10X,"//TRIM(str)//"(11X,A4,13X))", iostat=err) codes
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "Write error (10).", 1)
+       RETURN
+    END IF
+
+    DO i=1,SIZE(residuals_,dim=1)
+       WRITE(lu, "(A10,1X,"//TRIM(str)//"(2(E13.6,1X)))", iostat=err) &
+            TRIM(id), residuals_(i,:,2:3)/rad_asec
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResiduals", &
+               "Write error (15).", 1)
+          RETURN
+       END IF
+    END DO
+
+    IF (PRESENT(residuals)) THEN
+       ALLOCATE(residuals(SIZE(residuals_,dim=1),nobs,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeResiduals", &
+               "Could not allocate memory (15).", 1)
+          RETURN
+       END IF
+       residuals = residuals_
+    END IF
+
+    DEALLOCATE(obs_arr, residuals_, jds, codes, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeResiduals", &
+            "Could not deallocate memory (15).", 1)
+       DEALLOCATE(obs_arr, stat=err)
+       DEALLOCATE(residuals_, stat=err)
+       DEALLOCATE(jds, stat=err)
+       DEALLOCATE(codes, stat=err)
+       RETURN
+    END IF
+
+
+  END SUBROUTINE writeResiduals
+
+
+
+
+
+  SUBROUTINE writeSORResults(storb, obss, lu, impact)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout)            :: storb
+    TYPE (Observations), INTENT(in)                  :: obss
+    INTEGER, INTENT(in)                              :: lu
+    LOGICAL, INTENT(in), OPTIONAL                    :: impact
+
+    TYPE (Orbit), DIMENSION(:), POINTER :: orb_arr_cmp
+    TYPE (Time) :: t
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: &
+         element_type_prm
+    CHARACTER(len=DYN_MODEL_LEN) :: &    
+         dyn_model_prm
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         integrator
+    CHARACTER(len=1024) :: frmt
+    CHARACTER(len=145) :: str1, str2, str3
+    CHARACTER(len=64) :: sor_2point_method
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         res_arr_cmp, sor_deviates_prm
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         sor_rho_arr_cmp, res_accept_prm, obs_stdev_arr, jac_arr_cmp, &
+         rms_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER :: &
+         pdf_arr_cmp, reg_apr_arr_cmp, rchi2_arr_cmp
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+         res_arr, elements_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         ellipse_fac
+    REAL(bp), DIMENSION(2,6,2) :: &
+         conf_limits 
+    REAL(bp), DIMENSION(2,2) :: &
+         sor_rho_prm, &
+         sor_rho_cmp 
+    REAL(bp), DIMENSION(6) :: elements
+    REAL(bp) :: &
+         generat_multiplier_prm, accept_multiplier_prm, obsarc, &
+         dchi2, chi2_min_prm, apriori_a_min_prm, apriori_a_max_prm, &
+         apriori_periapsis_min_prm, apriori_periapsis_max_prm, &
+         apriori_apoapsis_min_prm, apriori_apoapsis_max_prm, &
+         apriori_rho_min_prm, apriori_rho_max_prm
+    INTEGER, DIMENSION(:,:), POINTER :: &
+         sor_pair_arr_prm
+    INTEGER, DIMENSION(2) :: &
+         npoints
+    INTEGER :: & 
+         sor_norb_cmp, sor_ntrial_cmp, &
+         sor_norb_prm, sor_ntrial_prm, sor_rho_histo_cmp
+    INTEGER :: &
+         nobs, i, k, err, indx_ml, nra, ndec
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask_arr
+    LOGICAL :: impact_, sor_random_obs_prm, regularization_prm, dchi2_rejection_prm
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (PRESENT(impact)) THEN
+       impact_ = impact
+    ELSE
+       impact_ = .FALSE.
+    END IF
+
+    IF (impact_) THEN
+       WRITE(lu,"(A,3X,A,A)", advance="no") "#","IMPACT PROBABILITY (MC) FOR ", getID(obss)
+    ELSE
+       WRITE(lu,"(A,3X,A,A)", advance="no") "#","STATISTICAL ORBITAL RANGING FOR ", getID(obss)
+    END IF
+
+    nobs = getNumberOfObservations(obss)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 20", 1)
+       RETURN
+    END IF
+    obsarc = getObservationalTimespan(obss)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 20", 1)
+       RETURN
+    END IF
+    obs_stdev_arr => getStandardDeviations(obss)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 20", 1)
+       RETURN
+    END IF
+    obs_stdev_arr = obs_stdev_arr/rad_asec
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 20", 1)
+       RETURN
+    END IF
+    obs_masks => getObservationMasks(storb)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 10", 1)
+       RETURN
+    END IF
+
+    nra=COUNT(obs_masks(:,2))
+    ndec=COUNT(obs_masks(:,3))
+
+    frmt = "(/'#',3X,'Number of initial observations = ',I14/" // &
+         "'#',3X,'Number of R.A. included        = ',I14/" // &
+         "'#',3X,'Number of Dec. included        = ',I14/" // &
+         "'#',3X,'Observational time arc         = ',F14.4,3X,'days'/" // &
+         "'#')"
+    WRITE(lu,TRIM(frmt)) nobs, nra, ndec, obsarc
+
+    CALL getParameters(storb, &
+         dyn_model=dyn_model_prm, integrator=integrator, &
+         element_type = element_type_prm, &
+         dchi2_rejection = dchi2_rejection_prm, regularized_pdf = regularization_prm, &
+         accept_multiplier = accept_multiplier_prm, &
+         res_accept = res_accept_prm, &
+         chi2_min_prm = chi2_min_prm, &
+         dchi2_prm = dchi2, &
+         apriori_a_min = apriori_a_min_prm, &
+         apriori_a_max = apriori_a_max_prm, &
+         apriori_periapsis_min = apriori_periapsis_min_prm, &
+         apriori_periapsis_max = apriori_periapsis_max_prm, &
+         apriori_apoapsis_min = apriori_apoapsis_min_prm, &
+         apriori_apoapsis_max = apriori_apoapsis_max_prm, &
+         apriori_rho_min = apriori_rho_min_prm, &
+         apriori_rho_max = apriori_rho_max_prm, &
+         sor_2point_method = sor_2point_method, &
+         sor_norb = sor_norb_prm, sor_ntrial = sor_ntrial_prm, &
+         sor_rho1_l=sor_rho_prm(1,1), sor_rho1_u=sor_rho_prm(1,2), &
+         sor_rho2_l=sor_rho_prm(2,1), sor_rho2_u=sor_rho_prm(2,2), &
+         sor_random_obs_selection=sor_random_obs_prm, & 
+         generat_multiplier = generat_multiplier_prm, &
+         sor_deviates = sor_deviates_prm)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeSORResults", &
+            "TRACE BACK 15", 1)
+       RETURN
+    END IF
+
+    IF (.NOT.impact_) THEN
+
+       orb_arr_cmp => getSampleOrbits(storb)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       t = getTime(orb_arr_cmp(1))
+
+       pdf_arr_cmp => getPDFValues(storb)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       rchi2_arr_cmp => getReducedChi2Distribution(storb)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       res_arr_cmp => getResidualDistribution(storb)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       rms_arr_cmp => getRMSDistribution(storb)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 20", 1)
+          RETURN
+       END IF
+       CALL getResults(storb, reg_apr_arr=reg_apr_arr_cmp, &
+            jac_arr=jac_arr_cmp, &
+            sor_norb_cmp=sor_norb_cmp, sor_ntrial_cmp=sor_ntrial_cmp, &
+            sor_rho_cmp=sor_rho_cmp, sor_rho_histo_cmp=sor_rho_histo_cmp)
+       IF (error) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "TRACE BACK 25", 1)
+          RETURN
+       END IF
+       indx_ml = MAXLOC(pdf_arr_cmp,dim=1)
+       ALLOCATE(elements_arr(SIZE(orb_arr_cmp),6))
+       str1 = "KEP elements     = "
+       str2 = "Confid. limit lo = "
+       str3 = "Confid. limit hi = "
+       DO i=1,SIZE(orb_arr_cmp)
+          elements_arr(i,1:6) =  getElements(orb_arr_cmp(i), "keplerian")
+          IF (error) THEN
+             EXIT
+          END IF
+       END DO
+       IF (error) THEN
+          error = .FALSE.
+          str1 = "CAR elements     = "
+          str2 = "Confid. limit lo = "
+          str3 = "Confid. limit hi = "
+          DO i=1,SIZE(orb_arr_cmp)
+             elements_arr(i,1:6) =  getElements(orb_arr_cmp(i), "cartesian", "ecliptic")
+             IF (error) THEN
+                CALL errorMessage("io / writeSORResults", &
+                     "TRACE BACK 26", 1)
+                RETURN
+             END IF
+          END DO
+       ELSE
+          elements_arr(:,3:6) = elements_arr(:,3:6)/rad_deg
+       END IF
+       ! Compute 1-sigma-equivalent and 3-sigma-equivalent bounds for elements 
+       DO i=1,6
+          CALL confidence_limits(elements_arr(:,i), pdf_arr_cmp, &
+               probability_mass=0.6827_bp, peak=elements(i), bounds=conf_limits(1,i,:), &
+               errstr=errstr)
+          CALL confidence_limits(elements_arr(:,i), pdf_arr_cmp, &
+               probability_mass=0.9973_bp, peak=elements(i), bounds=conf_limits(2,i,:), &
+               errstr=errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeSORResults", &
+                  "Could not compute confidence limits. " // TRIM(errstr), 1)
+             errstr = ""
+             RETURN
+          END IF
+       END DO
+       IF (ANY(elements-elements_arr(indx_ml,:) /= 0.0_bp)) THEN
+          WRITE(stdout,*) elements
+          WRITE(stdout,*) elements_arr(indx_ml,:)
+       END IF
+       DEALLOCATE(elements_arr, stat=err)
+
+       frmt = "('#',3X,'ORBITAL-ELEMENT PDF' /" // &
+            "'#',3X,' Epoch            = ',A,' = ',F13.5,' TDT'/" // &
+            "'#',3X,' Maximum likelihood (ML) orbit' /" // &
+            "'#',3X,'  ',A19,6(F15.10,1X)/" // &
+            "'#',3X,' 68.27% credible intervals' /" // &
+            "'#',3X,'  ',A19,6(F15.10,1X)/" // &
+            "'#',3X,'  ',A19,6(F15.10,1X)/" // &
+            "'#',3X,' 99.73% credible intervals' /" // &
+            "'#',3X,'  ',A19,6(F15.10,1X)/" // &
+            "'#',3X,'  ',A19,6(F15.10,1X)/" // &
+            "'#',3X,'  ML value        =',E16.6/" // &
+            "'#',3X,'  ML reduced chi2 =',E16.6/" // &
+            "'#',3X,'  ML rms          =',E16.6,3X,'arcsec'/" // &            
+            "'#',3X,' Apriori pdf, min =',E16.6/" // &
+            "'#',3X,'              max =',E16.6/" // &
+            "'#',3X,' Jacobian,    min =',E16.6/" // &
+            "'#',3X,'              max =',E16.6/" // &
+            "'#',3X,' Rms,         min =',E16.6,3X,'arcsec'/" // &
+            "'#',3X,'              max =',E16.6,3X,'arcsec'/" // &
+            "'#')"
+       WRITE(lu,TRIM(frmt)) getCalendarDateString(t,"tdt"), getJD(t,"tdt"), &
+            str1(1:19), elements, str2(1:19), conf_limits(1,:,1), str3(1:19), &
+            conf_limits(1,:,2), str2(1:19), conf_limits(2,:,1), str3(1:19), &
+            conf_limits(2,:,2), pdf_arr_cmp(indx_ml),rchi2_arr_cmp(indx_ml)+nra+ndec,&
+            SQRT(0.5*(rms_arr_cmp(indx_ml,2)**2+rms_arr_cmp(indx_ml,3)**2))/rad_asec,&
+            MINVAL(reg_apr_arr_cmp),MAXVAL(reg_apr_arr_cmp),&
+            MINVAL(jac_arr_cmp(:,1)),MAXVAL(jac_arr_cmp(:,1)),&
+            MINVAL(SQRT(0.5*(rms_arr_cmp(:,2)**2+rms_arr_cmp(:,3)**2)))/rad_asec,&
+            MAXVAL(SQRT(0.5*(rms_arr_cmp(:,2)**2+rms_arr_cmp(:,3)**2)))/rad_asec
+
+       frmt = "('#',3X,'COMPUTATIONAL PARAMETERS'/" // &
+            "'#',3X,'Element set      = ',A/" // &
+            "'#',3X,'Two-point method = ',A/" // &
+            "'#',3X,'Dynamical model  = ',A/" // &
+            "'#',3X,'Regularization   = ',L2/" // &
+            "'#',3X,'Uniform PDF      = ',L2/" // &
+            "'#')"
+       WRITE(lu,TRIM(frmt)) element_type_prm, &
+            TRIM(sor_2point_method), &
+            TRIM(dyn_model_prm), &
+            regularization_prm, &
+            dchi2_rejection_prm
+
+
+       frmt = "('#',3X,'BAYESIAN A PRIORI INFORMATION'/" // &
+            "'#',3X,'Semimajor axis (AU), min      = ',F15.9/" // &
+            "'#',3X,'                     max      = ',F15.9/" // &
+            "'#',3X,'Periapsis distance (AU),  min = ',F15.9/" // &
+            "'#',3X,'                          max = ',F15.9/" // &
+            "'#',3X,'Apoapsis distance (AU),   min = ',F15.9/" // &
+            "'#',3X,'                          max = ',F15.9/" // &
+            "'#',3X,'Topocentric range (AU),   min = ',F15.9/" // &
+            "'#',3X,'                          max = ',F15.9/" // &
+            "'#')"
+       WRITE(lu,TRIM(frmt)) apriori_a_min_prm, &
+            apriori_a_max_prm, &
+            apriori_periapsis_min_prm, &
+            apriori_periapsis_max_prm, &
+            apriori_apoapsis_min_prm, &
+            apriori_apoapsis_max_prm, &
+            apriori_rho_min_prm, &
+            apriori_rho_max_prm
+    END IF
+
+    frmt = "('#',3X,'Final   number of sample orbits  = ',I14/" // &
+         "'#',3X,'Initial number of sample orbits  = ',I14/" // &
+         "'#',3X,'Final   number of trials         = ',I14/" // &
+         "'#',3X,'Initial number of trials         = ',I14/" // &
+         "'#')"
+    WRITE(lu,TRIM(frmt)) sor_norb_cmp, &
+         sor_norb_prm, &
+         sor_ntrial_cmp,&
+         sor_ntrial_prm
+
+    frmt = "('#',3X,'RESIDUALS AND PDF'/" // &
+         "'#',3X,'R.A.*cos Dec. std        (min)   = ',E14.4,3X,'arcsec'/" // &
+         "'#',3X,'Dec. std                 (min)   = ',E14.4,3X,'arcsec'/" // &
+         "'#',3X,'Acceptance, residuals'/" // &
+         "'#',3X,'  sigma multiplier               = ',E14.4/" // &
+         "'#',3X,'  window for 1st R.A.            = ',E14.4,3X,'arcsec'/" // &
+         "'#',3X,'  window for 1st Dec.            = ',E14.4,3X,'arcsec'/" // &
+         "'#',3X,'Acceptance, chi2                   ',3X,/" // &
+         "'#',3X,'  reference value                = ',E14.4/" // &
+         "'#',3X,'  chi2 difference                = ',E14.4/" // &
+         "'#')"
+    WRITE(lu,TRIM(frmt)) & 
+         MINVAL(obs_stdev_arr(:,2:3),dim=1), &
+         accept_multiplier_prm, &
+         res_accept_prm(1,2:3)/rad_asec,&
+         chi2_min_prm, &
+         dchi2
+
+    IF (impact_) THEN
+
+       mask_arr(:) = .FALSE.
+       WHERE(sor_rho_arr_cmp(:,1) <= planetary_radii(3))
+          mask_arr = .TRUE.
+       END WHERE
+       frmt = "('#',3X,'Impact probability  = ',E14.4/)"
+       WRITE(lu,TRIM(frmt)) SUM(pdf_arr_cmp,mask_arr)/SUM(pdf_arr_cmp)
+
+    ELSE
+
+       sor_pair_arr_prm => getObservationPairs(storb)
+       IF (.NOT. sor_random_obs_prm) THEN
+          CALL toString(sor_pair_arr_prm(1,1), str1, error)
+          IF (error) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeSORResults", &
+                  "TRACE BACK 20", 1)
+             RETURN
+          END IF
+          CALL toString(sor_pair_arr_prm(1,2), str2, error)
+          IF (error) THEN
+             error = .TRUE.
+             CALL errorMessage("io / writeSORResults", &
+                  "TRACE BACK 20", 1)
+             RETURN
+          END IF
+       ELSE
+          str1 = "<random>"
+          str2 = "<random>"
+       END IF
+
+       ALLOCATE(mask_arr(sor_norb_cmp), &
+            res_arr(2,sor_norb_cmp), &
+            ellipse_fac(sor_norb_cmp), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          CALL errorMessage("io / writeSORResults", &
+               "Could not allocate memory.", 1)
+          RETURN       
+       END IF
+
+       DO k=1,2
+          res_arr(1,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),2)
+          res_arr(2,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),3)       
+          ellipse_fac = &
+               (res_arr(1,:)/res_accept_prm(sor_pair_arr_prm(1,k),2))**2 + &
+               (res_arr(2,:)/res_accept_prm(sor_pair_arr_prm(1,k),3))**2
+          mask_arr(:) = .FALSE.
+          WHERE (ellipse_fac > 1.0_bp)
+             mask_arr = .TRUE.
+          endwhere
+          npoints(k) = COUNT(mask_arr)
+       END DO
+
+       sor_deviates_prm = sor_deviates_prm/rad_asec
+
+       frmt = "('#',3X,'GENERATION WINDOWS FOR RHO, R.A., AND DEC.' /" // &
+            "'#',3X,'  Id. number of 1st observation  = ',A14/" // &
+            "'#',3X,'  Id. number of 2nd observation  = ',A14/" // &
+            "'#',3X,'  Bound for rho1;      lower     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'                       upper     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'  Bound for rho2-rho1; lower     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'                       upper     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'  sigma multiplier               = ',E14.4/" // &
+            "'#',3X,'  window shift for 1st R.A.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'                   1st Dec.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'  window width for 1st R.A.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'                   1st Dec.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'  window shift for 2nd R.A.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'                   2nd Dec.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'  window width for 2nd R.A.      = ',E14.4,3X,'arcsec'/" // &
+            "'#',3X,'                   2nd Dec.      = ',E14.4,3X,'arcsec'/" // &
+            "'#')"
+       WRITE(lu,TRIM(frmt)) ADJUSTR(str1(1:14)), &
+            ADJUSTR(str2(1:14)), &
+            sor_rho_prm(1,1:2), &
+            sor_rho_prm(2,1:2), &
+            generat_multiplier_prm, &
+            sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,1),&
+            sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,2),&
+            sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,1),&
+            sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,2)
+
+       frmt = "('#',3X,'COMPUTED VALUES FOR RHO, R.A., AND DEC.'/" // &
+            "'#',3X,'Computed, rho' /" // &
+            "'#',3X,'  Bound for rho1,      lower     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'                       upper     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'  Bound for rho2-rho1, lower     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'                       upper     = ',E14.4,3X,'AU'/" // &
+            "'#',3X,'  Histogram flag                 = ',I14/" // &
+            "'#',3X,'Computed, R.A. and Dec. residuals' /" // &
+            "'#',3X,'  Fraction outside ref. ellipse, 1st obs =',E12.4/" // &
+            "'#',3X,'  Fraction outside ref. ellipse, 2nd obs =',E12.4/" // &
+            "'#')"
+       WRITE(lu,TRIM(frmt)) sor_rho_cmp(1,1:2), &
+            sor_rho_cmp(2,1:2), &
+            sor_rho_histo_cmp, & 
+            npoints(1)/REAL(sor_norb_cmp), &
+            npoints(2)/REAL(sor_norb_cmp)
+
+    END IF
+
+    DO i=1,SIZE(orb_arr_cmp)
+       CALL NULLIFY(orb_arr_cmp(i))
+    END DO
+    DEALLOCATE(orb_arr_cmp, stat=err)
+    DEALLOCATE(res_arr_cmp, stat=err)
+    DEALLOCATE(rms_arr_cmp, stat=err)
+    DEALLOCATE(sor_deviates_prm, stat=err)
+    DEALLOCATE(sor_rho_arr_cmp, stat=err)
+    DEALLOCATE(res_accept_prm, stat=err)
+    DEALLOCATE(jac_arr_cmp, stat=err)
+    DEALLOCATE(pdf_arr_cmp, stat=err)
+    DEALLOCATE(reg_apr_arr_cmp, stat=err)
+    DEALLOCATE(rchi2_arr_cmp, stat=err)
+    DEALLOCATE(res_arr, stat=err)
+    DEALLOCATE(ellipse_fac, stat=err)
+    DEALLOCATE(sor_pair_arr_prm, stat=err)
+    DEALLOCATE(obs_stdev_arr, stat=err)
+    DEALLOCATE(obs_masks, stat=err)
+    DEALLOCATE(mask_arr, stat=err)
+
+  END SUBROUTINE writeSORResults
+
+
+
+
+
+  SUBROUTINE writeVOMCMCResults(storb, obss, lu)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: storb
+    TYPE (Observations), INTENT(in)       :: obss
+    INTEGER, INTENT(in)                   :: lu
+    TYPE (Orbit), DIMENSION(:), POINTER   :: orb_arr_cmp
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         res_arr_cmp
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         res_accept_prm, stdevs, jac_arr_cmp, rms_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER :: &
+         pdf_arr_cmp, reg_apr_arr_cmp, rchi2_arr_cmp
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+         res_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         ellipse_fac
+    REAL(bp), DIMENSION(6,2) :: vomcmc_scaling_prm
+    REAL(bp), DIMENSION(6) :: elements, elem_stdevs
+    REAL(bp) :: &
+         accept_multiplier_prm, obsarc, &
+         dchi2, chi2_min_prm
+    INTEGER :: & 
+         vomcmc_norb_cmp, vomcmc_ntrial_cmp, &
+         vomcmc_norb_prm, vomcmc_ntrial_prm, vomcmc_nmap_prm 
+    INTEGER :: &
+         nobs, i, err, indx_ml, nra, ndec
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL, DIMENSION(6,2) :: &
+         vomcmc_scaling_ready_cmp
+    LOGICAL, DIMENSION(6) :: &
+         vomcmc_mapping_mask_prm
+    LOGICAL :: regularization_prm, dchi2_rejection_prm
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: &
+         element_type_prm
+    CHARACTER(len=DYN_MODEL_LEN) :: &    
+         dyn_model_prm
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         integrator
+    CHARACTER(len=20) :: str1, str2
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    WRITE(lu,"(A,3X,A,A)", advance="no") "#", &
+         "VOLUME-OF-VARIATION SAMPLING FOR ", getID(obss)
+
+    nobs = getNumberOfObservations(obss)
+    obsarc = getObservationalTimespan(obss)
+    stdevs => getStandardDeviations(obss)
+    stdevs = stdevs/rad_asec
+    obs_masks => getObservationMasks(storb)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    nra=COUNT(obs_masks(:,2))
+    ndec=COUNT(obs_masks(:,3))
+
+    WRITE(lu,200) nobs, nra, ndec, obsarc
+200 FORMAT(/"#",3X,"Number of initial observations = ",I14/ &
+         "#",3X,"Number of R.A. included        = ",I14/ &
+         "#",3X,"Number of Dec. included        = ",I14/ &
+         "#",3X,"Observational time arc         = ",F14.4,3X,"days")
+
+    WRITE(lu,"(A)") "#"
+
+    CALL getParameters(storb, dyn_model=dyn_model_prm, integrator=integrator, &
+         element_type = element_type_prm, &
+         vomcmc_norb = vomcmc_norb_prm, vomcmc_ntrial = vomcmc_ntrial_prm, &
+         vomcmc_nmap = vomcmc_nmap_prm, vomcmc_scaling = vomcmc_scaling_prm, &
+         vomcmc_mapping_mask=vomcmc_mapping_mask_prm)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    orb_arr_cmp => getSampleOrbits(storb)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    t = getTime(orb_arr_cmp(1))
+
+    pdf_arr_cmp => getPDFValues(storb)
+    rchi2_arr_cmp => getReducedChi2Distribution(storb)
+    CALL getResults(storb, &
+         vomcmc_norb_cmp=vomcmc_norb_cmp, &
+         vomcmc_ntrial_cmp=vomcmc_ntrial_cmp, &
+         vomcmc_scaling_ready_cmp=vomcmc_scaling_ready_cmp)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    indx_ml = MAXLOC(pdf_arr_cmp,dim=1)
+
+    elements = getElements(orb_arr_cmp(indx_ml), "cartesian")
+    !elements(3:6) = elements(3:6)/rad_deg
+    str1 = "CAR elements    = "
+    str2 = "CAR stdevs      = "
+
+    elem_stdevs = getStandardDeviations(storb, "cartesian")
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOMCMCResults", &
+            "TRACE BACK 30", 1)
+       RETURN
+    END IF
+    !elem_stdevs(3:5) = elem_stdevs(3:5)/rad_deg
+
+    WRITE(lu,700) getCalendarDateString(t,"tdt"), getJD(t,"tdt"), &
+         str1(1:18), elements, str2(1:18), elem_stdevs, &
+         pdf_arr_cmp(indx_ml),rchi2_arr_cmp(indx_ml)
+
+700 FORMAT("#",3X,"ORBITAL-ELEMENT PDF" /&
+         "#",3X," Epoch              = ",A," = ",F13.5," TDT"/&
+         "#",3X," Maximum likelihood (ML) orbit" /&
+         "#",3X,"  ",A18,6(F15.10,1X)/&
+         "#",3X,"  ",A18,6(F15.10,1X)/&
+         "#",3X,"  ML value          =",E16.6/ &
+         "#",3X,"  ML 'reduced' chi2 =",E16.6)
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,220) element_type_prm, &
+         TRIM(dyn_model_prm)
+220 FORMAT("#",3X,"COMPUTATIONAL PARAMETERS"/&
+         "#",3X,"Element set      = ",A/ &
+         "#",3X,"Dynamical model  = ",A)
+
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,250) vomcmc_norb_cmp, vomcmc_norb_prm, vomcmc_ntrial_cmp,&
+         vomcmc_ntrial_prm
+250 FORMAT("#",3X,"Final   number of sample orbits  = ",I14/ &
+         "#",3X,"Initial number of sample orbits  = ",I14/ &
+         "#",3X,"Final   number of trials         = ",I14/ &
+         "#",3X,"Initial number of trials         = ",I14)
+
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,400) vomcmc_mapping_mask_prm, &
+         vomcmc_scaling_prm(:,1), &
+         vomcmc_scaling_prm(:,2), &
+         vomcmc_scaling_ready_cmp(:,1), &
+         vomcmc_scaling_ready_cmp(:,2)
+400 FORMAT("#",3X,"Mapping mask         = ",6(3X,L2,1X)/ &
+         "#",3X,"Scaling factors, lower = ",6(F5.1,1X)/ &
+         "#",3X,"                 upper = ",6(F5.1,1X)/ &
+         "#",3X,"Scaling ready,   lower = ",6(L3,3X)/ &
+         "#",3X,"                 upper = ",6(L3,3X))
+
+!!$    ALLOCATE(mask_arr(sor_norb_cmp),res_arr(2,sor_norb_cmp),&
+!!$         ellipse_fac(sor_norb_cmp),stat=err)
+!!$    IF (err /= 0) THEN
+!!$       error = .TRUE.
+!!$       CALL errorMessage("io / writeVOMCMCResults", &
+!!$            "Could not allocate memory.", 1)
+!!$       RETURN       
+!!$    END IF
+!!$
+!!$    DO k=1,2
+!!$       res_arr(1,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),2)
+!!$       res_arr(2,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),3)       
+!!$       ellipse_fac = &
+!!$            (res_arr(1,:)/res_accept_prm(sor_pair_arr_prm(1,k),2))**2 + &
+!!$            (res_arr(2,:)/res_accept_prm(sor_pair_arr_prm(1,k),3))**2
+!!$       mask_arr(:) = .FALSE.
+!!$       WHERE (ellipse_fac > 1.0_bp)
+!!$          mask_arr = .TRUE.
+!!$       endwhere
+!!$       npoints(k) = COUNT(mask_arr)
+!!$    END DO
+!!$
+!!$    sor_deviates_prm=sor_deviates_prm/rad_asec
+!!$
+!!$    WRITE(lu,400) ADJUSTR(str1(1:14)), ADJUSTR(str2(1:14)), &
+!!$         sor_generat_multiplier_prm, &
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,1),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,2),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,1),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,2)
+!!$
+!!$400 FORMAT("#",3X,"Generated, R.A. and Dec. "/ &
+!!$         "#",3X,"  Id. number of 1st observation  = ",A14/ &
+!!$         "#",3X,"  Id. number of 2nd observation  = ",A14/ &
+!!$         "#",3X,"  sigma multiplier               = ",E14.4/ &
+!!$         "#",3X,"  window shift for 1st R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   1st Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window width for 1st R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   1st Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window shift for 2nd R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   2nd Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window width for 2nd R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   2nd Dec.      = ",E14.4,3X,"arcsec")
+!!$    WRITE(lu,"(A)") "#"
+!!$
+!!$    WRITE(lu,550) npoints(1)/REAL(sor_norb_cmp),npoints(2)/REAL(sor_norb_cmp)
+!!$550 FORMAT("#",3X,"Computed, R.A. and Dec. residuals" /&
+!!$         "#",3X,"  Fraction outside ref. ellipse, 1st obs =",E12.4/ &
+!!$         "#",3X,"  Fraction outside ref. ellipse, 2nd obs =",E12.4)
+    DO i=1,SIZE(orb_arr_cmp)
+       CALL NULLIFY(orb_arr_cmp(i))
+    END DO
+    DEALLOCATE(orb_arr_cmp, stat=err)
+    DEALLOCATE(res_arr_cmp, stat=err)
+    DEALLOCATE(rms_arr_cmp, stat=err)
+    DEALLOCATE(res_accept_prm, stat=err)
+    DEALLOCATE(stdevs, stat=err)
+    DEALLOCATE(pdf_arr_cmp, stat=err)
+    DEALLOCATE(obs_masks, stat=err)
+    DEALLOCATE(rchi2_arr_cmp, stat=err)
+    DEALLOCATE(res_arr, stat=err)
+    DEALLOCATE(ellipse_fac, stat=err)
+
+  END SUBROUTINE writeVOMCMCResults
+
+
+
+
+
+  SUBROUTINE writeVOVResults(storb, obss, lu)
+
+    IMPLICIT NONE
+    TYPE (StochasticOrbit), INTENT(inout) :: storb
+    TYPE (Observations), INTENT(in)       :: obss
+    INTEGER, INTENT(in)                   :: lu
+    TYPE (Orbit), DIMENSION(:), POINTER   :: orb_arr_cmp
+    TYPE (Time) :: t
+    REAL(bp), DIMENSION(:,:,:), POINTER :: &
+         res_arr_cmp
+    REAL(bp), DIMENSION(:,:), POINTER :: &
+         res_accept_prm, stdevs, jac_arr_cmp, rms_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER :: &
+         pdf_arr_cmp, reg_apr_arr_cmp, rchi2_arr_cmp
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+         res_arr
+    REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+         ellipse_fac
+    REAL(bp), DIMENSION(6,2) :: vov_scaling_prm
+    REAL(bp), DIMENSION(6) :: elements, elem_stdevs
+    REAL(bp) :: &
+         accept_multiplier_prm, obsarc, &
+         dchi2, chi2_min_prm
+    INTEGER :: & 
+         vov_norb_cmp, vov_ntrial_cmp, &
+         vov_norb_prm, vov_ntrial_prm, vov_nmap_prm 
+    INTEGER :: &
+         nobs, i, err, indx_ml, nra, ndec
+    LOGICAL, DIMENSION(:,:), POINTER :: obs_masks
+    LOGICAL, DIMENSION(6,2) :: &
+         vov_scaling_ready_cmp
+    LOGICAL, DIMENSION(6) :: &
+         vov_mapping_mask_prm
+    LOGICAL :: regularization_prm, dchi2_rejection_prm
+    CHARACTER(len=ELEMENT_TYPE_LEN) :: &
+         element_type_prm
+    CHARACTER(len=DYN_MODEL_LEN) :: &    
+         dyn_model_prm
+    CHARACTER(len=INTEGRATOR_LEN) :: &
+         integrator
+    CHARACTER(len=20) :: str1, str2
+
+    IF (.NOT. exist(storb)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "StochasticOrbit object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    IF (.NOT. exist(obss)) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "Observations object has not yet been initialized.", 1)
+       RETURN
+    END IF
+
+    WRITE(lu,"(A,3X,A,A)", advance="no") "#", &
+         "VOLUME-OF-VARIATION SAMPLING FOR ", getID(obss)
+
+    nobs = getNumberOfObservations(obss)
+    obsarc = getObservationalTimespan(obss)
+    stdevs => getStandardDeviations(obss)
+    stdevs = stdevs/rad_asec
+    obs_masks => getObservationMasks(storb)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    nra=COUNT(obs_masks(:,2))
+    ndec=COUNT(obs_masks(:,3))
+
+    WRITE(lu,200) nobs, nra, ndec, obsarc
+200 FORMAT(/"#",3X,"Number of initial observations = ",I14/ &
+         "#",3X,"Number of R.A. included        = ",I14/ &
+         "#",3X,"Number of Dec. included        = ",I14/ &
+         "#",3X,"Observational time arc         = ",F14.4,3X,"days")
+
+    WRITE(lu,"(A)") "#"
+
+    CALL getParameters(storb, dyn_model=dyn_model_prm, integrator=integrator, &
+         element_type = element_type_prm, &
+         dchi2_rejection = dchi2_rejection_prm, regularized_pdf = regularization_prm, &
+         accept_multiplier = accept_multiplier_prm, &
+         res_accept = res_accept_prm, &
+         chi2_min_prm = chi2_min_prm, &
+         dchi2_prm = dchi2, &
+         vov_norb = vov_norb_prm, vov_ntrial = vov_ntrial_prm, &
+         vov_nmap = vov_nmap_prm, vov_scaling = vov_scaling_prm, &
+         vov_mapping_mask=vov_mapping_mask_prm)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    orb_arr_cmp => getSampleOrbits(storb)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+    t = getTime(orb_arr_cmp(1))
+
+    pdf_arr_cmp => getPDFValues(storb)
+    rchi2_arr_cmp => getReducedChi2Distribution(storb)
+    rms_arr_cmp => getRMSDistribution(storb)
+    CALL getResults(storb, reg_apr_arr=reg_apr_arr_cmp, &
+         jac_arr=jac_arr_cmp, &
+         vov_norb_cmp=vov_norb_cmp, &
+         vov_ntrial_cmp=vov_ntrial_cmp, &
+         vov_scaling_ready_cmp=vov_scaling_ready_cmp)
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVOVResults", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+    indx_ml = MAXLOC(pdf_arr_cmp,dim=1)
+
+    elements = getElements(orb_arr_cmp(indx_ml), "keplerian")
+    IF (error) THEN
+       error = .FALSE.
+       elements = getElements(orb_arr_cmp(indx_ml), "cartesian")
+       str1 = "CAR elements    = "
+       str2 = "CAR stdevs      = "
+    ELSE
+       elements(3:6) = elements(3:6)/rad_deg
+       str1 = "KEP elements    = "
+       str2 = "KEP stdevs      = "
+    END IF
+
+    elem_stdevs = getStandardDeviations(storb, "keplerian")
+    IF (error) THEN
+       error = .TRUE.
+       CALL errorMessage("io / writeVoVResults", &
+            "TRACE BACK 30", 1)
+       RETURN
+    END IF
+    elem_stdevs(3:6) = elem_stdevs(3:6)/rad_deg
+
+    WRITE(lu,700) getCalendarDateString(t,"tdt"), getJD(t,"tdt"), &
+         str1(1:18), elements, str2(1:18), elem_stdevs, &
+         pdf_arr_cmp(indx_ml),rchi2_arr_cmp(indx_ml)+nra+ndec,&
+         SQRT(0.5*(rms_arr_cmp(indx_ml,2)**2+rms_arr_cmp(indx_ml,3)**2))/rad_asec,&
+         MINVAL(reg_apr_arr_cmp),MAXVAL(reg_apr_arr_cmp),&
+         MINVAL(jac_arr_cmp(:,1)),MAXVAL(jac_arr_cmp(:,1)),&
+         MINVAL(SQRT(0.5*(rms_arr_cmp(:,2)**2+rms_arr_cmp(:,3)**2)))/rad_asec,&
+         MAXVAL(SQRT(0.5*(rms_arr_cmp(:,2)**2+rms_arr_cmp(:,3)**2)))/rad_asec
+
+700 FORMAT("#",3X,"ORBITAL-ELEMENT PDF" /&
+         "#",3X," Epoch            = ",A," = ",F13.5," TDT"/&
+         "#",3X," Maximum likelihood (ML) orbit" /&
+         "#",3X,"  ",A18,6(F15.10,1X)/&
+         "#",3X,"  ",A18,6(F15.10,1X)/&
+         "#",3X,"  ML value        =",E16.6/ &
+         "#",3X,"  ML reduced chi2 =",E16.6/ &
+         "#",3X,"  ML rms          =",E16.6,3X,"arcsec"/ &
+         "#",3X," Apriori pdf, min =",E16.6/ &
+         "#",3X,"              max =",E16.6/ &
+         "#",3X," Jacobian,    min =",E16.6/ &
+         "#",3X,"              max =",E16.6/ &
+         "#",3X," Rms,         min =",E16.6,3X,"arcsec"/ &
+         "#",3X,"              max =",E16.6,3X,"arcsec")
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,220) element_type_prm, &
+         TRIM(dyn_model_prm), &
+         regularization_prm, dchi2_rejection_prm
+220 FORMAT("#",3X,"COMPUTATIONAL PARAMETERS"/&
+         "#",3X,"Element set      = ",A/ &
+         "#",3X,"Dynamical model  = ",A/ &
+         "#",3X,"Regularization   = ",L2/&
+         "#",3X,"Uniform PDF      = ",L2)
+
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,250) vov_norb_cmp, vov_norb_prm, vov_ntrial_cmp,&
+         vov_ntrial_prm
+250 FORMAT("#",3X,"Final   number of sample orbits  = ",I14/ &
+         "#",3X,"Initial number of sample orbits  = ",I14/ &
+         "#",3X,"Final   number of trials         = ",I14/ &
+         "#",3X,"Initial number of trials         = ",I14)
+
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,300) & 
+         MINVAL(stdevs(:,2:3),dim=1),&
+         accept_multiplier_prm,res_accept_prm(1,2:3)/rad_asec,&
+         chi2_min_prm,dchi2
+
+300 FORMAT(&
+         "#",3X,"R.A.*cos Dec. std        (min)   = ",E14.4,3X,"arcsec"/ &
+         "#",3X,"Dec. std                 (min)   = ",E14.4,3X,"arcsec"/ &
+         "#",3X,"Acceptance, residuals"/  &
+         "#",3X,"  sigma multiplier               = ",E14.4/ &
+         "#",3X,"  window for 1st R.A.            = ",E14.4,3X,"arcsec"/ &
+         "#",3X,"  window for 1st Dec.            = ",E14.4,3X,"arcsec"/ &
+         "#",3X,"Acceptance, chi2                   ",3X,/&
+         "#",3X,"  reference value                = ",E14.4/ &
+         "#",3X,"  chi-square difference          = ",E14.4)
+
+    WRITE(lu,"(A)") "#"
+
+    WRITE(lu,400) vov_mapping_mask_prm, &
+         vov_scaling_prm(:,1), &
+         vov_scaling_prm(:,2), &
+         vov_scaling_ready_cmp(:,1), &
+         vov_scaling_ready_cmp(:,2)
+400 FORMAT("#",3X,"Mapping mask         = ",6(3X,L2,1X)/ &
+         "#",3X,"Scaling factors, lower = ",6(F5.1,1X)/ &
+         "#",3X,"                 upper = ",6(F5.1,1X)/ &
+         "#",3X,"Scaling ready,   lower = ",6(L3,3X)/ &
+         "#",3X,"                 upper = ",6(L3,3X))
+
+!!$    ALLOCATE(mask_arr(sor_norb_cmp),res_arr(2,sor_norb_cmp),&
+!!$         ellipse_fac(sor_norb_cmp),stat=err)
+!!$    IF (err /= 0) THEN
+!!$       error = .TRUE.
+!!$       CALL errorMessage("io / writeVOVResults", &
+!!$            "Could not allocate memory.", 1)
+!!$       RETURN       
+!!$    END IF
+!!$
+!!$    DO k=1,2
+!!$       res_arr(1,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),2)
+!!$       res_arr(2,:) = res_arr_cmp(:,sor_pair_arr_prm(1,k),3)       
+!!$       ellipse_fac = &
+!!$            (res_arr(1,:)/res_accept_prm(sor_pair_arr_prm(1,k),2))**2 + &
+!!$            (res_arr(2,:)/res_accept_prm(sor_pair_arr_prm(1,k),3))**2
+!!$       mask_arr(:) = .FALSE.
+!!$       WHERE (ellipse_fac > 1.0_bp)
+!!$          mask_arr = .TRUE.
+!!$       endwhere
+!!$       npoints(k) = COUNT(mask_arr)
+!!$    END DO
+!!$
+!!$    sor_deviates_prm=sor_deviates_prm/rad_asec
+!!$
+!!$    WRITE(lu,400) ADJUSTR(str1(1:14)), ADJUSTR(str2(1:14)), &
+!!$         sor_generat_multiplier_prm, &
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,1),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,1),2:3,2),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,1),&
+!!$         sor_deviates_prm(sor_pair_arr_prm(1,2),2:3,2)
+!!$
+!!$400 FORMAT("#",3X,"Generated, R.A. and Dec. "/ &
+!!$         "#",3X,"  Id. number of 1st observation  = ",A14/ &
+!!$         "#",3X,"  Id. number of 2nd observation  = ",A14/ &
+!!$         "#",3X,"  sigma multiplier               = ",E14.4/ &
+!!$         "#",3X,"  window shift for 1st R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   1st Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window width for 1st R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   1st Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window shift for 2nd R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   2nd Dec.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"  window width for 2nd R.A.      = ",E14.4,3X,"arcsec"/ &
+!!$         "#",3X,"                   2nd Dec.      = ",E14.4,3X,"arcsec")
+!!$    WRITE(lu,"(A)") "#"
+!!$
+!!$    WRITE(lu,550) npoints(1)/REAL(sor_norb_cmp),npoints(2)/REAL(sor_norb_cmp)
+!!$550 FORMAT("#",3X,"Computed, R.A. and Dec. residuals" /&
+!!$         "#",3X,"  Fraction outside ref. ellipse, 1st obs =",E12.4/ &
+!!$         "#",3X,"  Fraction outside ref. ellipse, 2nd obs =",E12.4)
+    DO i=1,SIZE(orb_arr_cmp)
+       CALL NULLIFY(orb_arr_cmp(i))
+    END DO
+    DEALLOCATE(orb_arr_cmp, stat=err)
+    DEALLOCATE(res_arr_cmp, stat=err)
+    DEALLOCATE(rms_arr_cmp, stat=err)
+    DEALLOCATE(res_accept_prm, stat=err)
+    DEALLOCATE(stdevs, stat=err)
+    DEALLOCATE(jac_arr_cmp, stat=err)
+    DEALLOCATE(pdf_arr_cmp, stat=err)
+    DEALLOCATE(reg_apr_arr_cmp, stat=err)
+    DEALLOCATE(obs_masks, stat=err)
+    DEALLOCATE(rchi2_arr_cmp, stat=err)
+    DEALLOCATE(res_arr, stat=err)
+    DEALLOCATE(ellipse_fac, stat=err)
+
+  END SUBROUTINE writeVOVResults
+
+
+
+
+
+END MODULE io
+
Index: trunk/mops/oorb/main/oorb.conf
===================================================================
--- trunk/mops/oorb/main/oorb.conf	(revision 34646)
+++ trunk/mops/oorb/main/oorb.conf	(revision 34646)
@@ -0,0 +1,428 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Option file for OpenOrb executable 'oorb'
+#
+# The order in which the keywords are given can be arbitrary, 
+# lines starting with "#" are ignored.
+#
+# Author:  MG
+# Version: 2011-10-13
+
+
+# GENERAL SETTINGS
+
+# Verbose level for informative messages (0=nothing and 5=maximum, default=1)
+verbose.info:   1
+
+# Verbose level for error messages (0=nothing and 5=maximum, default=1)
+verbose.error:   1
+
+# Name of binary file containing JPL's planetary ephemerides,
+# typically deXXX.dat, where XXX is either 405 or 406. Note that the
+# name used *must* include either 405 or 406 since there is no other
+# way to differentiate between the contents.
+planetary_ephemeris_fname: de405.dat
+
+
+# INPUT
+
+# Standard deviation of RA (in asec). If *.mpc[23] files (that may
+# contain information on the observational noise) are the input data,
+# this parameter may be commented out. Otherwise it will override any
+# noise estimates included in the file.
+stdev.ra: 1.0
+
+# Standard deviation of Dec (in asec). If *.mpc[23] files (that may
+# contain information on the observational noise) are the input data,
+# this parameter may be commented out. Otherwise it will override any
+# noise estimates included in the file.
+stdev.dec: 1.0
+
+
+# OUTPUT
+
+# Element type to be used in the resulting orbital element file
+# [ keplerian | cartesian | cometary ]  
+element_type_out: keplerian
+
+# Automatic plot generation (T=yes/F=no)
+plot.results: T
+
+# Automatic plot opening for each object (T=yes/F=no)
+plot.open: F
+
+# Format of output observation file
+# [ mpc | des ]
+observation.format.out: des
+
+# Format of output orbit file
+# [ orb | des ]
+orbit.format.out: orb
+
+
+# GENERAL INVERSION PARAMETERS
+
+# Orbital element type used during computations
+# [ keplerian | cartesian | cometary ]  
+element_type_comp: cartesian
+
+# Computation epoch TT (YYYY/MM/DD.DDDDD or JD or MJD) 
+# If left unspecified and doing inversion, the midnight closest to 
+# the observational mid-epoch will be used. 
+#epoch.cal:  2008/10/6.1146
+#epoch.jd:      2453800.5
+#epoch.mjd:       53800.0
+
+# Toggle outlier rejection
+#outlier_rejection:
+
+# Outlier criterion (sigma multiplier)
+outlier.multiplier: 4.0
+
+# Sigma multiplier for generation of deviates
+generation.multiplier:    4.0
+
+# Defines whether the generated deviates are drawn from a Gaussian
+# distribution (T) or a uniform distribution (F).
+generation.gaussian_deviates: F
+
+# Sigma multiplier for acceptance windows
+accwin.multiplier:      4.0
+
+
+# PROPAGATION PARAMETERS
+
+# Dynamical model
+# [ 2-body | n-body ]
+dynamical_model:      2-body
+
+# Perturbing bodies to be taken into account in n-body propagation
+# [ T | F ]
+perturber.Mercury: T
+perturber.Venus:   T
+perturber.Earth:   T
+perturber.Moon:    T
+perturber.Mars:    T
+perturber.Jupiter: T
+perturber.Saturn:  T
+perturber.Uranus:  T
+perturber.Neptune: T
+perturber.Pluto:   T
+
+# Integrator (only used if dynamical model is different from
+# 2-body).
+# [ bulirsch-stoer ]
+integrator: bulirsch-stoer
+
+# Integrator step length (in days)
+integration_step:      2.0
+
+# Relativistic corrections
+relativity: T
+
+# Dynamical model of the initial orbit
+# [ 2-body | n-body ]
+dynamical_model_init:      2-body
+
+# Integrator of the initial orbit (only used if dynamical model is
+# different from 2-body).
+# [ bulirsch-stoer ] 
+integrator_init: bulirsch-stoer
+
+# Integrator step length of the initial orbit (in days)
+integration_step_init:       2.0
+
+
+# STATISTICAL PARAMETERS
+
+# Use the dchi2 criterion when deciding which trial orbits are
+# rejected (default on).
+dchi2_rejection: T
+
+# Maximum chi2 difference between best-fit orbit and accepted sample
+# orbits (20.1 = 99.73% of the total probability mass, 30 = XX % of
+# the total probability mass).
+dchi2.max: 30
+
+# Regularize the PDF using Jeffreys' prior (default off).
+reg.pdf:         F
+
+# Read observation mask from observation file
+obs.mask:        F
+
+# Assumed minimum value for chi2 at start of inversion ('-1' equals
+# setting the minimum to 2 * number of observations)
+chi2_min.init:  -1
+
+
+# BAYESIAN (INFORMATIVE) A PRIORI PARAMETERS
+
+# Lower limit for semimajor axis in AU (default: r_Sun = 0.00465424 AU)
+apriori.a.min : 0.00465424
+
+# Upper limit for semimajor axis in AU
+apriori.a.max : 1000.0
+
+# Lower limit for perihelion distance in AU
+#apriori.q.min : 0.00465424
+
+# Upper limit for perihelion distance in AU
+#apriori.q.max : 1.3 
+
+# Lower limit for aphelion distance in AU
+#apriori.Q.min : 
+
+# Upper limit for aphelion distance in AU
+#apriori.Q.max : 1.3 
+
+# Lower limit for rho in AU (default: 10*r_Earth = 0.000425641 AU)
+#apriori.rho.min : 0.000425641 
+
+# Upper limit for rho in AU (default: not defined)
+#apriori.rho.max :
+
+
+# STATISTICAL ORBITAL RANGING
+
+# Method for solving the two-point boundary-value problem
+# [ continued fraction | p-iteration | n-body amoeba ]
+sor.two_point_method: continued fraction
+
+# Type of ranging (1=basic, 2=automatic, 3=stepwise)
+sor.type:           2
+
+# Number of requested sample orbits
+sor.norb:           2000
+
+# Maximum number of trial orbits
+sor.ntrial:         10000000
+
+# Method for solving the two-point boundary-value problem during
+# the preliminary steps of stepwise Ranging
+# [ continued fraction | p-iteration | n-body amoeba ]
+sor.two_point_method_sw: continued fraction
+
+# Number of requested sample orbits for the preliminary steps of
+# stepwise ranging 
+sor.norb.sw:        500
+
+# Maximum number of trial orbits for the preliminary steps of
+# stepwise ranging
+sor.ntrial.sw:      200000
+
+# Maximum number of iterations in automatic/stepwise Ranging
+sor.niter:          3
+
+# Lower topocentric range bound corresponding to the first date 
+# (observer -> target) [AU]
+sor.rho11.init:     0.0
+
+# Upper topocentric range bound corresponding to the first date 
+# (observer -> target) [AU]
+sor.rho12.init:     100.0
+
+# Lower topocentric range bound of the second date relative to the 
+# generated range of the first date [AU]
+#sor.rho21.init:    -0.1
+
+# Upper topocentric range bound of the second date relative to the 
+# generated range of the first date [AU]
+#sor.rho22.init:     0.1
+
+# Offset for generation windows RA1, Dec1, RA2, Dec2 [asec]
+sor.genwin.offset:    0.0 0.0 0.0 0.0
+
+# Toggle use of random observation pair. Default is off, that is, use
+# fixed pair (cronologically first and last).  
+#sor.ran.obs:
+
+# Bounds to be iterated in automatical versions 
+# (rho1_lo, rho1_hi, rho2_lo, rho2_hi) 
+sor.iterate_bounds: T T T T
+
+
+# VOLUME OF VARIATION
+
+# Type of method (1=basic, 2=automatic)
+vov.type:           2
+
+# Number of requested sample orbits
+vov.norb:           1000
+
+# Maximum number of trial orbits
+vov.ntrial:         1000000
+
+# Number of requested sample orbits during iteration phase of
+# automatic VoV.
+vov.norb_iter:      1000
+
+# Maximum number of trial orbits during iteration phase of automatic
+# VoV.
+vov.ntrial_iter:    1000000
+
+# Maximum number of iterations during automatic VoV
+vov.niter:          5
+
+# Mapping element (T indicates mapping element, the five other
+# elements should be marked with F)
+vov.mapping_mask: T F F F F F
+
+# Number of mapping points
+vov.nmap:           101
+
+# Scaling factors (initial scaling factors for automatic VoV)
+vov.scaling.lo:  5.0 5.0 5.0 2.0 2.0 2.0
+vov.scaling.hi:  5.0 5.0 5.0 2.0 2.0 2.0
+
+
+# VIRTUAL OBSERVATION MCMC
+
+# Type of method (1=basic, 2=automatic)
+vomcmc.type:           1
+
+# Number of requested sample orbits
+vomcmc.norb:           200
+
+# Maximum number of trial orbits
+vomcmc.ntrial:         1000000
+
+# Number of requested sample orbits during iteration phase of
+# automatic VOMCMC.
+vomcmc.norb_iter:      1000
+
+# Maximum number of trial orbits during iteration phase of automatic
+# VOMCMC.
+vomcmc.ntrial_iter:    1000000
+
+# Maximum number of iterations during automatic VOMCMC.
+vomcmc.niter:          5
+
+# Mapping element (T indicates mapping element, the five other
+# elements should be marked with F)
+vomcmc.mapping_mask: T F F F F F
+
+# Number of mapping points
+vomcmc.nmap:           10
+
+# Scaling factors (initial scaling factors for automatic VOMCMC)
+vomcmc.scaling.lo:  2.0 2.0 2.0 2.0 2.0 2.0
+vomcmc.scaling.hi:  2.0 2.0 2.0 2.0 2.0 2.0
+
+
+# LEAST SQUARES
+
+# Correction factor for the iterative solution of the least-squares
+# problem (NOT used for the default [Levenberg-Marquardt] algorithm)
+# [0:1]
+ls.correction_factor:  0.2
+
+# Maximum acceptable reduced chi2 value for calling a differential
+# correction procedure successful (note that a failure to meet this
+# criteria may indicate that the assumption for the astrometric
+# uncertainty is too optimistic, ie, too small.)
+ls.rchi2.acceptable:  1.2
+
+# Maximum number of major iterations
+ls.niter_major.max:  20
+
+# Minimum number of major iterations
+ls.niter_major.min:  2
+
+# Number of iterations per scheme
+ls.niter_minor:  100
+
+# Elements to included in the correction process (indicated with
+# T). Fixed elements should be marked with F.
+ls.element_mask: T T T T T T
+
+
+# COVARIANCE SAMPLING
+
+# Generate a trial orbit by adding normally (T) or uniformly (F)
+# distributed offsets to the nominal orbit
+cos.gaussian: F
+
+# Size of volume to be sampled as the number of sigmas
+cos.nsigma: 8
+
+# Number of sample orbits requested
+cos.norb: 100
+
+# Maximum number of trial orbits
+cos.ntrial: 1000
+
+
+# SIMPLEX OPTIMIZATION
+
+# Reduced chi2 of the worst-fitting sample orbit (out of 7) required
+# for successfully ending the optimization 
+smplx.tol: 1.05
+
+# Maximum number of function evaluations
+smplx.niter: 1000
+
+# Tries to force all 7 orbits below smplx.tol if set to true (T) by
+# reinitializing when the orbits are above smplx.tol and the
+# optimization stalls due to too similar orbits. The optimization is
+# considered successful when the optimization stalls due to orbit
+# similarity if set to false (F).
+smplx.force: F
+
+# The treshold fractional range from highest to lowest chi2 which
+# either reinitializes the orbits or ends the optimization if very
+# similar chi2 values.
+smplx.similarity.tol: 0.001
+
+
+# OBSERVATION SAMPLING
+
+# Number of sample orbits requested
+os.norb: 200
+
+# Maximum number of generated observation sets
+os.ntrial: 10000
+
+# Type of MCMC sampling to be used. The options are (1) independence
+# sampling Metropolis-Hastings where the new observation sets are
+# always generated around the original observations and the acceptance
+# decision is made after comparison with the previous accepted orbit,
+# and (2) random-walk Metropolis-Hastings where the new observations
+# are generated around the observations generated for the previous
+# accepted orbit and the acceptance decision is made after comparison
+# with the previous accepted orbit.
+os.sampling_type: 1
+
+
+# PHYSICAL PARAMETERS
+
+# Toggle estimation of H(alpha=0) magnitude
+# [ T | F ] 
+pp.H_estimation: T
+
+# Use given fixed slope parameter G when estimating H if specified 
+pp.G : 0.15
+
+# Use given fixed uncertainty for the slope parameter G when
+# estimating uncertainty for H if specified
+pp.G_unc : 0.10
Index: trunk/mops/oorb/main/oorb.f90
===================================================================
--- trunk/mops/oorb/main/oorb.f90	(revision 34646)
+++ trunk/mops/oorb/main/oorb.f90	(revision 34646)
@@ -0,0 +1,8943 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Description*:
+!!
+!! Main program for various tasks that include orbit computation.
+!!
+!! @author  MG
+!! @version 2012-04-30
+!!
+PROGRAM oorb
+
+  USE Base_cl
+  USE File_cl
+  USE Time_cl
+  USE CartesianCoordinates_cl
+  USE SphericalCoordinates_cl
+  USE Observatories_cl
+  USE Orbit_cl
+  USE Observation_cl
+  USE Observations_cl
+  USE StochasticOrbit_cl
+  USE PhysicalParameters_cl
+  USE cl_options
+  USE planetary_data  
+  USE statistics
+  USE io
+
+  IMPLICIT NONE
+  TYPE (PhysicalParameters) :: &
+       physparam
+  TYPE (StochasticOrbit), DIMENSION(:), ALLOCATABLE :: &
+       storb_arr_in
+  TYPE (StochasticOrbit) :: &
+       storb
+  TYPE (Orbit), DIMENSION(:,:), POINTER :: &
+       orb_lt_corr_arr2
+  TYPE (Orbit), DIMENSION(:), POINTER :: &
+       orb_arr_in
+  TYPE (Orbit), DIMENSION(:), POINTER :: &
+       orb_arr, &
+       orb_arr_, &       
+       orb_arr_cmp, &
+       orb_lt_corr_arr
+  TYPE (Orbit) :: &
+       orb, &
+       ref_orb
+  TYPE (Observations), DIMENSION(:), POINTER :: &
+       obss_sep
+  TYPE (Observations) :: &
+       obss, &
+       obss_in  
+  TYPE (Observation) :: &
+       obs
+  TYPE (Observation), DIMENSION(:), POINTER :: &
+       obs_arr
+  TYPE (Observatories) :: &
+       obsies
+  TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: &
+       ephemerides_arr
+  TYPE (SphericalCoordinates), DIMENSION(:), POINTER :: &
+       ephemerides
+  TYPE (SphericalCoordinates) :: &
+       ephemeris, &
+       scoord
+  TYPE (CartesianCoordinates), DIMENSION(:), POINTER :: &
+       observers
+  TYPE (CartesianCoordinates) :: &
+       ccoord, &
+       obsy_ccoord, &
+       sun_ccoord
+  TYPE (Time) :: &
+       epoch, &
+       epoch0, &
+       epoch1, &
+       t
+  TYPE (File) :: &
+       conf_file, &                                                 !! Configuration file.
+       obs_file, &                                                  !! Generic observation file.
+       orb_in_file, &                                               !! Input orbit file.
+       orb_out_file, &                                              !! Output orbit file.
+       out_file, &                                                  !! Generic output file.
+       tmp_file                                                     !! Generic temporary file.
+  CHARACTER(len=ELEMENT_TYPE_LEN), DIMENSION(:), ALLOCATABLE :: &
+       element_type_pdf_arr_in                                      !! Element type of input orbital-element PDF.
+  CHARACTER(len=OBSY_CODE_LEN), DIMENSION(:), POINTER :: &
+       obsy_code_arr                                                !! IAU/MPC designated observatory code.
+  CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: &
+       group_name_arr, &
+       id_arr_storb_in, &
+       id_arr_in, &
+       id_arr
+  CHARACTER(len=32), DIMENSION(:), ALLOCATABLE :: &
+       str_arr
+  CHARACTER(len=32), DIMENSION(6) :: &
+       element_str_arr, &
+       stdev_str_arr
+  CHARACTER(len=32), DIMENSION(5) :: &
+       corr_str_arr
+  CHARACTER(len=1024), DIMENSION(4) :: &
+       header                                                       !! Generic header.
+  CHARACTER(len=FNAME_LEN) :: &
+       conf_fname, &                                                !! Path to configuration file (incl. fname). 
+       planetary_ephemeris_fname, &
+       gnuplot_scripts_dir, &                                       !! Path to Gnuplot scripts directory. 
+       obs_fname, &                                                 !! Path to observation file (incl. fname).
+       orb_in_fname, &                                              !! Path to input orbit file (incl. fname).
+       orb_out_fname, &                                             !! Path to output orbit file (incl. fname).
+       out_fname, &                                                 !! Path to generic output file (incl. fname).
+       tmp_fname, &
+       line
+  CHARACTER(len=ELEMENT_TYPE_LEN) :: &
+       element_type_comp_prm, &                                     !! Element type to be used in computations.
+       element_type_in, &                                           !! Element type of input orbit(s).
+       element_type_out_prm                                         !! Element type of output orbit(s).
+  CHARACTER(len=DYN_MODEL_LEN) :: &
+       dyn_model, &                                                 !! Dynamical model.
+       dyn_model_init                                               !! Dynamical model used to propagate init orbit to epoch in LSL.
+  CHARACTER(len=INTEGRATOR_LEN) :: &
+       integrator, &                                                !! Integrator.
+       integrator_init                                              !! Integrator used to propagate init orbit to epoch in LSL.
+  CHARACTER(len=FRAME_LEN) :: &
+       frame
+  CHARACTER(len=256) :: &
+       frmt, &
+       str, &
+       suffix, &
+       task
+  CHARACTER(len=64) :: &
+       sor_2point_method, &                                         !! Method used for 2-point boundary-value problem. 
+       sor_2point_method_sw                                         !! Method used for 2-point boundary-value problem in stepwise Ranging.
+  CHARACTER(len=DESIGNATION_LEN) :: &
+       id                                                           !! Number or temporary designation of asteroid.
+  CHARACTER(len=8) :: &
+       observation_format_out, &                                    !! Format of output observations
+       orbit_format_out                                             !! Format of output orbits
+  CHARACTER(len=OBSY_CODE_LEN) :: &
+       obsy_code                                                    !! IAU/MPC designated observatory code.
+  REAL(bp), DIMENSION(:,:,:), POINTER :: &
+       cov_arr, &
+       cov_arr_in, &                                                !! Input array of covariance matrices.
+       encounters, &
+       HG_arr_storb_in
+  REAL(bp), DIMENSION(:,:), POINTER :: &
+       apoapsis_distance_pdf, &
+       HG_arr_in, &
+       jac_arr_cmp, &
+       pdfs_arr, &
+       periapsis_distance_pdf, &
+       planeph, &
+       vov_map, &
+       vomcmc_map
+  REAL(bp), DIMENSION(:,:), ALLOCATABLE :: &
+       elements_arr, &
+       ephem_, &
+       hist, &
+       jac_arr_in, &
+       mean_arr, &
+       temp_arr
+  REAL(bp), DIMENSION(6,6) :: &
+       corr, &
+       cov
+  REAL(bp), DIMENSION(6,2) :: &
+       vov_scaling_cmp, &
+       vov_scaling_prm, &
+       vomcmc_scaling_cmp, &
+       vomcmc_scaling_prm
+  REAL(bp), DIMENSION(2,2) :: &
+       sor_rho_cmp
+  REAL(bp), DIMENSION(:), POINTER :: &
+       rchi2_arr_cmp, &
+       pdf_arr, &
+       pdf_arr_cmp, &
+       pdf_arr_in, &
+       reg_apr_arr_cmp, &
+       weight_arr
+  REAL(bp), DIMENSION(:), ALLOCATABLE :: &
+       arc_arr, &
+       rchi2_arr_in, &
+       reg_apr_arr_in, &
+       real_arr
+  REAL(bp), DIMENSION(10) :: &
+       tisserands_parameters,  &
+       jacobi_constants
+  REAL(bp), DIMENSION(6) :: &
+       comp_coord, &
+       coordinates, &
+       elements, &
+       h_ecl_car_coord_obj, &
+       h_ecl_car_coord_obsy, &
+       lower_limit, &
+       upper_limit, &
+       mean, &
+       obs_stdev_arr_prm, &
+       stdev_arr
+  REAL(bp), DIMENSION(4) :: &
+       sor_genwin_offset, &
+       sor_rho_init
+  REAL(bp), DIMENSION(3) :: &
+       geoc_obsy, &
+       obsy_moon, &
+       obsy_obj, &
+       obsy_pos, &
+       obsy_sun, &
+       pos, &
+       pos_opp, &
+       pos_sun, &
+       sun_moon, &
+       pos_ast, &
+       vec3
+  REAL(bp), DIMENSION(2) :: &
+       bounds
+  REAL(bp) :: &
+       Delta, &
+       H_max, H_value, &
+       G_value, &
+       accwin_multiplier, angular_distance_dec, angular_distance_ra, &
+       apoapsis_distance, apriori_a_max, &
+       apriori_a_min, apriori_apoapsis_max, apriori_apoapsis_min, &
+       apriori_periapsis_max,  apriori_periapsis_min, &
+       apriori_rho_min, &
+       chi2_min_init, cos_nsigma, cos_obj_phase, &
+       day0, day1, dDelta, ddec, dec, dra, dt, dt_, dt_fulfill_night, dchi2_max, &
+       ephemeris_r2, &
+       hdist, heliocentric_r2, hlat, hlon, hoclat, hoclon, &
+       i_min, i_max, integration_step, integration_step_init, &
+       ls_correction_factor, ls_rchi2_acceptable, lunar_alt, lunar_alt_max, &
+       lunar_elongation, lunar_elongation_min, lunar_phase, &
+       lunar_phase_min, lunar_phase_max, &
+       mag, mjd, mjd0, mjd1, mjd_tai, mjd_tt, mjd_utc, moid, &
+       obj_alt, obj_alt_min, obj_phase, obj_vmag, obj_vmag_max, &
+       observer_r2, obsy_moon_r2, opplat, opplon, outlier_multiplier_prm, &
+       output_interval, &
+       periapsis_distance, peak, pp_G, pp_G_unc, probability_mass, &
+       ra, &
+       sec, smplx_tol, smplx_similarity_tol, &
+       solar_elongation, solar_elon_min, solar_elon_max, &
+       solar_alt, solar_alt_max, solelon_max, solelon_min, generat_multiplier, stdev, &
+       step, sun_moon_r2, sunlat, sunlon, &
+       timespan, tlat, tlon, toclat, toclon, tsclat, tsclon
+  INTEGER, DIMENSION(:), POINTER :: &
+       repetition_arr_cmp, &
+       repetition_arr_in
+  INTEGER, DIMENSION(:), ALLOCATABLE :: &
+       indx_arr, &
+       int_arr
+  INTEGER :: &
+       cos_norb, cos_ntrial, &
+       err, &
+       err_verb_, &
+       i, &
+       iday, &
+       indx, indx_max, indx_min, &
+       iobj, &
+       iorb, &
+       istep, &
+       j, &
+       k, k_max, &
+       l, &
+       m, &
+       ls_niter_major_max, &
+       ls_niter_major_min, &
+       ls_niter_minor, &
+       lu, &
+       lu_orb_out, &
+       min, minstep, &
+       month, month0, month1, &
+       ncenter, nhist, nobj, nobs, norb, noutlier, nstep, &
+       os_norb, os_ntrial, os_sampling_type, &
+       smplx_niter, &
+       sor_niter, sor_norb, sor_norb_sw, sor_ntrial, sor_ntrial_sw, &
+       sor_type_prm, &
+       vov_type, vov_type_prm, vov_norb, vov_ntrial, vov_niter, &
+       vov_norb_iter, vov_ntrial_iter, vov_nmap, &
+       vomcmc_type, vomcmc_type_prm, vomcmc_norb, vomcmc_ntrial, vomcmc_niter, &
+       vomcmc_norb_iter, vomcmc_ntrial_iter, vomcmc_nmap, &
+       year, year0, year1
+  LOGICAL, DIMENSION(:,:), POINTER :: &
+       obs_masks
+  LOGICAL, DIMENSION(:), POINTER :: &
+       perturbers
+  LOGICAL, DIMENSION(6) :: &
+       ls_element_mask, &
+       vov_mapping_mask, &
+       vomcmc_mapping_mask
+  LOGICAL, DIMENSION(4) :: &
+       sor_iterate_bounds
+  LOGICAL :: &
+       compress, &
+       cos_gaussian, &
+       first, &
+       force_pdf, &
+       gaussian_rho, &
+       generat_gaussian_deviates, &
+       mjd_epoch, &
+       noise, &
+       outlier_rejection_prm, &
+       plot_open, &
+       plot_results, &
+       relativity, &
+       pp_H_estimation, &
+       random_obs, &
+       regularized, &
+       separately, separately_, & !! Output orbit(s)/ephemerides/etc separately for each object
+       dchi2_rejection, &
+       write_residuals
+
+  ! Defaults:
+  error = .FALSE.
+  task = " "
+  compress = .FALSE.
+  orbit_format_out = "des"
+  element_type_comp_prm = "keplerian"
+  element_type_out_prm = "keplerian"
+  planetary_ephemeris_fname = "de405.dat"
+  err_verb = 1
+  info_verb = 1
+  gnuplot_scripts_dir = "."
+  obs_stdev_arr_prm = -1.0_bp
+  observation_format_out = "des"
+  obsy_code = "500"
+  dyn_model = " "
+  integrator = " "
+  integration_step = -1.0_bp
+  orb_in_fname = " "
+  orb_out_fname = " "
+  separately = .FALSE.
+  outlier_multiplier_prm = 3.0_bp
+  outlier_rejection_prm = .FALSE.
+  plot_open = .FALSE.
+  plot_results = .FALSE.
+  relativity = .TRUE.
+  pp_H_estimation = .FALSE.
+  pp_G = 99.9_bp
+  pp_G_unc = 99.9_bp
+  mjd_epoch = .TRUE.
+  write_residuals = .TRUE.
+
+  IF (get_cl_option("--version",.FALSE.)) THEN
+     WRITE(stdout,"(A)") ""
+     WRITE(stdout,"(A)") "OpenOrb v1.0.1"
+     WRITE(stdout,"(A)") "Copyright 2011 Mikael Granvik, Jenni Virtanen, Karri Muinonen,"
+     WRITE(stdout,"(A)") "               Teemu Laakso, Dagmara Oszkiewicz"
+     WRITE(stdout,"(A)") ""
+     WRITE(stdout,"(A)") "OpenOrb comes with NO WARRANTY, to the extent permitted by law."
+     WRITE(stdout,"(A)") "You may redistribute copies of OpenOrb under the terms of the "
+     WRITE(stdout,"(A)") "GNU General Public License. For more information about these "
+     WRITE(stdout,"(A)") "matters, see the file named COPYING or visit "
+     WRITE(stdout,"(A)") "<http://www.gnu.org/licenses/>."
+     WRITE(stdout,"(A)") ""
+  END IF
+
+  task = get_cl_option("--task=",task)
+  IF (LEN_TRIM(task) == 0 .OR. get_cl_option("--help",.FALSE.)) THEN
+     WRITE(stdout,"(A)") "Usage:" 
+     WRITE(stdout,"(A)") "oorb [ --version | --help | --task=TASK ] [ options ]"
+     WRITE(stdout,"(A)") " or"
+     WRITE(stdout,"(A)") "oorb [ --version | --help | --task=TASK ] [ options ]"
+     WRITE(stdout,"(A)") ""
+     WRITE(stdout,"(A)") ""
+     STOP
+  END IF
+
+  ! Set path to configuration file:
+  ! First, try the environment variable:
+  CALL getenv("OORB_CONF", conf_fname)
+  IF (LEN_TRIM(conf_fname) == 0) THEN
+     ! Second, if environment variable not defined use default:
+     conf_fname = "./oorb.conf"
+  END IF
+  ! Third, (if specified) the command-line option overrides the previous:
+  conf_fname = get_cl_option("--conf=",conf_fname)
+  CALL NEW(conf_file, conf_fname)
+  CALL setActionRead(conf_file)
+  CALL setStatusOld(conf_file)
+  CALL OPEN(conf_file)
+  IF (error) THEN
+     CALL errorMessage("oorb", &
+          "Configuration file missing or error while opening it.", 1)
+     STOP
+  END IF
+  CALL readConfigurationFile(conf_file, &
+       planetary_ephemeris_fname=planetary_ephemeris_fname, &
+       err_verb=err_verb, &
+       info_verb=info_verb, &
+       element_type_comp=element_type_comp_prm, &
+       element_type_out=element_type_out_prm, &
+       obs_stdev_arr=obs_stdev_arr_prm, &
+       observation_format_out=observation_format_out, &
+       orbit_format_out=orbit_format_out, &
+       outlier_rejection=outlier_rejection_prm, &
+       outlier_multiplier=outlier_multiplier_prm, &
+       dchi2_rejection=dchi2_rejection, &
+       dchi2_max=dchi2_max, &
+       plot_open=plot_open, &
+       plot_results=plot_results, &
+       dyn_model=dyn_model, &
+       perturbers=perturbers, &
+       integrator=integrator, &
+       integration_step=integration_step, &
+       relativity=relativity, &
+       pp_H_estimation=pp_H_estimation, &
+       pp_G=pp_G, &
+       pp_G_unc=pp_G_unc)
+  IF (error) THEN
+     CALL errorMessage("oorb", &
+          "TRACE BACK (15)", 1)
+     STOP
+  END IF
+  IF (.NOT.ALL(obs_stdev_arr_prm < 0.0_bp)) THEN
+     WHERE (obs_stdev_arr_prm < 0.0_bp)
+        obs_stdev_arr_prm = 0.0_bp
+     END WHERE
+  END IF
+  CALL set_relativity(relativity)
+
+  ! Set path to data files:
+  CALL setAccessToDataFiles()
+  IF (LEN_TRIM(planetary_ephemeris_fname) == 0) THEN
+     planetary_ephemeris_fname = TRIM(EPH_FNAME)
+  END IF
+  CALL JPL_ephemeris_init(error, &
+       filename=TRIM(OORB_DATA_DIR) // "/" // TRIM(planetary_ephemeris_fname)) 
+  IF (error) THEN
+     CALL errorMessage("oorb", &
+          "Could not initialize planetary ephemerides using the " // &
+          TRIM(OORB_DATA_DIR) // "/" // TRIM(planetary_ephemeris_fname) // " file.", 1)
+     STOP
+  END IF
+
+  ! Set path to Gnuplot scripts using environment variable:
+  CALL getenv("OORB_GNUPLOT_SCRIPTS_DIR", gnuplot_scripts_dir)
+
+  ! Read observation file if given:
+  obs_fname = get_cl_option("--obs-in="," ")
+  IF (LEN_TRIM(obs_fname) /= 0) THEN
+     CALL NEW(obs_file, TRIM(obs_fname))
+     CALL setActionRead(obs_file)
+     CALL setStatusOld(obs_file)
+     CALL OPEN(obs_file)
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "TRACE BACK (30)", 1)
+        STOP
+     END IF
+     IF (ANY(obs_stdev_arr_prm < 0.0_bp)) THEN
+        CALL NEW(obss_in, obs_file)
+     ELSE
+        CALL NEW(obss_in, obs_file, stdev=obs_stdev_arr_prm)
+     END IF
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "TRACE BACK (35)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obs_file)
+     indx = INDEX(obs_fname,".",back=.TRUE.)
+     out_fname = obs_fname(1:indx-1)
+  ELSE IF (task == "2mpc3" .OR. &
+       task == "2mpc" .OR. &
+       task == "ranging" .OR. &
+       task == "lsl") THEN
+     CALL errorMessage("oorb", &
+          "Path to observation file must be supplied using " // &
+          "the '--obs-in=FILE' option.", 1)
+     STOP
+  END IF
+
+  ! Read orbit file if given:
+  orb_in_fname = get_cl_option("--orb-in=",orb_in_fname)
+  IF (LEN_TRIM(orb_in_fname) /= 0) THEN
+
+     ! Open orbit file
+     CALL NEW(orb_in_file,TRIM(orb_in_fname))
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "TRACE BACK (40)", 1)
+        STOP
+     END IF
+     CALL setActionRead(orb_in_file)
+     CALL setStatusOld(orb_in_file)
+     CALL OPEN(orb_in_file)
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "TRACE BACK (45)", 1)
+        STOP
+     END IF
+
+     ! Decide which routine should read the input 
+     ! file by checking the suffix:
+     indx = INDEX(orb_in_fname, ".", back=.TRUE.)
+     IF (indx == 0) THEN
+        error = .TRUE.
+        CALL errorMessage("oorb", &
+             "Suffix (either .orb or .des) required in orbit file name.",1)
+        STOP
+     END IF
+     suffix = orb_in_fname(indx+1:LEN_TRIM(orb_in_fname))
+     CALL locase(suffix, error)
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "The orbit file suffix contains forbidden characters.", 1)
+        STOP
+     END IF
+
+     SELECT CASE (suffix)
+     CASE ("orb")
+        ! OpenOrb orbit file
+
+        norb = getNrOfLines(orb_in_file) - 4 ! 4 header lines are not taken into count
+        IF (error) THEN
+           CALL errorMessage("oorb", &
+                "TRACE BACK (50)", 1)
+           STOP
+        END IF
+        ALLOCATE(id_arr_in(norb), orb_arr_in(norb), &
+             element_type_pdf_arr_in(norb), cov_arr_in(norb,6,6), &
+             HG_arr_in(norb,4), pdf_arr_in(norb), &
+             rchi2_arr_in(norb), jac_arr_in(norb,3), &
+             reg_apr_arr_in(norb), repetition_arr_in(norb), stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb", &
+                "Could not allocate memory (20).", 1)
+           STOP
+        END IF
+        jac_arr_in = -1.0_bp
+        pdf_arr_in = -1.0_bp
+        cov_arr_in = -1.0_bp
+        repetition_arr_in = 0
+        id_arr_in = " "
+        element_type_pdf_arr_in = " "
+        header(1:4)(:) = " "
+        FORALL (i=1:norb)
+           HG_arr_in(i,1:4) = 99.9_bp
+        END FORALL
+        DO i=1,norb
+           CALL readOpenOrbOrbitFile(getUnit(orb_in_file), header, &
+                element_type_in=element_type_in, id=id_arr_in(i), &
+                orb=orb_arr_in(i), &
+                element_type_pdf=element_type_pdf_arr_in(i), &
+                cov=cov_arr_in(i,:,:), H=HG_arr_in(i,1), &
+                G=HG_arr_in(i,3), pdf=pdf_arr_in(i), &
+                rchi2=rchi2_arr_in(i), reg_apr=reg_apr_arr_in(i), &
+                jac_sph_inv=jac_arr_in(i,1), &
+                jac_car_kep=jac_arr_in(i,2), &
+                jac_equ_kep=jac_arr_in(i,3), &
+                repetitions=repetition_arr_in(i))
+           IF (error) THEN
+              CALL errorMessage("oorb", &
+                   "Could not read orbit file.", 1)
+              STOP
+           END IF
+        END DO
+        CALL NULLIFY(orb_in_file)
+
+        ! Calculate the number of different objects in the orbit file:
+        ALLOCATE(indx_arr(SIZE(id_arr_in)))
+        CALL quickSort(id_arr_in, indx_arr, errstr)
+        IF (LEN_TRIM(errstr) /= 0) THEN
+           CALL errorMessage("oorb", &
+                "Could not sort orbit id's. " // TRIM(errstr), 1)
+           STOP
+        END IF
+        nobj = 1
+        DO i=1,SIZE(id_arr_in)-1
+           IF (id_arr_in(indx_arr(i)) /= id_arr_in(indx_arr(i+1))) THEN
+              nobj = nobj + 1
+           END IF
+        END DO
+        DEALLOCATE(indx_arr)
+
+        ! Initialize stochasticorbits if uncertainty information available:
+        IF (norb > nobj .AND. ALL(pdf_arr_in /= -1.0_bp)) THEN
+           ! Sampled PDF available
+           ALLOCATE(storb_arr_in(nobj))
+           i = 0
+           j = 1
+           ! generate storbs for sets 1...n-1
+           DO k=2,SIZE(id_arr_in)
+              IF (id_arr_in(k-1) /= id_arr_in(k)) THEN
+                 i = i + 1
+                 CALL NEW(storb_arr_in(i), orb_arr_in(j:k-1), pdf_arr_in(j:k-1), &
+                      element_type_pdf_arr_in(1), jac_arr=jac_arr_in(j:k-1,:), &
+                      reg_apr_arr=reg_apr_arr_in(j:k-1), &
+                      rchi2_arr=rchi2_arr_in(j:k-1), &
+                      repetition_arr=repetition_arr_in(j:k-1))
+                 j = k
+              END IF
+           END DO
+           ! generate storb for set n (note k-1 above)
+           i = i + 1
+           CALL NEW(storb_arr_in(i), orb_arr_in(j:), pdf_arr_in(j:), &
+                element_type_pdf_arr_in(1), jac_arr=jac_arr_in(j:,:), &
+                reg_apr_arr=reg_apr_arr_in(j:), &
+                rchi2_arr=rchi2_arr_in(j:), &
+                repetition_arr=repetition_arr_in(j:))
+
+           ALLOCATE(id_arr(nobj), HG_arr_storb_in(nobj,norb,4))
+           id_arr = ""
+           id_arr(1) = id_arr_in(1)
+           HG_arr_storb_in = 99.9_bp 
+           HG_arr_storb_in(1,1,1:4) = HG_arr_in(1,1:4)
+           j = 1
+           k = 1
+           k_max = 1
+           DO i=2,SIZE(id_arr_in)
+              k = k + 1
+              IF (ALL(id_arr(1:j) /= id_arr_in(i))) THEN
+                 j = j + 1
+                 id_arr(j) = id_arr_in(i)
+                 k = 1
+                 HG_arr_storb_in(j,k,1:4) = HG_arr_in(i,1:4)
+              ELSE
+                 HG_arr_storb_in(j,k,1:4) = HG_arr_in(i,1:4)
+              END IF
+              IF (k > k_max) THEN
+                 k_max = k
+              END IF
+           END DO
+           ALLOCATE(id_arr_storb_in(nobj))
+           id_arr_storb_in = id_arr
+           HG_arr_storb_in => reallocate(HG_arr_storb_in, nobj, k_max, 4)
+           DEALLOCATE(id_arr, id_arr_in, HG_arr_in)
+        ELSE IF (nobj == norb .AND. &
+             ALL(cov_arr_in(:,1,1) > 0.0_bp)) THEN
+           ! Covariance matrix/ces available
+           ALLOCATE(storb_arr_in(norb))
+           DO i=1,norb
+              CALL NEW(storb_arr_in(i), orb_arr_in(i), cov_arr_in(i,:,:), &
+                   cov_type=element_type_in, element_type=element_type_in)            
+           END DO
+           ALLOCATE(id_arr_storb_in(nobj), HG_arr_storb_in(nobj,1,4))
+           id_arr_storb_in = id_arr_in
+           HG_arr_storb_in(1:nobj,1,1:4) = HG_arr_in(1:nobj,1:4)
+           DEALLOCATE(id_arr_in, HG_arr_in)
+        END IF
+
+     CASE ("des")
+        ! Data exchange format
+
+        norb = getNrOfLines(orb_in_file) 
+        IF (error) THEN
+           CALL errorMessage("oorb", &
+                "TRACE BACK (55)", 1)
+           STOP
+        END IF
+        ALLOCATE(id_arr_in(norb), orb_arr_in(norb), &
+             HG_arr_in(norb,4), stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb", &
+                "Could not allocate memory (20).", 1)
+           STOP
+        END IF
+        id_arr_in = " "
+        header = " "
+        CALL readDESOrbitFile(getUnit(orb_in_file), norb, header(1), &
+             id_arr_in, orb_arr_in, HG_arr_in(:,1))
+        IF (error) THEN
+           CALL errorMessage("oorb", &
+                "Could not read orbit file.", 1)
+           STOP
+        END IF
+        CALL NULLIFY(orb_in_file)
+        HG_arr_in(:,3) = 0.15_bp
+        HG_arr_in(:,2) = 99.9_bp
+        HG_arr_in(:,4) = 99.9_bp
+        id_arr_in => reallocate(id_arr_in, norb)
+        orb_arr_in => reallocate(orb_arr_in, norb)
+        HG_arr_in => reallocate(HG_arr_in, norb, 4)
+
+     CASE default
+
+        ! Not a valid suffix.
+        CALL errorMessage("oorb", &
+             "'." // TRIM(suffix) // &
+             "' is not a valid suffix for orbit files. " // &
+             "Use either '.orb' or '.des'.", 1)
+        STOP
+
+     END SELECT
+
+     ! Convert to the desired element type if needed:
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)
+           IF (element_type_in /= "cartesian" .AND. &
+                element_type_comp_prm == "cartesian") THEN
+              CALL toCartesian(storb_arr_in(i), "ecliptic")
+           ELSE IF (element_type_in /= "cometary" .AND. &
+                element_type_comp_prm == "cometary") THEN
+              CALL toCometary(storb_arr_in(i))
+           ELSE IF (element_type_in /= "keplerian" .AND. &
+                element_type_comp_prm == "keplerian") THEN
+              CALL toKeplerian(storb_arr_in(i))
+           ELSE IF (element_type_comp_prm /= "cartesian" .AND. &
+                element_type_comp_prm /= "keplerian") THEN
+              CALL errorMessage("oorb", &
+                   "No such option: " // TRIM(element_type_comp_prm), 1)
+              STOP
+           END IF
+           IF (error) THEN
+              CALL errorMessage("oorb", &
+                   "TRACE BACK (60)", 1)
+              STOP
+           END IF
+        END DO
+        ! Delete 'raw' orbit data
+        DO i=1,norb
+           CALL NULLIFY(orb_arr_in(i))
+        END DO
+        DEALLOCATE(orb_arr_in, stat=err)
+     ELSE
+        DO i=1,norb
+           IF (element_type_comp_prm == "keplerian") THEN
+              CALL toKeplerian(orb_arr_in(i))
+           ELSE IF (element_type_comp_prm == "cartesian") THEN
+              CALL toCartesian(orb_arr_in(i), "ecliptic")
+           ELSE IF (element_type_comp_prm == "cometary") THEN
+              CALL toCometary(orb_arr_in(i))
+           END IF
+           IF (error) THEN
+              CALL errorMessage("oorb", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+        END DO
+     END IF
+     DEALLOCATE(pdf_arr_in, rchi2_arr_in, jac_arr_in, &
+          repetition_arr_in, reg_apr_arr_in, &
+          element_type_pdf_arr_in, stat=err)
+
+  ELSE IF (task == "lsl" .OR. &
+       task == "ephemeris" .OR. &
+       task == "propagation") THEN
+     CALL errorMessage("oorb", &
+          "Path to orbit file must be supplied using " // &
+          "the '--orb-in=FILE' option.", 1)
+     STOP
+  END IF
+
+  ! Choose logical unit for output orbit file (all orbits in same file)
+  orb_out_fname = get_cl_option("--orb-out=",orb_out_fname)
+  IF (LEN_TRIM(orb_out_fname) == 0) THEN
+     lu_orb_out = stdout
+  ELSE
+     CALL NEW(orb_out_file,TRIM(orb_out_fname))
+     CALL OPEN(orb_out_file)
+     IF (error) THEN
+        CALL errorMessage("oorb", &
+             "TRACE BACK (70)", 1)
+        STOP
+     END IF
+     lu_orb_out = getUnit(orb_out_file)
+  END IF
+
+  ! Output orbit(s)/ephemerides/etc written into separate files for
+  ! each object (overrides --orb-out)
+  separately = get_cl_option("--separately",separately)
+
+
+  ! OpenOrb orbit files written use mjd instead of cal date:
+  mjd_epoch = get_cl_option("--oorb-mjd", mjd_epoch)
+
+  SELECT CASE (task)
+
+  CASE ("none")
+
+     CONTINUE
+
+  CASE ("2oorbpdf", "toorbpdf")
+
+     first = .TRUE.
+     tmp_fname = get_cl_option("--id-in=","")
+     IF (LEN_TRIM(tmp_fname) /= 0) THEN
+        ! Read and sort ids
+        CALL NEW(tmp_file, TRIM(tmp_fname))
+        CALL setStatusOld(tmp_file)
+        CALL OPEN(tmp_file)
+        IF (error) THEN
+           STOP
+        END IF
+        j = getNrOfLines(tmp_file)
+        ALLOCATE(id_arr(j))
+        DO i=1,j
+           READ(getUnit(tmp_file),*) id_arr(i)
+        END DO
+        CALL quickSort(id_arr,errstr)
+     END IF
+
+     ! Convert orbits + uncertainties
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)
+           IF (get_cl_option("--id-in=",.FALSE.)) THEN
+              j = binarySearch(id_arr_storb_in(i),id_arr,errstr)
+              IF (j < 0 .OR. LEN_TRIM(errstr) /= 0) THEN
+                 CYCLE
+              END IF
+           END IF
+           IF (containsSampledPDF(storb_arr_in(i))) THEN
+              orb_arr_in => getSampleOrbits(storb_arr_in(i))
+              pdf_arr_in => getPDFValues(storb_arr_in(i), element_type_out_prm)
+              !pdf_arr_in = pdf_arr_in/sum(pdf_arr_in)
+
+              DO j=1,SIZE(orb_arr_in)
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, first, &
+                      element_type_out_prm, id_arr_storb_in(i), &
+                      orb_arr_in(j), pdf=pdf_arr_in(j), &
+                      element_type_pdf=element_type_out_prm, &
+                      H=HG_arr_storb_in(i,j,1), &
+                      G=HG_arr_storb_in(i,j,3), &
+                      mjd=mjd_epoch)
+                 first = .FALSE.
+                 CALL NULLIFY(orb_arr_in(j))
+              END DO
+              DEALLOCATE(orb_arr_in, pdf_arr_in)
+           ELSE
+              orb = getNominalOrbit(storb_arr_in(i))
+              cov = getCovarianceMatrix(storb_arr_in(i), element_type_out_prm)
+              CALL writeOpenOrbOrbitFile(lu_orb_out, first, &
+                   element_type_out_prm, id_arr_storb_in(i), &
+                   orb=orb, cov=cov, H=HG_arr_storb_in(i,j,1), &
+                   G=HG_arr_storb_in(i,j,3), mjd=mjd_epoch)
+              first = .FALSE.
+           END IF
+        END DO
+     ELSE
+        CALL errorMessage("oorb / 2oorbpdf", &
+             "Orbital-element PDFs were not detected in the input.", 1)
+     END IF
+
+     IF (ASSOCIATED(id_arr)) THEN
+        DEALLOCATE(id_arr, stat=err)
+     END IF
+
+  CASE ("2oorb", "toorb")
+
+     norb = HUGE(norb)
+     norb = get_cl_option("--norb=",norb)
+     H_max = get_cl_option("--H-max=",HUGE(H_max))
+     first = .TRUE.
+
+     tmp_fname = get_cl_option("--id-in=","")
+     IF (LEN_TRIM(tmp_fname) /= 0) THEN
+        ! Read and sort ids
+        CALL NEW(tmp_file, TRIM(tmp_fname))
+        CALL setStatusOld(tmp_file)
+        CALL OPEN(tmp_file)
+        IF (error) THEN
+           STOP
+        END IF
+        j = getNrOfLines(tmp_file)
+        ALLOCATE(id_arr(j))
+        DO i=1,j
+           READ(getUnit(tmp_file),*) id_arr(i)
+        END DO
+        CALL quickSort(id_arr,errstr)
+     END IF
+
+     ! Convert orbits
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)        
+           IF (get_cl_option("--id-in=",.FALSE.)) THEN
+              j = binarySearch(id_arr_storb_in(i),id_arr,errstr)
+              IF (j < 0 .OR. LEN_TRIM(errstr) /= 0) THEN
+                 CYCLE
+              END IF
+           END IF
+           IF (containsSampledPDF(storb_arr_in(i))) THEN
+              orb_arr_in => getSampleOrbits(storb_arr_in(i))
+              k = 0
+              DO j=1,SIZE(orb_arr_in)
+                 IF (get_cl_option("--only-prograde",.FALSE.)) THEN
+                    elements = getElements(orb_arr_in(j), "keplerian")
+                    IF (elements(3) > pi/2) THEN
+                       ! retrograde orbit -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 IF (get_cl_option("--H-max=",.FALSE.)) THEN
+                    IF (HG_arr_storb_in(i,j,1) > H_max) THEN
+                       ! too large H magnitude -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 k = k + 1
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, first, &
+                      element_type_out_prm, id_arr_storb_in(i), &
+                      orb_arr_in(j), H=HG_arr_storb_in(i,j,1), &
+                      G=HG_arr_storb_in(i,j,3), mjd=mjd_epoch)
+                 first = .FALSE.
+                 IF (k == norb) THEN
+                    EXIT
+                 END IF
+              END DO
+           ELSE
+              orb = getNominalOrbit(storb_arr_in(i))
+              CALL writeOpenOrbOrbitFile(lu_orb_out, first, &
+                   element_type_out_prm, id_arr_storb_in(i), &
+                   orb=orb, H=HG_arr_storb_in(i,1,1), &
+                   G=HG_arr_storb_in(i,1,3), mjd=mjd_epoch)
+              first = .FALSE.
+           END IF
+        END DO
+     ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+        j = 0
+        DO i=1,SIZE(orb_arr_in)
+           IF (get_cl_option("--id-in=",.FALSE.)) THEN
+              k = binarySearch(id_arr_in(i),id_arr,errstr)
+              IF (k < 0 .OR. LEN_TRIM(errstr) /= 0) THEN
+                 CYCLE
+              END IF
+           END IF
+           IF (get_cl_option("--only-prograde",.FALSE.)) THEN
+              elements = getElements(orb_arr_in(i), "keplerian")
+              IF (elements(3) > pi/2) THEN
+                 ! retrograde orbit -> skip it
+                 CYCLE
+              END IF
+           END IF
+           IF (get_cl_option("--H-max=",.FALSE.)) THEN
+              IF (HG_arr_in(i,1) > H_max) THEN
+                 ! too large H magnitude -> skip it
+                 CYCLE
+              END IF
+           END IF
+           j = j + 1
+           CALL writeOpenOrbOrbitFile(lu_orb_out, first, &
+                element_type_out_prm, id_arr_in(i), orb_arr_in(i), &
+                H=HG_arr_in(i,1), G=HG_arr_in(i,3), mjd=mjd_epoch)
+           first = .FALSE.
+           IF (j == norb) THEN
+              EXIT
+           END IF
+        END DO
+     END IF
+     IF (ASSOCIATED(id_arr)) THEN
+        DEALLOCATE(id_arr, stat=err)
+     END IF
+
+  CASE ("orb2des", "orbitstodes")
+
+     H_max = get_cl_option("--H-max=",HUGE(H_max))
+     i_min = get_cl_option("--i-min=",0.0_bp)
+     i_max = get_cl_option("--i-max=",HUGE(i_max))
+     first = .TRUE.
+
+     tmp_fname = get_cl_option("--id-in=","")
+     IF (LEN_TRIM(tmp_fname) /= 0) THEN
+        ! Read and sort ids
+        CALL NEW(tmp_file, TRIM(tmp_fname))
+        CALL setStatusOld(tmp_file)
+        CALL OPEN(tmp_file)
+        IF (error) THEN
+           STOP
+        END IF
+        j = getNrOfLines(tmp_file)
+        ALLOCATE(id_arr(j))
+        DO i=1,j
+           READ(getUnit(tmp_file),*) id_arr(i)
+        END DO
+        CALL quickSort(id_arr,errstr)
+     END IF
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)
+           IF (get_cl_option("--id-in=",.FALSE.)) THEN
+              j = binarySearch(id_arr_storb_in(i),id_arr,errstr)
+              IF (j < 0 .OR. LEN_TRIM(errstr) /= 0) THEN
+                 CYCLE
+              END IF
+           END IF
+           IF (containsSampledPDF(storb_arr_in(i))) THEN
+              orb_arr_in => getSampleOrbits(storb_arr_in(i))
+              DO j=1,SIZE(orb_arr_in)
+                 IF (get_cl_option("--H-max=",.FALSE.)) THEN
+                    IF (HG_arr_storb_in(i,j,1) > H_max) THEN
+                       ! too large H magnitude -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 IF (get_cl_option("--only-neos",.FALSE.) .OR. &
+                      get_cl_option("--i-min=",.FALSE.) .OR. &
+                      get_cl_option("--i-max=",.FALSE.)) THEN
+                    elements = getElements(orb_arr_in(j),"cometary")
+                 END IF
+                 IF (get_cl_option("--only-neos",.FALSE.)) THEN
+                    IF (elements(1) > 1.3_bp) THEN
+                       ! too large q -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 IF (get_cl_option("--i-min=",.FALSE.)) THEN
+                    IF (elements(3)/rad_deg < i_min) THEN
+                       ! inclination too small -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 IF (get_cl_option("--i-max=",.FALSE.)) THEN
+                    IF (elements(3)/rad_deg > i_max) THEN
+                       ! inclination too large -> skip it
+                       CYCLE
+                    END IF
+                 END IF
+                 CALL writeDESOrbitFile(lu_orb_out, first, &
+                      element_type_out_prm, id_arr_storb_in(i), &
+                      orb_arr_in(j), HG_arr_storb_in(i,j,1))
+                 IF (error) THEN
+                    CALL errorMessage("oorb", &
+                         "DES output failed at orbit:", 1)
+                    WRITE(stderr,*) j
+                    STOP
+                 END IF
+                 first = .FALSE.
+                 CALL NULLIFY(orb_arr_in(j))
+              END DO
+              DEALLOCATE(orb_arr_in)
+           ELSE
+              IF (HG_arr_storb_in(i,1,1) > H_max) THEN
+                 ! too large H magnitude -> skip it
+                 CYCLE
+              END IF
+              orb = getNominalOrbit(storb_arr_in(i))
+              IF (get_cl_option("--only-neos",.FALSE.)) THEN
+                 elements = getElements(orb,"cometary")
+                 IF (elements(1) > 1.3_bp) THEN
+                    ! too large q -> skip it
+                    CYCLE
+                 END IF
+              END IF
+              CALL writeDESOrbitFile(lu_orb_out, first, &
+                   element_type_out_prm, id_arr_storb_in(i), orb, &
+                   HG_arr_storb_in(i,1,1))
+              first = .FALSE.
+              CALL NULLIFY(orb)
+           END IF
+        END DO
+        STOP
+     END IF
+     IF (ASSOCIATED(orb_arr_in)) THEN
+        DO i=1,SIZE(orb_arr_in)
+           IF (get_cl_option("--id-in=",.FALSE.)) THEN
+              j = binarySearch(id_arr_in(i),id_arr,errstr)
+              IF (j < 0 .OR. LEN_TRIM(errstr) /= 0) THEN
+                 CYCLE
+              END IF
+           END IF
+           IF (get_cl_option("--H-max=",.FALSE.)) THEN
+              IF (HG_arr_in(i,1) > H_max) THEN
+                 ! too large H magnitude -> skip it
+                 CYCLE
+              END IF
+           END IF
+           IF (get_cl_option("--only-neos",.FALSE.)) THEN
+              elements = getElements(orb_arr_in(i),"cometary")
+              IF (elements(1) > 1.3_bp) THEN
+                 ! too large q -> skip it
+                 CYCLE
+              END IF
+           END IF
+           CALL writeDESOrbitFile(lu_orb_out, first, element_type_out_prm, &
+                id_arr_in(i), orb_arr_in(i), HG_arr_in(i,1))
+           IF (error) THEN
+              CALL errorMessage("oorb", &
+                   "DES output failed at orbit:", 1)
+              WRITE(stderr,*) i
+              STOP
+           END IF
+           first = .FALSE.
+        END DO
+     END IF
+     IF (ASSOCIATED(id_arr)) THEN
+        DEALLOCATE(id_arr, stat=err)
+     END IF
+
+  CASE ("obs2des", "observationstodes")
+
+     ! Output input observations in DES format.
+
+     obs_fname = " "
+     obs_fname = get_cl_option("--obs-out=",obs_fname)
+     IF (LEN_TRIM(obs_fname) == 0) THEN
+        lu = stdout
+     ELSE
+        CALL NEW(obs_file,TRIM(obs_fname))
+        CALL OPEN(obs_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / tompc3", &
+                "TRACE BACK", 1)
+           STOP
+        END IF
+        lu = getUnit(obs_file)
+     END IF
+     CALL writeObservationFile(obss_in, lu, "des")
+     IF (LEN_TRIM(obs_fname) /= 0) THEN
+        CALL NULLIFY(obs_file)
+     END IF
+
+  CASE ("2mpc3", "tompc3")
+
+     ! Output input observations in new MPC format.
+
+     obs_fname = " "
+     obs_fname = get_cl_option("--obs-out=",obs_fname)
+     IF (LEN_TRIM(obs_fname) == 0) THEN
+        lu = stdout
+     ELSE
+        CALL NEW(obs_file,TRIM(obs_fname))
+        CALL OPEN(obs_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / tompc3", &
+                "TRACE BACK", 1)
+           STOP
+        END IF
+        lu = getUnit(obs_file)
+     END IF
+     CALL writeObservationFile(obss_in, lu, "mpc3")
+     IF (LEN_TRIM(obs_fname) /= 0) THEN
+        CALL NULLIFY(obs_file)
+     END IF
+
+  CASE ("2mpc", "tompc")
+
+     ! Output input observations in current MPC format.
+
+     obs_fname = " "
+     obs_fname = get_cl_option("--obs-out=",obs_fname)
+     IF (LEN_TRIM(obs_fname) == 0) THEN
+        lu = stdout
+     ELSE
+        CALL NEW(obs_file,TRIM(obs_fname))
+        CALL OPEN(obs_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / tompc", &
+                "TRACE BACK", 1)
+           STOP
+        END IF
+        lu = getUnit(obs_file)
+     END IF
+     CALL writeObservationFile(obss_in, lu, "mpc")
+     IF (LEN_TRIM(obs_fname) /= 0) THEN
+        CALL NULLIFY(obs_file)
+     END IF
+
+  CASE ("astorb")
+
+     ! Convert Ted's astorb file to the .orb format:
+
+     orb_in_fname = " "
+     orb_in_fname = get_cl_option("--astorb=",orb_in_fname)
+     IF (LEN_TRIM(orb_in_fname) == 0) THEN
+        CALL errorMessage("oorb / astorbtoorb", &
+             "ASTORB file not given.", 1)
+        STOP        
+     END IF
+     CALL NEW(orb_in_file, TRIM(orb_in_fname))
+     CALL setStatusOld(orb_in_file)
+     CALL OPEN(orb_in_file)
+     IF (error) THEN
+        CALL errorMessage("oorb / astorbtoorb", &
+             "TRACE BACK (5)", 1)
+        STOP        
+     END IF
+     norb = getNrOfLines(orb_in_file)
+     ! Format for astorb.dat:
+     frmt = '(A6,1X,A18,1X,A15,1X,F5.2,1X,F5.2,1X,A4,1X,A5,1X,A4,' // &
+          '1X,6I4,1X,2I5,1X,I4,2I2.2,3(1X,F10.6),F10.6,1X,F10.8,1X,' // &
+          'F12.8,1X,I4,2I2.2,1X,F7.2,1X,F8.2,1X,I4,2I2,' // &
+          '3(1X,F7.2,1X,I4,2I2))'
+     i = 0
+     iorb = 0
+     ALLOCATE(str_arr(6), real_arr(5), int_arr(23))
+     str_arr(1)(1:LEN(str_arr(1))) = " "
+     str_arr(2)(1:LEN(str_arr(2))) = " "
+     DO
+        line(:) = " "
+        str_arr(1)(1:6) = " "
+        str_arr(2)(1:18) = " "
+        iorb = iorb + 1
+        READ(getUnit(orb_in_file),"(A)",iostat=err) line
+        IF (err > 0) THEN
+           CALL errorMessage("oorb / astorbtoorb", &
+                'Error while reading line:',1)
+           WRITE(stderr,"(I0)") iorb
+           STOP
+        ELSE IF (err < 0) THEN
+           ! Input file read.
+           EXIT
+        END IF
+        READ(line,TRIM(frmt),iostat=err) &
+             str_arr(1)(1:6), str_arr(2)(1:18), str_arr(3)(1:15), &
+             H_value, G_value, str_arr(4)(1:4), str_arr(5)(1:5), &
+             str_arr(6)(1:4), int_arr(1:8), year, month, iday, &
+             elements(6:1:-1), int_arr(9:11), real_arr(1:2), &
+             int_arr(12:14), real_arr(3), int_arr(15:17), &
+             real_arr(4), int_arr(18:20), real_arr(5), int_arr(21:23)
+        IF (err > 0) THEN
+           CALL errorMessage("oorb / astorbtoorb", &
+                'Error while converting line:',1)
+           WRITE(stderr,"(I0)") iorb
+           STOP
+        END IF
+        READ(line(43:47),*,iostat=err) H_value
+        IF (err > 0) THEN
+           CALL errorMessage("oorb / astorbtoorb", &
+                'Error while converting H str to real on line:',1)
+           WRITE(stderr,"(I0)") iorb
+           STOP
+        END IF
+!!$        ! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+!!$        ! Discard some orbits depending on the following requirement:
+!!$        IF (int_arr(7) < 30 .OR. & ! orbital arc in days
+!!$                                !elements(1)*(1.0_bp-elements(2)) < 1.666_bp .OR. &
+!!$                                !elements(1) <= 2.0_bp .or. elements(1) >= 3.5_bp) then ! .or. &
+!!$             elements(1)*(1.0_bp-elements(2)) < 1.3_bp .OR. &
+!!$             elements(1) > 4.5_bp .OR. &
+!!$                                !elements(3) > 60.0_bp .OR. &
+!!$             H_value > 15.5_bp) then
+!!$             int_arr(9) >= 2008) THEN
+!!$           CYCLE
+!!$        END IF
+!!$        ! End requirement
+!!$        ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+        IF (LEN_TRIM(str_arr(2)) /= 0) THEN
+           !! 9-char alphanumeric encoded designation
+           !CALL encodeMPC3Designation(str_arr(2))
+           !! 7-char alphanumeric encoded designation (current MPC format)
+           CALL encodeMPCDesignation(str_arr(2))
+           IF (error) THEN
+              CALL errorMessage("oorb / astorbtoorb", &
+                   "TRACE BACK (10)",1)
+              STOP
+           END IF
+        END IF
+        DO j=1,6
+           IF (IACHAR(str_arr(1)(j:j)) == 0) THEN
+              str_arr(1)(j:j) = CHAR(32)
+           END IF
+        END DO
+        DO j=1,18
+           IF (IACHAR(str_arr(2)(j:j)) == 0) THEN
+              str_arr(2)(j:j) = CHAR(32)
+           END IF
+        END DO
+        i = i + 1
+        CALL NEW(epoch, year, month, REAL(iday,bp), "TT")
+        elements(3:6) = elements(3:6)*rad_deg
+        CALL NEW(orb, elements, "keplerian", "ecliptic", epoch)
+        IF (error) THEN
+           CALL errorMessage("oorb / astorbtoorb", &
+                "TRACE BACK (15)",1)
+           STOP
+        END IF
+        CALL NULLIFY(epoch)
+        id(1:LEN(id)) = " "
+        IF (LEN_TRIM(str_arr(1)) /= 0) THEN
+           id = TRIM(ADJUSTL(str_arr(1)))
+           !! 7-char numeric number
+           !DO WHILE (LEN_TRIM(id) < 7)
+           !   id = '0' // TRIM(id)
+           !END DO
+           !! 5-char alphanumeric number (current MPC format)
+           IF (LEN_TRIM(id) == 6) THEN
+              CALL toInt(id(1:2), i, error)
+              id(2:5) = id(3:6)
+              id(6:6) = " "
+              id(1:1) = mpc_conv_table(i)
+           ELSE IF (LEN_TRIM(id) > 6) THEN
+              CALL errorMessage("oorb / astorbtoorb", &
+                   "Number (" // TRIM(id) // ") too large -> cannot encode.",1)
+              STOP             
+           END IF
+           DO WHILE (LEN_TRIM(id) < 5)
+              id = '0' // TRIM(id)
+           END DO
+        ELSE
+           id = TRIM(ADJUSTL(str_arr(2)))
+        END IF
+        SELECT CASE (TRIM(orbit_format_out))
+        CASE ("des")
+           CALL writeDESOrbitFile(lu_orb_out, i==1, element_type_out_prm, &
+                id, orb, H_value, 1, 6, &
+                REAL(int_arr(7),bp), "OPENORB")
+        CASE ("orb")
+           CALL writeOpenOrbOrbitFile(lu_orb_out, print_header=i==1, &
+                element_type_out=element_type_out_prm, &
+                id=TRIM(id), orb=orb, H=H_value, G=G_value, &
+                mjd=mjd_epoch)
+        CASE default
+           CALL errorMessage("oorb / astorbtoorb", &
+                "Orbit format " // TRIM(orbit_format_out) // &
+                " not supported.",1)
+           STOP           
+        END SELECT
+        CALL NULLIFY(orb)
+     END DO
+     CALL NULLIFY(orb_in_file)
+
+  CASE ("mpcorb")
+
+     ! Convert MPC's MPCORB.DAT file to the .orb format:
+
+     orb_in_fname = " "
+     orb_in_fname = get_cl_option("--mpcorb=",orb_in_fname)
+     IF (LEN_TRIM(orb_in_fname) == 0) THEN
+        CALL errorMessage("oorb / mpcorbtoorb", &
+             "MPCORB file not given.", 1)
+        STOP        
+     END IF
+     CALL NEW(orb_in_file, TRIM(orb_in_fname))
+     CALL setStatusOld(orb_in_file)
+     CALL OPEN(orb_in_file)
+     IF (error) THEN
+        CALL errorMessage("oorb / mpcorbtoorb", &
+             "TRACE BACK (5)", 1)
+        STOP        
+     END IF
+     norb = getNrOfLines(orb_in_file)
+     DEALLOCATE(id_arr_in, orb_arr_in, HG_arr_in, arc_arr, stat=err)
+     ALLOCATE(id_arr_in(norb), orb_arr_in(norb), HG_arr_in(norb,2), arc_arr(norb))
+     CALL readMPCOrbitFile(getUnit(orb_in_file), norb, id_arr_in, orb_arr_in, HG_arr_in, arc_arr)
+     IF (error) THEN
+        CALL errorMessage("oorb / mpcorbtoorb", &
+             "TRACE BACK (10)", 1)
+        STOP        
+     END IF
+     CALL NULLIFY(orb_in_file)
+
+     DO i=1,norb
+!!$        elements = getElements(orb_arr_in(i), "keplerian")
+!!$        ! vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+!!$        ! Discard some orbits depending on the following requirement:
+!!$        IF (elements(1) < 2.1_bp .or. elements(1) > 3.3_bp .or. & 
+!!$             elements(2) > 0.35_bp .or. elements(3) > 26.0_bp*rad_deg) THEN ! not-MBO
+!!$        IF (.not.(elements(1)*(1.0_bp-elements(2)) <= 1.3_bp .and. &
+!!$             elements(1)*(1.0_bp-elements(2)) > 1.017_bp)) THEN ! not-Amor
+!!$        IF (.not.(elements(1)*(1.0_bp-elements(2)) <= 1.017_bp .and. &
+!!$             elements(1) > 1.0_bp)) THEN ! not-Apollo
+!!$        IF (.not.(elements(1)*(1.0_bp+elements(2)) > 0.983_bp .and. &
+!!$             elements(1) <= 1.0_bp)) THEN ! not-Aten
+!!$           CYCLE
+!!$        END IF
+!!$        ! End requirement
+!!$        ! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+        SELECT CASE (TRIM(orbit_format_out))
+        CASE ("des")
+           CALL writeDESOrbitFile(lu_orb_out, i==1, element_type_out_prm, &
+                id_arr_in(i), orb_arr_in(i), HG_arr_in(i,1), 1, 6, &
+                arc_arr(i), "OPENORB")
+        CASE ("orb")
+           CALL writeOpenOrbOrbitFile(lu_orb_out, print_header=i==1, &
+                element_type_out=element_type_out_prm, &
+                id=TRIM(id_arr_in(i)), orb=orb_arr_in(i), &
+                H=HG_arr_in(i,1), G=HG_arr_in(i,2), &
+                mjd=mjd_epoch)
+        CASE default
+           CALL errorMessage("oorb / mpcorbtoorb", &
+                "Orbit format " // TRIM(orbit_format_out) // &
+                " not supported.",1)
+           STOP           
+        END SELECT
+        IF (error) THEN
+           CALL errorMessage("oorb / mpcorbtoorb", &
+                "TRACE BACK (15)", 1)
+           STOP        
+        END IF
+     END DO
+
+  CASE ("2planetocentric")
+
+     ncenter = get_cl_option("--center=",-1)
+     IF (ncenter < 0 .OR. ncenter > 13) THEN
+        CALL errorMessage("oorb / planetocentricorbits", &
+             "New center must be given with the --center=CENTER option where 1 <= CENTER <= 13.", 1)
+        STOP
+     END IF
+
+     DO i=1,SIZE(orb_arr_in)
+        t = getTime(orb_arr_in(i))
+        mjd = getMJD(t, "TT")
+        ! Get Sun's coordinates at the epoch as seen from the planet:
+        planeph => JPL_ephemeris(mjd, 11, ncenter, error)
+        CALL NEW(ccoord, planeph(1,1:6), "equatorial", t)
+        DEALLOCATE(planeph)
+        CALL rotateToEcliptic(ccoord)
+        coordinates = getCoordinates(ccoord)
+        CALL NULLIFY(ccoord)
+        elements = getElements(orb_arr_in(i), "cartesian", "ecliptic")
+        ! New center -> asteroid = new_center -> Sun + Sun -> asteroid
+        CALL NEW(orb, coordinates + elements, "cartesian", "ecliptic", t, central_body=ncenter)
+        SELECT CASE (TRIM(orbit_format_out))
+        CASE ("des")
+           CALL writeDESOrbitFile(lu_orb_out, i==1, element_type_out_prm, &
+                id_arr_in(i), orb, HG_arr_in(i,1), 1, 6, &
+                -1.0_bp, "OPENORB")
+        CASE ("orb")
+           CALL writeOpenOrbOrbitFile(lu_orb_out, print_header=i==1, &
+                element_type_out=element_type_out_prm, &
+                id=TRIM(id_arr_in(i)), orb=orb, &
+                H=HG_arr_in(i,1), G=HG_arr_in(i,2), &
+                mjd=mjd_epoch)
+        CASE default
+           CALL errorMessage("oorb / planetocentricorbits", &
+                "Orbit format " // TRIM(orbit_format_out) // &
+                " not supported.",1)
+           STOP           
+        END SELECT
+        IF (error) THEN
+           CALL errorMessage("oorb / planetocentricorbits", &
+                "TRACE BACK (15)", 1)
+           STOP        
+        END IF
+        CALL NULLIFY(orb)        
+        CALL NULLIFY(t)
+     END DO
+
+
+  CASE ("obs2ecl")
+
+     ! Convert observed RA,Dec to topocentric ecliptic coordinates.
+
+     DO i=1,getNrOfObservations(obss_in)
+        obs = getObservation(obss_in,i)
+        ! Get number or designation
+        id = getID(obs)
+        ! Get observation date
+        t = getTime(obs)
+        mjd_utc = getMJD(t,"UTC")
+        CALL NULLIFY(t)
+        ! Get apparent magnitude
+        mag = getMagnitude(obs)
+        ! Compute topocentric opposition coordinates starting from the
+        ! heliocentric observatory coordinates.
+        ccoord = getObservatoryCCoord(obs)
+        scoord = getSCoord(ccoord)
+        CALL NULLIFY(ccoord)
+        CALL rotateToEcliptic(scoord)
+        pos_opp = getPosition(scoord)
+        CALL NULLIFY(scoord)
+        scoord = getObservationSCoord(obs)
+        CALL rotateToEcliptic(scoord)
+        pos_ast = getPosition(scoord)
+        CALL NULLIFY(scoord)
+        ! Compute opposition-centered topocentric ecliptic coordinates
+        toclon = pos_ast(2) - pos_opp(2)
+        toclat = pos_ast(3) - pos_opp(3)
+        IF (toclon > pi) THEN
+           toclon = toclon - two_pi
+        ELSE IF (toclon < -pi) THEN
+           toclon = toclon + two_pi
+        END IF
+        WRITE(stdout,"(A,1X,I0,1X,F7.5,2(1X,F12.7),1X,F6.2)") &
+             TRIM(id), FLOOR(mjd_utc), mjd_utc-FLOOR(mjd_utc), &
+             toclon/rad_deg, toclat/rad_deg, mag
+        CALL NULLIFY(obs)
+     END DO
+
+
+  CASE ("ranging")
+
+     ! Orbital inversion using statistical orbital ranging, that is,
+     ! without making any assumptions on the shape of the resulting
+     ! orbital-element pdf.
+
+     CALL NULLIFY(epoch)
+     apriori_a_max = -1.0_bp
+     apriori_a_min = -1.0_bp
+     apriori_periapsis_max = -1.0_bp
+     apriori_periapsis_min = -1.0_bp
+     apriori_apoapsis_max = -1.0_bp
+     apriori_apoapsis_min = -1.0_bp
+     apriori_rho_min = -1.0_bp
+     sor_type_prm = -1
+     sor_2point_method = " "
+     sor_2point_method_sw = " "
+     sor_norb = -1
+     sor_norb_sw = -1
+     sor_ntrial = -1
+     sor_ntrial_sw = -1
+     sor_niter = -1
+     sor_rho_init = HUGE(sor_rho_init)
+     generat_multiplier = -1.0_bp
+     sor_genwin_offset = -1.0_bp
+     sor_iterate_bounds = .TRUE.
+     accwin_multiplier = -1.0_bp
+     gaussian_rho = .FALSE.
+     regularized = .FALSE.
+     write_residuals = .FALSE.
+     chi2_min_init = -1.0_bp
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_periapsis_max=apriori_periapsis_max, &
+          apriori_periapsis_min=apriori_periapsis_min, &
+          apriori_apoapsis_max=apriori_apoapsis_max, &
+          apriori_apoapsis_min=apriori_apoapsis_min, &
+          apriori_rho_min=apriori_rho_min, &
+          sor_type=sor_type_prm, sor_2point_method=sor_2point_method, &
+          sor_2point_method_sw=sor_2point_method_sw, &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          generat_multiplier=generat_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          sor_iterate_bounds=sor_iterate_bounds, &
+          accwin_multiplier=accwin_multiplier, &
+          regularized_pdf=regularized, &
+          sor_random_obs=random_obs, sor_rho_gauss=gaussian_rho, &
+          write_residuals=write_residuals, &
+          chi2_min=chi2_min_init)
+     IF (error) THEN
+        CALL errorMessage("oorb / ranging", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / ranging", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DEALLOCATE(HG_arr_storb_in, stat=err)
+     ALLOCATE(HG_arr_storb_in(SIZE(obss_sep),sor_norb,4))
+     HG_arr_storb_in = 99.9_bp
+     DO i=1,SIZE(obss_sep)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / ranging", &
+                "TRACE BACK (25)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(2(1X,A))") "Object:", TRIM(id)
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / ranging", &
+                "TRACE BACK (27)", 1)
+           STOP
+        END IF
+        IF (sor_rho_init(3) > HUGE(sor_rho_init(3))/2) THEN
+           ! Initialize the rho2-rho1 range based on the observational timespan.
+           IF (dt > 10) THEN
+              sor_rho_init(3) = -0.5_bp
+           ELSE
+              sor_rho_init(3) = -0.05_bp*dt
+           END IF
+           sor_rho_init(4) = -sor_rho_init(3)
+        END IF
+        IF (ASSOCIATED(id_arr_storb_in) .AND. ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in)
+              IF (TRIM(id) == TRIM(id_arr_storb_in(j))) THEN
+                 EXIT
+              END IF
+           END DO
+           IF (j <= SIZE(id_arr_storb_in)) THEN
+              CALL setParameters(storb_arr_in(j), &
+                   dyn_model=dyn_model, &
+                   perturbers=perturbers, &
+                   integrator=integrator, &
+                   integration_step=integration_step, &
+                   accept_multiplier=accwin_multiplier, &
+                   apriori_rho_min=apriori_rho_min, &
+                   set_acceptance_window=.FALSE.)
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (30)", 1)
+                 STOP
+              END IF
+              CALL constrainRangeDistributions(storb_arr_in(j), obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (31)", 1)
+                 STOP
+              END IF
+              CALL setRangeBounds(storb_arr_in(j))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (32)", 1)
+                 STOP
+              END IF
+              sor_rho_init(1:4) = getRangeBounds(storb_arr_in(j))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (33)", 1)
+                 STOP
+              END IF
+              pdf_arr_in => getPDFValues(storb_arr_in(j))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (34)", 1)
+                 STOP
+              END IF
+              DEALLOCATE(pdf_arr_in)
+           END IF
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (35)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (40)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL NEW(storb, obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / ranging", &
+                "TRACE BACK (55)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             regularized_pdf = regularized, &
+             dchi2_rejection = dchi2_rejection, &
+             dchi2_max = dchi2_max, &
+             chi2_min=chi2_min_init, &
+             accept_multiplier=accwin_multiplier, &
+             apriori_a_max=apriori_a_max, apriori_a_min=apriori_a_min, &
+             apriori_periapsis_max=apriori_periapsis_max, &
+             apriori_periapsis_min=apriori_periapsis_min, &
+             apriori_apoapsis_max=apriori_apoapsis_max, &
+             apriori_apoapsis_min=apriori_apoapsis_min, &
+             apriori_rho_min=apriori_rho_min, &
+             sor_2point_method=sor_2point_method, &
+             sor_2point_method_sw=sor_2point_method_sw, &
+             sor_norb=sor_norb, sor_ntrial=sor_ntrial, &
+             sor_rho1_l=sor_rho_init(1), sor_rho1_u=sor_rho_init(2), &
+             sor_rho2_l=sor_rho_init(3), sor_rho2_u=sor_rho_init(4), &
+             sor_iterate_bounds=sor_iterate_bounds, &
+             sor_random_obs_selection=.FALSE., &
+             gaussian_pdf=gaussian_rho, &
+             generat_multiplier=generat_multiplier, &
+             sor_generat_offset=sor_genwin_offset)
+        IF (error) THEN
+           CALL errorMessage("oorb / ranging", &
+                "TRACE BACK (60)", 1)
+           STOP
+        END IF
+
+        SELECT CASE (sor_type_prm)
+        CASE (1)
+           CALL statisticalRanging(storb)
+        CASE (2)
+           CALL setParameters(storb, &
+                sor_niter=sor_niter)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (85)", 1)
+              STOP
+           END IF
+           CALL autoStatisticalRanging(storb)
+        CASE (3)
+           CALL setParameters(storb, &
+                sor_norb_sw=sor_norb_sw, &
+                sor_ntrial_sw=sor_ntrial_sw, &
+                sor_niter=sor_niter)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (90)", 1)
+              STOP
+           END IF
+           CALL stepwiseRanging(storb, nobs_max=-1)
+        CASE default
+           CALL errorMessage("oorb / ranging", &
+                "Unknown type of ranging:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(2X,I0)") sor_type_prm
+           END IF
+           STOP              
+        END SELECT
+
+        IF (error) THEN
+           CALL errorMessage("oorb / ranging", &
+                "TRACE BACK (115)", 1)
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (135)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           CALL NULLIFY(storb)
+        ELSE
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Ranging for object", &
+                   TRIM(id), "is ready."
+           END IF
+
+           IF (pp_H_estimation) THEN
+              CALL NEW(physparam, storb)
+              IF (pp_G > 99.0_bp) THEN
+                 CALL estimateHAndG(physparam, obss_sep(i))
+              ELSE
+                 CALL estimateHAndG(physparam, obss_sep(i), &
+                      input_G=pp_G, input_delta_G=pp_G_unc)
+              END IF
+              HG_arr_in => getH0Distribution(physparam)
+              ALLOCATE(temp_arr(SIZE(HG_arr_in,dim=1),4))
+              temp_arr(:,1:2) = HG_arr_in(:,1:2)
+              DEALLOCATE(HG_arr_in)
+              HG_arr_in => getGDistribution(physparam)
+              temp_arr(:,3:4) = HG_arr_in(:,1:2)
+              DEALLOCATE(HG_arr_in)
+              HG_arr_storb_in(i,:,:) = temp_arr
+              DEALLOCATE(temp_arr)              
+              CALL NULLIFY(physparam)
+           END IF
+
+           CALL NEW(out_file, TRIM(id) // ".sor")
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (150)", 1)
+              STOP
+           END IF
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (155)", 1)
+              STOP
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#" 
+           ! WRITE RANGING PARAMETERS
+           CALL writeSORResults(storb, obss_sep(i), getUnit(out_file))
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (160)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file) 
+           CALL getResults(storb, sor_rho_cmp=sor_rho_cmp)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "TRACE BACK (170)", 1)
+              STOP
+           END IF
+           ! WRITE ORBITAL-ELEMENT PDF
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging ", &
+                   "TRACE BACK (175)", 1)
+              STOP
+           END IF
+           pdf_arr_cmp => getPDFValues(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging ", &
+                   "TRACE BACK (180)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging ", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           CALL getResults(storb, &
+                reg_apr_arr=reg_apr_arr_cmp, &
+                jac_arr=jac_arr_cmp)
+           IF (error) THEN
+              CALL errorMessage("oorb / ranging ", &
+                   "TRACE BACK (190)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           DO j=1,SIZE(orb_arr_cmp,dim=1)
+              IF (orbit_format_out == "orb") THEN
+                 IF (ASSOCIATED(HG_arr_storb_in)) THEN
+                    CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                         print_header=j==1, &
+                         element_type_out=element_type_out_prm, &
+                         id=id, &
+                         orb=orb_arr_cmp(j), &
+                         element_type_pdf=element_type_comp_prm, &
+                         pdf=pdf_arr_cmp(j), &
+                         rchi2=rchi2_arr_cmp(j), &
+                         reg_apr=reg_apr_arr_cmp(j), &
+                         jac_sph_inv=jac_arr_cmp(j,1), &
+                         jac_car_kep=jac_arr_cmp(j,2), &
+                         jac_equ_kep=jac_arr_cmp(j,3), &
+                         H=HG_arr_storb_in(i,j,1), &
+                         G=HG_arr_storb_in(i,j,3), &
+                         mjd=mjd_epoch)
+                 ELSE
+                    CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                         print_header=j==1, &
+                         element_type_out=element_type_out_prm, &
+                         id=id, &
+                         orb=orb_arr_cmp(j), &
+                         element_type_pdf=element_type_comp_prm, &
+                         pdf=pdf_arr_cmp(j), &
+                         rchi2=rchi2_arr_cmp(j), &
+                         reg_apr=reg_apr_arr_cmp(j), &
+                         jac_sph_inv=jac_arr_cmp(j,1), &
+                         jac_car_kep=jac_arr_cmp(j,2), &
+                         jac_equ_kep=jac_arr_cmp(j,3), &
+                         mjd=mjd_epoch)
+                 END IF
+              ELSE IF (orbit_format_out == "des") THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "DES format not yet supported for Ranging output.", 1)
+                 STOP                 
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+           END DO
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           ! WRITE RESIDUALS
+           IF (write_residuals) THEN
+              CALL NEW(out_file, TRIM(out_fname) // ".res")
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (225)", 1)
+                 STOP
+              END IF
+              CALL writeResiduals(storb, obss_sep(i), getUnit(out_file))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (230)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+           END IF
+           IF (plot_results) THEN
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "TRACE BACK (235)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                   "_sor_residual_stamps.eps")
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "TRACE BACK (240)", 1)
+                 STOP
+              END IF
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_sor_residual_stamps.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_sor_residual_stamps.eps* &")
+              END IF
+              ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "Could not allocate memory (3).", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// "_sor_orbits.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "TRACE BACK (250)", 1)
+                 STOP
+              END IF
+              DO j=1,SIZE(orb_arr_cmp,dim=1)
+                 IF (element_type_comp_prm == "cartesian") THEN
+                    CALL rotateToEcliptic(orb_arr_cmp(j))
+                 END IF
+                 elements_arr(j,1:6) = getElements(orb_arr_cmp(j), element_type_comp_prm)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / ranging", &
+                         "TRACE BACK (255)", 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    elements_arr(j,3:6) = elements_arr(j,3:6)/rad_deg
+                 END IF
+                 elements_arr(j,7) = pdf_arr_cmp(j)
+                 t = getTime(orb_arr_cmp(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / ranging ", &
+                         "TRACE BACK (260)", 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file),"(7(E23.15,1X),A)") &
+                      elements_arr(j,1:6), &
+                      pdf_arr_cmp(j), &
+                      getCalendarDateString(t,"tdt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / ranging ", &
+                         "TRACE BACK (265)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(t)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NEW(tmp_file, TRIM(str) // &
+                   "_sor_sample_standard_deviations.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "TRACE BACK (275)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                   advance="no") &
+                   getObservationalTimespan(obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / ranging ", &
+                      "TRACE BACK (280)", 1)
+                 STOP
+              END IF
+              DO j=1,6
+                 CALL moments(elements_arr(:,j), &
+                      pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+                 IF (LEN_TRIM(errstr) /= 0) THEN
+                    CALL errorMessage("oorb / ranging", &
+                         "Could not compute moments. " // TRIM(errstr), 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                      advance="no") stdev
+              END DO
+              WRITE(getUnit(tmp_file),*)
+              CALL NULLIFY(tmp_file)
+              DEALLOCATE(elements_arr, stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / ranging", &
+                      "Could not deallocate memory (5).", 1)
+                 STOP
+              END IF
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_sor_orbits.out sor_orbits.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_car.gp")
+              ELSE
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_kep.gp")
+              END IF
+              CALL system("cp sor_results.eps " // TRIM(str) // &
+                   "_sor_" // TRIM(element_type_comp_prm) // &
+                   "_results.eps")
+              CALL system("rm -f sor_orbits.out sor_results.eps " // & 
+                   TRIM(str) // "_sor_orbits.out " // TRIM(str) // &
+                   "_sor_sample_standard_deviations.out")
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_sor_" // &
+                      TRIM(element_type_comp_prm) // "_results.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_sor_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.eps* &")
+              END IF
+           END IF
+           DO j=1,SIZE(orb_arr_cmp)
+              CALL NULLIFY(orb_arr_cmp(j))
+           END DO
+           DEALLOCATE(orb_arr_cmp, stat=err)
+           DEALLOCATE(pdf_arr_cmp, stat=err)
+           DEALLOCATE(rchi2_arr_cmp, stat=err)
+           DEALLOCATE(reg_apr_arr_cmp, stat=err)
+           DEALLOCATE(jac_arr_cmp, stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / ranging", &
+                   "Could not deallocate memory (10).", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obss_sep(i))
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        IF (ASSOCIATED(HG_arr_in)) THEN
+           DEALLOCATE(HG_arr_in, stat=err)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / ranging", &
+             "Could not deallocate memory (15).", 1)
+        STOP
+     END IF
+
+
+
+  CASE ("mcmcranging")
+
+     ! Orbital inversion using MCMC ranging, that is, without making
+     ! any assumptions on the shape of the resulting orbital-element
+     ! pdf.
+
+     CALL NULLIFY(epoch)
+     dyn_model = " "
+     integrator = " "
+     integration_step = -1.0_bp
+     apriori_a_max = -1.0_bp
+     apriori_a_min = -1.0_bp
+     apriori_periapsis_max = -1.0_bp
+     apriori_periapsis_min = -1.0_bp
+     apriori_apoapsis_max = -1.0_bp
+     apriori_apoapsis_min = -1.0_bp
+     apriori_rho_min = -1.0_bp
+     sor_type_prm = -1
+     sor_2point_method = " "
+     sor_2point_method_sw = " "
+     sor_norb = -1
+     sor_norb_sw = -1
+     sor_ntrial = -1
+     sor_ntrial_sw = -1
+     sor_niter = -1
+     sor_rho_init = HUGE(sor_rho_init)
+     generat_multiplier = -1.0_bp
+     sor_genwin_offset = -1.0_bp
+     sor_iterate_bounds = .TRUE.
+     accwin_multiplier = -1.0_bp
+     gaussian_rho = .FALSE.
+     regularized = .FALSE.
+     write_residuals = .FALSE.
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model=dyn_model, &
+          perturbers=perturbers, &
+          integrator=integrator, &
+          integration_step=integration_step, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_periapsis_max=apriori_periapsis_max, &
+          apriori_periapsis_min=apriori_periapsis_min, &
+          apriori_apoapsis_max=apriori_apoapsis_max, &
+          apriori_apoapsis_min=apriori_apoapsis_min, &
+          apriori_rho_min=apriori_rho_min, &
+          sor_type=sor_type_prm, sor_2point_method=sor_2point_method, &
+          sor_2point_method_sw=sor_2point_method_sw, &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          generat_multiplier=generat_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          sor_iterate_bounds=sor_iterate_bounds, &
+          accwin_multiplier=accwin_multiplier, &
+          regularized_pdf=regularized, &
+          sor_random_obs=random_obs, sor_rho_gauss=gaussian_rho, &
+          write_residuals=write_residuals, &
+          ls_correction_factor=ls_correction_factor, &
+          ls_element_mask=ls_element_mask, &
+          ls_niter_major_max=ls_niter_major_max, &
+          ls_niter_major_min=ls_niter_major_min, &
+          ls_niter_minor=ls_niter_minor)
+     IF (error) THEN
+        CALL errorMessage("oorb / mcmcranging", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / mcmcranging", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     ! Print header before printing first orbit:
+     first = .TRUE.
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (15)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")."
+        END IF
+        nobs = getNrOfObservations(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (20)", 1)
+           STOP
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (55)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (60)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        iorb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 iorb = j
+                 EXIT
+              END IF
+           END DO
+           IF (iorb == 0) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+           orb_arr => getSampleOrbits(storb_arr_in(iorb))
+           orb = copy(orb_arr(1))
+           DEALLOCATE(orb_arr)
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 iorb = j
+                 EXIT
+              END IF
+           END DO
+           IF (iorb == 0) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+           orb = copy(orb_arr_in(iorb))
+        END IF
+        CALL setParameters(orb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step)
+        ! Propagate initial orbit to inversion epoch
+        CALL propagate(orb, t)
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (65)", 1)
+           STOP
+        END IF
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (65)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             dchi2_rejection = dchi2_rejection, &
+             dchi2_max = dchi2_max, &
+             regularized_pdf = regularized, &
+             accept_multiplier=accwin_multiplier, &
+             apriori_a_max=apriori_a_max, apriori_a_min=apriori_a_min, &
+             apriori_periapsis_max=apriori_periapsis_max, &
+             apriori_periapsis_min=apriori_periapsis_min, &
+             apriori_apoapsis_max=apriori_apoapsis_max, &
+             apriori_apoapsis_min=apriori_apoapsis_min, &
+             apriori_rho_min=apriori_rho_min, &
+             sor_2point_method=sor_2point_method, &
+             sor_2point_method_sw=sor_2point_method_sw, &
+             sor_norb=sor_norb, sor_ntrial=sor_ntrial, &
+             sor_iterate_bounds=sor_iterate_bounds, &
+             sor_random_obs_selection=.FALSE., &
+             gaussian_pdf=gaussian_rho, &
+             generat_multiplier=generat_multiplier, &
+             sor_generat_offset=sor_genwin_offset)
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "TRACE BACK (70)", 1)
+           STOP
+        END IF
+        CALL MCMCRanging(storb, orb)
+        IF (error) THEN
+           CALL errorMessage("oorb / mcmcranging", &
+                "MCMC failed:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(3A,1X,I0)") "ID: ", TRIM(id), &
+                   " and number of observations: ", nobs
+           END IF
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (90)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (95)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "TRACE BACK (100)", 1)
+              STOP
+           END IF
+        ELSE
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Mcmc inversion for object", &
+                   TRIM(id), "is ready."
+           END IF
+!!$           CALL NEW(out_file, TRIM(id) // ".sor")
+!!$           CALL OPEN(out_file)
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / mcmcranging", &
+!!$                   "TRACE BACK (105)", 1)
+!!$              STOP
+!!$           END IF
+!!$           ! WRITE OBSERVATIONS:
+!!$           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+!!$                TRIM(observation_format_out)) 
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / mcmcranging", &
+!!$                   "TRACE BACK (110)", 1)
+!!$              STOP
+!!$           END IF
+!!$           WRITE(getUnit(out_file),"(A)") "#" 
+!!$           ! WRITE MCMC PARAMETERS
+!!$           CALL writeSORResults(storb, obss_sep(i), getUnit(out_file))
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / mcmcranging", &
+!!$                   "TRACE BACK (115)", 1)
+!!$              STOP
+!!$           END IF
+!!$           CALL NULLIFY(out_file) 
+           ! WRITE ORBITAL-ELEMENT PDF
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging ", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+           pdf_arr_cmp => getPDFValues(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging ", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / mcmcranging ", &
+                   "TRACE BACK (135)", 1)
+              STOP
+           END IF
+!!$           CALL getResults(storb, &
+!!$                reg_apr_arr=reg_apr_arr_cmp, &
+!!$                jac_arr=jac_arr_cmp)
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / mcmcranging ", &
+!!$                   "TRACE BACK (140)", 1)
+!!$              STOP
+!!$           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "TRACE BACK (145)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           DO j=1,SIZE(orb_arr_cmp,dim=1)
+              IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=j==1, &
+                      element_type_out=element_type_out_prm, &
+                      id=id, &
+                      orb=orb_arr_cmp(j), &
+                      element_type_pdf=element_type_comp_prm, &
+                      pdf=pdf_arr_cmp(j), &
+                      rchi2=rchi2_arr_cmp(j))
+!!$                   reg_apr=reg_apr_arr_cmp(j), &
+!!$                   jac_sph_inv=jac_arr_cmp(j,1), &
+!!$                   jac_car_kep=jac_arr_cmp(j,2), &
+!!$                   jac_equ_kep=jac_arr_cmp(j,3))
+              ELSE IF (orbit_format_out == "des") THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "DES format not yet supported for MCMC output.", 1)
+                 STOP                 
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging ", &
+                      "TRACE BACK (150)", 1)
+                 STOP
+              END IF
+           END DO
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           ! WRITE RESIDUALS
+           IF (write_residuals) THEN
+              CALL NEW(out_file, TRIM(out_fname) // ".res")
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "TRACE BACK (155)", 1)
+                 STOP
+              END IF
+              CALL writeResiduals(storb, obss_sep(i), getUnit(out_file))
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "TRACE BACK (160)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+           END IF
+           IF (plot_results) THEN
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging ", &
+                      "TRACE BACK (165)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                   "_mcmcranging_residual_stamps.eps")
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "TRACE BACK (170)", 1)
+                 STOP
+              END IF
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_mcmcranging_residual_stamps.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_mcmcranging_residual_stamps.eps* &")
+              END IF
+              ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "Could not allocate memory (3).", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// "_mcmcranging_orbits.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging ", &
+                      "TRACE BACK (175)", 1)
+                 STOP
+              END IF
+              DO j=1,SIZE(orb_arr_cmp,dim=1)
+                 IF (element_type_comp_prm == "cartesian") THEN
+                    CALL rotateToEcliptic(orb_arr_cmp(j))
+                 END IF
+                 elements_arr(j,1:6) = getElements(orb_arr_cmp(j), element_type_comp_prm)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / mcmcranging", &
+                         "TRACE BACK (180)", 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    elements_arr(j,3:6) = elements_arr(j,3:6)/rad_deg
+                 END IF
+                 elements_arr(j,7) = pdf_arr_cmp(j)
+                 t = getTime(orb_arr_cmp(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / mcmcranging ", &
+                         "TRACE BACK (185)", 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file),*) &
+                      elements_arr(j,1:6), &
+                      pdf_arr_cmp(j), &
+                      getCalendarDateString(t,"tdt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / mcmcranging ", &
+                         "TRACE BACK (190)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(t)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NEW(tmp_file, TRIM(str) // &
+                   "_mcmcranging_sample_standard_deviations.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging ", &
+                      "TRACE BACK (195)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                   advance="no") &
+                   getObservationalTimespan(obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / mcmcranging ", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              DO j=1,6
+                 CALL moments(elements_arr(:,j), &
+                      pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                      advance="no") stdev
+              END DO
+              WRITE(getUnit(tmp_file),*)
+              CALL NULLIFY(tmp_file)
+              DEALLOCATE(elements_arr, stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / mcmcranging", &
+                      "Could not deallocate memory (5).", 1)
+                 STOP
+              END IF
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_mcmcranging_orbits.out sor_orbits.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_car.gp")
+              ELSE
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_kep.gp")
+              END IF
+              CALL system("cp sor_results.eps " // TRIM(str) // &
+                   "_mcmcranging_" // TRIM(element_type_comp_prm) // &
+                   "_results.eps")
+              CALL system("rm -f sor_orbits.out sor_results.eps " // & 
+                   TRIM(str) // "_mcmcranging_orbits.out " // TRIM(str) // &
+                   "_sor_sample_standard_deviations.out")
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_mcmcranging_" // &
+                      TRIM(element_type_comp_prm) // "_results.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_mcmcranging_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.eps* &")
+              END IF
+           END IF
+           DO j=1,SIZE(orb_arr_cmp)
+              CALL NULLIFY(orb_arr_cmp(j))
+           END DO
+           DEALLOCATE(orb_arr_cmp, stat=err)
+           DEALLOCATE(pdf_arr_cmp, stat=err)
+           DEALLOCATE(rchi2_arr_cmp, stat=err)
+!!$           DEALLOCATE(reg_apr_arr_cmp, stat=err)
+!!$           DEALLOCATE(jac_arr_cmp, stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / mcmcranging", &
+                   "Could not deallocate memory (10).", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obss_sep(i))
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / mcmcranging", &
+             "Could not deallocate memory (15)", 1)
+        STOP
+     END IF
+
+
+
+  CASE ("simplex")
+
+     ! Orbit optimization using the downhill simplex method.
+
+     ALLOCATE(orb_arr_(7))
+
+     CALL NULLIFY(epoch)
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          accwin_multiplier=accwin_multiplier, &
+          smplx_niter=smplx_niter, &
+          smplx_tol=smplx_tol)
+     IF (error) THEN
+        CALL errorMessage("oorb / simplex", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / simplex", &
+             "TRACE BACK (20)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DEALLOCATE(HG_arr_storb_in, stat=err)
+     ALLOCATE(HG_arr_storb_in(SIZE(obss_sep),7,4))
+     HG_arr_storb_in = 99.9_bp
+
+     ! Print header before printing first orbit:
+     first = .TRUE.
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "TRACE BACK (25)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")."
+        END IF
+        nobs = getNrOfObservations(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        IF (nobs < 4) THEN
+           CALL errorMessage("oorb / simplex", &
+                "Too few observations:", 1)
+           WRITE(stderr,*) "ID: ", TRIM(id), "  and number of observations: ", nobs
+           CYCLE
+        END IF
+        norb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    orb_arr => getSampleOrbits(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / simplex", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = SIZE(orb_arr)
+                    EXIT
+                 ELSE
+                    ALLOCATE(orb_arr(1))
+                    orb_arr(1) = getNominalOrbit(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / simplex", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = 1
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 norb = norb + 1
+                 IF (.NOT.ASSOCIATED(orb_arr)) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 ELSE IF (SIZE(orb_arr) < norb) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 END IF
+                 orb_arr(norb) = copy(orb_arr_in(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / simplex", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "Initial orbit not available.", 1)
+              STOP
+           ELSE
+              orb_arr => reallocate(orb_arr,norb)
+           END IF
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "TRACE BACK (75)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             accept_multiplier=accwin_multiplier, &
+             smplx_niter=smplx_niter, &
+             smplx_tol=smplx_tol)
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "TRACE BACK (80)", 1)
+           STOP
+        END IF
+        DO j=1,SIZE(orb_arr,dim=1),7
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(A,1X,I0,1X))") "Orbits", j, "to", &
+                   j+6, "out of", SIZE(orb_arr,dim=1)
+           END IF
+           DO k=1,7
+              CALL NULLIFY(orb_arr_(k))
+              orb_arr_(k) = copy(orb_arr(j+k-1))
+              CALL setParameters(orb_arr_(k), &
+                   dyn_model=dyn_model_init, &
+                   perturbers=perturbers, &
+                   integrator=integrator_init, &
+                   integration_step=integration_step_init)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (85)", 1)
+                 STOP
+              END IF
+              CALL propagate(orb_arr_(k), t)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (90)", 1)
+                 STOP
+              END IF
+              CALL setParameters(orb_arr_(k), &
+                   dyn_model=dyn_model, &
+                   perturbers=perturbers, &
+                   integrator=integrator, &
+                   integration_step=integration_step)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (95)", 1)
+                 STOP
+              END IF
+           END DO
+           CALL simplexOrbits(storb, orb_arr_)
+           IF (.NOT.error) THEN
+              EXIT
+           ELSE IF (j + 13 < norb) THEN
+              error = .FALSE.
+           ELSE
+              EXIT
+           END IF
+        END DO
+        IF (error) THEN
+           CALL errorMessage("oorb / simplex", &
+                "Simplex failed:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(3A,1X,I0)") "ID: ", TRIM(id), &
+                   " and number of observations: ", nobs
+           END IF
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+        ELSE
+           obs_masks => getObservationMasks(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           noutlier = 0
+           DO j=1,SIZE(obs_masks,dim=1)
+              IF (ALL(.NOT.obs_masks(j,:))) THEN
+                 noutlier = noutlier + 1
+              END IF
+           END DO
+           IF (noutlier > SIZE(obs_masks,dim=1)/5) THEN
+              ! In case of too many outliers (>20% of obs), throw the
+              ! observation set in a separate bin:
+              CALL NEW(out_file, "observation_sets_with_many_outliers." // TRIM(observation_format_out))
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (145)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(out_file),"(1X)")
+              WRITE(getUnit(out_file),"(A,I0,A)",advance="no") "# ", &
+                   noutlier, " outliers: "
+              DO j=1,SIZE(obs_masks,dim=1)
+                 IF (ALL(.NOT.obs_masks(j,:))) THEN
+                    WRITE(getUnit(out_file),"(A)",advance="no") "*"
+                 ELSE
+                    WRITE(getUnit(out_file),"(A)",advance="no") "-"
+                 END IF
+              END DO
+              WRITE(getUnit(out_file),"(1X)")
+              CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (150)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (155)", 1)
+                 STOP
+              END IF
+              CYCLE
+           END IF
+           DEALLOCATE(obs_masks, stat=err)
+
+           IF (pp_H_estimation) THEN
+              CALL NEW(physparam, storb)
+              IF (pp_G > 99.0_bp) THEN
+                 CALL estimateHAndG(physparam, obss_sep(i))
+              ELSE
+                 CALL estimateHAndG(physparam, obss_sep(i), &
+                      input_G=pp_G, input_delta_G=pp_G_unc)
+              END IF
+              HG_arr_in => getH0Distribution(physparam)
+              HG_arr_storb_in(i,:,1:2) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              HG_arr_in => getGDistribution(physparam)
+              HG_arr_storb_in(i,:,3:4) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              CALL NULLIFY(physparam)
+           END IF
+
+           CALL NEW(out_file, TRIM(out_fname) // ".smplx")
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (160)", 1)
+              STOP
+           END IF
+           CALL setPositionAppend(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (165)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (170)", 1)
+              STOP
+           END IF
+
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex", &
+                   "TRACE BACK (175)", 1)
+              WRITE(getUnit(out_file),"(A)") &
+                   "Could not write observations for object " // TRIM(id) 
+              error = .FALSE.
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#"
+
+           CALL NULLIFY(out_file)
+
+           ! WRITE ORBITS
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex ", &
+                   "TRACE BACK (175)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / simplex ", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           DO j=1,SIZE(orb_arr_cmp,dim=1)
+              IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=j==1, &
+                      element_type_out=element_type_out_prm, &
+                      id=id, &
+                      orb=orb_arr_cmp(j), &
+                      rchi2=rchi2_arr_cmp(j), &
+                      H=HG_arr_storb_in(i,j,1), &
+                      G=HG_arr_storb_in(i,j,3), &
+                      mjd=mjd_epoch)
+              ELSE IF (orbit_format_out == "des") THEN
+                 CALL errorMessage("oorb / simplex ", &
+                      "DES format not yet supported for Simplex output.", 1)
+                 STOP                 
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex ", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+           END DO
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           ! WRITE RESIDUALS
+           IF (write_residuals) THEN
+              CALL NEW(out_file, TRIM(out_fname) // ".res")
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (225)", 1)
+                 STOP
+              END IF
+              CALL writeResiduals(storb, obss_sep(i), getUnit(out_file), compute=.TRUE.)
+              IF (error) THEN
+                 CALL errorMessage("oorb / simplex", &
+                      "TRACE BACK (230)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+           END IF
+
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+        END IF
+        DEALLOCATE(orb_arr, stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / simplex", &
+                "Could not deallocate memory (10)", 1)
+           STOP
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, orb_arr_, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / simplex", &
+             "Could not deallocate memory (15)", 1)
+        STOP
+     END IF
+
+
+
+
+  CASE ("observation_sampling")
+
+     ! Orbit inversion using a combination of MCMC sampling in
+     ! observation space and optimization by simplex
+
+     ALLOCATE(orb_arr_(7))
+
+     accwin_multiplier = -1.0_bp
+     chi2_min_init = -1.0_bp
+     CALL NULLIFY(epoch)
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          generat_multiplier=generat_multiplier, &
+          generat_gaussian_deviates=generat_gaussian_deviates, &
+          accwin_multiplier=accwin_multiplier, &
+          smplx_niter=smplx_niter, &
+          smplx_similarity_tol=smplx_similarity_tol, &
+          os_norb=os_norb, &
+          os_ntrial=os_ntrial, &
+          os_sampling_type=os_sampling_type, &
+          chi2_min=chi2_min_init)
+     IF (error) THEN
+        CALL errorMessage("oorb / observation_sampling", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / observation_sampling", &
+             "TRACE BACK (20)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DEALLOCATE(HG_arr_storb_in, stat=err)
+     ALLOCATE(HG_arr_storb_in(SIZE(obss_sep),os_norb,4))
+     HG_arr_storb_in = 99.9_bp
+     ! Print header before printing first orbit:
+     first = .TRUE.
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "TRACE BACK (25)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")."
+        END IF
+        nobs = getNrOfObservations(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        norb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    orb_arr => getSampleOrbits(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / observation_sampling", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = SIZE(orb_arr)
+                    EXIT
+                 ELSE
+                    ALLOCATE(orb_arr(1))
+                    orb_arr(1) = getNominalOrbit(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / observation_sampling", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = 1
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 norb = norb + 1
+                 IF (.NOT.ASSOCIATED(orb_arr)) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 ELSE IF (SIZE(orb_arr) < norb) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 END IF
+                 orb_arr(norb) = copy(orb_arr_in(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / observation_sampling", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "Initial orbit not available.", 1)
+              STOP
+           ELSE
+              orb_arr => reallocate(orb_arr,norb)
+           END IF
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "TRACE BACK (75)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             dchi2_rejection = dchi2_rejection, &
+             dchi2_max = dchi2_max, &
+             chi2_min=chi2_min_init, &
+             generat_multiplier=generat_multiplier, &
+             generat_gaussian_deviates=generat_gaussian_deviates, &
+             accept_multiplier=accwin_multiplier, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             smplx_niter=smplx_niter, &
+             smplx_force=.FALSE., &
+             smplx_similarity_tol=smplx_similarity_tol, &
+             os_norb=os_norb, &
+             os_ntrial=os_ntrial, &
+             os_sampling_type=os_sampling_type)
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "TRACE BACK (80)", 1)
+           STOP
+        END IF
+        DO k=1,SIZE(orb_arr)
+           CALL setParameters(orb_arr(k), &
+                dyn_model=dyn_model_init, &
+                perturbers=perturbers, &
+                integrator=integrator_init, &
+                integration_step=integration_step_init)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (85)", 1)
+              STOP
+           END IF
+           CALL propagate(orb_arr(k), t)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (90)", 1)
+              STOP
+           END IF
+           CALL setParameters(orb_arr(k), &
+                dyn_model=dyn_model, &
+                perturbers=perturbers, &
+                integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (95)", 1)
+              STOP
+           END IF
+        END DO
+        CALL observationSampling(storb, orb_arr)
+        IF (error) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "Observation_sampling failed:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(3A,1X,I0)") "ID: ", TRIM(id), &
+                   " and number of observations: ", nobs
+           END IF
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+        ELSE
+           obs_masks => getObservationMasks(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           noutlier = 0
+           DO j=1,SIZE(obs_masks,dim=1)
+              IF (ALL(.NOT.obs_masks(j,:))) THEN
+                 noutlier = noutlier + 1
+              END IF
+           END DO
+           IF (noutlier > SIZE(obs_masks,dim=1)/5) THEN
+              ! In case of too many outliers (>20% of obs), throw the
+              ! observation set in a separate bin:
+              CALL NEW(out_file, "observation_sets_with_many_outliers." // TRIM(observation_format_out))
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (145)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(out_file),"(1X)")
+              WRITE(getUnit(out_file),"(A,I0,A)",advance="no") "# ", &
+                   noutlier, " outliers: "
+              DO j=1,SIZE(obs_masks,dim=1)
+                 IF (ALL(.NOT.obs_masks(j,:))) THEN
+                    WRITE(getUnit(out_file),"(A)",advance="no") "*"
+                 ELSE
+                    WRITE(getUnit(out_file),"(A)",advance="no") "-"
+                 END IF
+              END DO
+              WRITE(getUnit(out_file),"(1X)")
+              CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (150)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (155)", 1)
+                 STOP
+              END IF
+              CYCLE
+           END IF
+           DEALLOCATE(obs_masks, stat=err)
+
+           IF (pp_H_estimation) THEN
+              CALL NEW(physparam, storb)
+              IF (pp_G > 99.0_bp) THEN
+                 CALL estimateHAndG(physparam, obss_sep(i))
+              ELSE
+                 CALL estimateHAndG(physparam, obss_sep(i), &
+                      input_G=pp_G, input_delta_G=pp_G_unc)
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (156)", 1)
+                 STOP
+              END IF
+              HG_arr_in => getH0Distribution(physparam)
+              HG_arr_storb_in(i,:,1:2) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              HG_arr_in => getGDistribution(physparam)
+              HG_arr_storb_in(i,:,3:4) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (157)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(physparam)
+           END IF
+
+           CALL NEW(out_file, TRIM(out_fname) // ".os")
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (160)", 1)
+              STOP
+           END IF
+           CALL setPositionAppend(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (165)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (170)", 1)
+              STOP
+           END IF
+
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "TRACE BACK (175)", 1)
+              WRITE(getUnit(out_file),"(A)") &
+                   "Could not write observations for object " // TRIM(id) 
+              error = .FALSE.
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#"
+
+           CALL NULLIFY(out_file)
+
+           ! WRITE ORBITS
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling ", &
+                   "TRACE BACK (175)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling ", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           CALL getResults(storb, repetition_arr_cmp=repetition_arr_cmp)
+           IF (error) THEN
+              CALL errorMessage("oorb / observation_sampling ", &
+                   "TRACE BACK (186)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           DO j=1,SIZE(orb_arr_cmp,dim=1)
+              IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=j==1, &
+                      element_type_out=element_type_out_prm, &
+                      id=id, &
+                      orb=orb_arr_cmp(j), &
+                      rchi2=rchi2_arr_cmp(j), &
+                      H=HG_arr_storb_in(i,j,1), &
+                      G=HG_arr_storb_in(i,j,3), &
+                      mjd=mjd_epoch, &
+                      repetitions=repetition_arr_cmp(j))
+              ELSE IF (orbit_format_out == "des") THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "DES format not yet supported for observation_sampling output.", 1)
+                 STOP                 
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+           END DO
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           ! WRITE RESIDUALS
+           IF (write_residuals) THEN
+              CALL NEW(out_file, TRIM(out_fname) // ".res")
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (225)", 1)
+                 STOP
+              END IF
+              CALL writeResiduals(storb, obss_sep(i), getUnit(out_file), compute=.TRUE.)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (230)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+           END IF
+
+           IF (plot_results) THEN
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "TRACE BACK (235)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                   "_os_residual_stamps.eps", compute=.TRUE.)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "TRACE BACK (240)", 1)
+                 STOP
+              END IF
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_os_residual_stamps.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_os_residual_stamps.eps* &")
+              END IF
+              ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "Could not allocate memory (3).", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// "_os_orbits.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "TRACE BACK (250)", 1)
+                 STOP
+              END IF
+              pdf_arr_cmp => getPDFValues(storb)
+              DO j=1,SIZE(orb_arr_cmp,dim=1)
+                 IF (element_type_comp_prm == "cartesian") THEN
+                    CALL rotateToEcliptic(orb_arr_cmp(j))
+                 END IF
+                 elements_arr(j,1:6) = getElements(orb_arr_cmp(j), element_type_comp_prm)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / observation_sampling", &
+                         "TRACE BACK (255)", 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    elements_arr(j,3:6) = elements_arr(j,3:6)/rad_deg
+                 END IF
+                 elements_arr(j,7) = pdf_arr_cmp(j)
+                 t = getTime(orb_arr_cmp(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / observation_sampling ", &
+                         "TRACE BACK (260)", 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file),"(7(E23.15,1X),A)") &
+                      elements_arr(j,1:6), &
+                      pdf_arr_cmp(j), &
+                      getCalendarDateString(t,"tdt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / observation_sampling ", &
+                         "TRACE BACK (265)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(t)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NEW(tmp_file, TRIM(str) // &
+                   "_os_sample_standard_deviations.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "TRACE BACK (275)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                   advance="no") &
+                   getObservationalTimespan(obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / observation_sampling ", &
+                      "TRACE BACK (280)", 1)
+                 STOP
+              END IF
+              DO j=1,6
+                 CALL moments(elements_arr(:,j), &
+                      pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+                 IF (LEN_TRIM(errstr) /= 0) THEN
+                    CALL errorMessage("oorb / observation_sampling", &
+                         "Could not compute moments. " // TRIM(errstr), 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                      advance="no") stdev
+              END DO
+              WRITE(getUnit(tmp_file),*)
+              CALL NULLIFY(tmp_file)
+              DEALLOCATE(elements_arr, stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / observation_sampling", &
+                      "Could not deallocate memory (5).", 1)
+                 STOP
+              END IF
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_os_orbits.out sor_orbits.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_car.gp")
+              ELSE
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_kep.gp")
+              END IF
+              CALL system("cp sor_results.eps " // TRIM(str) // &
+                   "_os_" // TRIM(element_type_comp_prm) // &
+                   "_results.eps")
+              CALL system("rm -f sor_orbits.out sor_results.eps " // & 
+                   TRIM(str) // "_os_orbits.out " // TRIM(str) // &
+                   "_os_sample_standard_deviations.out")
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_os_" // &
+                      TRIM(element_type_comp_prm) // "_results.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_os_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.eps* &")
+              END IF
+           END IF
+           DO j=1,SIZE(orb_arr_cmp)
+              CALL NULLIFY(orb_arr_cmp(j))
+           END DO
+           DEALLOCATE(orb_arr_cmp, stat=err)
+           DEALLOCATE(pdf_arr_cmp, stat=err)
+           DEALLOCATE(rchi2_arr_cmp, stat=err)
+           DEALLOCATE(repetition_arr_cmp, stat=err)           
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / observation_sampling", &
+                   "Could not deallocate memory (10).", 1)
+              STOP
+           END IF
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+        END IF
+        DEALLOCATE(orb_arr, stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / observation_sampling", &
+                "Could not deallocate memory (10)", 1)
+           STOP
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, orb_arr_, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / observation_sampling", &
+             "Could not deallocate memory (15)", 1)
+        STOP
+     END IF
+
+
+  CASE ("vov")
+
+     ! Orbit inversion using the 6D phase-space volume-of-variation
+     ! sampling.
+
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model=dyn_model, &
+          perturbers=perturbers, &
+          integrator=integrator, &
+          integration_step=integration_step, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          ls_correction_factor=ls_correction_factor, &
+          ls_element_mask=ls_element_mask, &
+          ls_rchi2_acceptable=ls_rchi2_acceptable, &
+          vov_type=vov_type_prm, &
+          vov_norb=vov_norb, &
+          vov_ntrial=vov_ntrial, &
+          vov_niter=vov_niter, &
+          vov_norb_iter=vov_norb_iter, &
+          vov_ntrial_iter=vov_ntrial_iter, &
+          vov_nmap=vov_nmap, &
+          vov_mapping_mask=vov_mapping_mask, &
+          vov_scaling=vov_scaling_prm, &
+          accwin_multiplier=accwin_multiplier)
+     IF (error) THEN
+        CALL errorMessage("oorb / vov", &
+             "TRACE BACK (2)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / vov", &
+             "TRACE BACK (25)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DO i=j+1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / vov", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")"
+        END IF
+        norb = 0
+        norb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    orb_arr => getSampleOrbits(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / lsl", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = SIZE(orb_arr)
+                    EXIT
+                 ELSE
+                    ALLOCATE(orb_arr(1))
+                    orb_arr(1) = getNominalOrbit(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / lsl", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = 1
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 norb = norb + 1
+                 IF (.NOT.ASSOCIATED(orb_arr)) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 ELSE IF (SIZE(orb_arr) < norb) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 END IF
+                 orb_arr(norb) = copy(orb_arr_in(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / lsl", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "Initial orbit not available.", 1)
+              STOP
+           ELSE
+              orb_arr => reallocate(orb_arr,norb)
+           END IF
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL propagate(orb_arr, t)
+        IF (error) THEN
+           CALL errorMessage("oorb / vov", &
+                "TRACE BACK (65)", 1)
+           STOP
+        END IF
+        DO k=1,norb
+           CALL setParameters(orb_arr(k), &
+                dyn_model=dyn_model, &
+                perturbers=perturbers, &
+                integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (35)", 1)
+              STOP
+           END IF
+        END DO
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / vov", &
+                "TRACE BACK (70)", 1)
+           STOP
+        END IF
+        vov_k: DO k=1,MIN(10,norb)
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(1X,A,1X,I0,2(A,1X))") "Trying", &
+                   k, ". orbit for object", TRIM(id)
+           END IF
+           CALL setParameters(storb, &
+                dyn_model=dyn_model, &
+                perturbers=perturbers, &
+                integrator=integrator, &
+                integration_step=integration_step, &
+                outlier_rejection=outlier_rejection_prm, &
+                outlier_multiplier=outlier_multiplier_prm, &
+                element_type=element_type_comp_prm, &
+                accept_multiplier=accwin_multiplier, &
+                vov_norb=vov_norb, &
+                vov_ntrial=vov_ntrial, &
+                vov_niter=vov_niter, &
+                vov_norb_iter=vov_norb_iter, &
+                vov_ntrial_iter=vov_ntrial_iter, &
+                vov_nmap=vov_nmap, &
+                vov_mapping_mask=vov_mapping_mask, &
+                vov_scaling=vov_scaling_prm, &
+                ls_correction_factor=ls_correction_factor, &
+                ls_element_mask=ls_element_mask, &
+                ls_rchi2_acceptable=ls_rchi2_acceptable)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (75)", 1)
+              STOP
+           END IF
+           SELECT CASE (vov_type_prm)
+           CASE (1)
+              CALL volumeOfVariation(storb, orb_arr(k))
+           CASE (2)
+              CALL autoVolumeOfVariation(storb, orb_arr(k))
+           CASE default
+              CALL errorMessage("oorb / vov", &
+                   "Unknown type of VoV:", 1)
+              IF (err_verb >= 1) THEN
+                 WRITE(stderr,"(2X,I0)") vov_type_prm
+              END IF
+              STOP
+           END SELECT
+           IF (error .OR. getNrOfSampleOrbits(storb) < INT(0.5*vov_norb)) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (80)", 1)
+              error  = .FALSE.
+              CALL NEW(out_file, "problematic_observation_sets." // &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (85)", 1)
+                 STOP
+              END IF
+              CALL setPositionAppend(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (90)", 1)
+                 STOP
+              END IF
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (95)", 1)
+                 STOP
+              END IF
+              CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (100)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (105)", 1)
+                 STOP
+              END IF
+              CYCLE vov_k
+           END IF
+           ! In case of too many outliers and the 2-b
+           ! approximation, throw the observation set in a separate
+           ! bin:
+           IF (dyn_model == "2-body") THEN
+              obs_masks => getObservationMasks(storb)
+              noutlier = 0
+              DO l=1,SIZE(obs_masks,dim=1)
+                 IF (ALL(.NOT.obs_masks(l,:))) THEN
+                    noutlier = noutlier + 1
+                 END IF
+              END DO
+              IF (noutlier > 0) THEN
+                 CALL NEW(out_file, "outliers." // TRIM(observation_format_out))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (85)", 1)
+                    STOP
+                 END IF
+                 CALL setPositionAppend(out_file)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (90)", 1)
+                    STOP
+                 END IF
+                 CALL OPEN(out_file)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (95)", 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(out_file),"(1X)")
+                 WRITE(getUnit(out_file),"(A,I0,A)",advance="no") "# ", &
+                      noutlier, " outliers: "
+                 DO l=1,SIZE(obs_masks,dim=1)
+                    IF (ALL(.NOT.obs_masks(l,:))) THEN
+                       WRITE(getUnit(out_file),"(A)",advance="no") "*"
+                    ELSE
+                       WRITE(getUnit(out_file),"(A)",advance="no") "-"
+                    END IF
+                 END DO
+                 WRITE(getUnit(out_file),"(1X)")
+                 CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                      TRIM(observation_format_out))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (100)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(out_file)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (105)", 1)
+                    STOP
+                 END IF
+              END IF
+              DEALLOCATE(obs_masks, stat=err)
+           END IF
+           CALL NEW(out_file, TRIM(id) // ".vov")
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (10)", 1)
+              STOP
+           END IF
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (85)", 1)
+              STOP
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#"
+           CALL writeVOVResults(storb, obss_sep(i), getUnit(out_file))
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK ()", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+
+           ! SAVE NOMINAL ORBIT INFORMATION TO A "LS" OUTPUT FILE?
+           CALL NEW(out_file, TRIM(id) // ".nominal")
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (10)", 1)
+              STOP
+           END IF
+           CALL writeNominalSolution(storb, obss_sep(i), &
+                element_type_out_prm, getUnit(out_file))
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK ()", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+           pdf_arr_cmp => getPDFValues(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           CALL getResults(storb, &
+                reg_apr_arr=reg_apr_arr_cmp, &
+                jac_arr=jac_arr_cmp)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (135)", 1)
+              STOP
+           END IF
+           CALL NEW(orb_out_file, TRIM(id) // ".orb")
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (15)", 1)
+              STOP
+           END IF
+           CALL OPEN(orb_out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vov", &
+                   "TRACE BACK (20)", 1)
+              STOP
+           END IF
+           DO l=1,SIZE(orb_arr_cmp,dim=1)
+              CALL writeOpenOrbOrbitFile(getUnit(orb_out_file), &
+                   print_header=l==1.AND.i==1, &
+                   element_type_out=element_type_out_prm, &
+                   id=id, &
+                   orb=orb_arr_cmp(l), &
+                   element_type_pdf=element_type_comp_prm, &
+                   pdf=pdf_arr_cmp(l), &
+                   rchi2=rchi2_arr_cmp(l), &
+                   reg_apr=reg_apr_arr_cmp(l), &
+                   jac_car_kep=jac_arr_cmp(l,2), &
+                   jac_equ_kep=jac_arr_cmp(l,3))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (140)", 1)
+                 STOP
+              END IF
+           END DO
+           CALL NULLIFY(orb_out_file)
+           IF (plot_results) THEN
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (145)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                   "_vov_residual_stamps.ps",  compute=.TRUE.)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (142)", 1)
+                 STOP
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_vov_residual_stamps.ps &")
+              END IF
+              CALL getResults(storb, &
+                   vov_map_cmp=vov_map, &
+                   vov_scaling_cmp=vov_scaling_cmp)
+              !vov_mapping_mask_prm=vov_mapping_mask)
+              CALL getParameters(storb, &
+                   vov_mapping_mask=vov_mapping_mask)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (135)", 1)
+                 STOP
+              END IF
+              ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "Could not allocate memory (10)", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// "_vov_orbits.out")
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (150)", 1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (155)", 1)
+                 STOP
+              END IF
+              DO l=1,SIZE(orb_arr_cmp,dim=1)
+                 IF (element_type_comp_prm == "cartesian") THEN
+                    CALL rotateToEcliptic(orb_arr_cmp(l))
+                 END IF
+                 elements_arr(l,1:6) = getElements(orb_arr_cmp(l), element_type_comp_prm)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (160)", 1)
+                    STOP
+                 END IF
+                 elements_arr(l,7) = pdf_arr_cmp(l)
+                 t = getTime(orb_arr_cmp(l))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "TRACE BACK (165)", 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    WRITE(getUnit(tmp_file),*) &
+                         elements_arr(l,1:2), &
+                         elements_arr(l,3:6)/rad_deg, &
+                         pdf_arr_cmp(l), &
+                         getCalendarDateString(t,"tdt")
+                 ELSE
+                    WRITE(getUnit(tmp_file),*) &
+                         elements_arr(l,1:6), &
+                         pdf_arr_cmp(l), &
+                         getCalendarDateString(t,"tdt")
+                 END IF
+                 CALL NULLIFY(t)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NULLIFY(orb)
+              orb = getNominalOrbit(storb)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (170)", 1)
+                 STOP
+              END IF
+              elements = getElements(orb, element_type_comp_prm)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (175)", 1)
+                 STOP
+              END IF
+              t = getTime(orb)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (180)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(orb)
+              CALL NEW(tmp_file, TRIM(str)// "_vov_nominal_orbit.out")
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (185)", 1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (190)", 1)
+                 STOP
+              END IF
+              IF (element_type_comp_prm == "keplerian") THEN
+                 WRITE(getUnit(tmp_file),*) elements(1:2), &
+                      elements(3:6)/rad_deg, &
+                      getCalendarDateString(t,"tdt")
+              ELSE
+                 WRITE(getUnit(tmp_file),*) elements(1:6), &
+                      getCalendarDateString(t,"tdt")
+              END IF
+              CALL NULLIFY(tmp_file)
+              CALL NULLIFY(t)
+              vov_nmap = SIZE(vov_map,dim=1)
+              CALL NEW(tmp_file, TRIM(str)// "_vov_sampling_grid.out")
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (195)", 1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              DO l=1,vov_nmap,vov_nmap/10
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    WRITE(getUnit(tmp_file), "(6(F22.15,1X))", &
+                         advance="no") vov_map(l,1:2), &
+                         vov_map(l,3:6)/rad_deg
+                 ELSE
+                    WRITE(getUnit(tmp_file), "(6(F22.15,1X))", &
+                         advance="no") vov_map(l,1:6)
+                 END IF
+                 lower_limit = vov_map(l,1:6) - &
+                      vov_scaling_cmp(:,1)*vov_map(l,7:12)
+                 upper_limit = vov_map(l,1:6) + &
+                      vov_scaling_cmp(:,2)*vov_map(l,7:12)
+                 DO m=1,6
+                    IF (vov_mapping_mask(m)) THEN
+                       CYCLE
+                    END IF
+                    IF (element_type_comp_prm == "keplerian" .AND. m>=3) THEN
+                       WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                            advance="no") lower_limit(m)/rad_deg
+                       WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                            advance="no") upper_limit(m)/rad_deg
+                    ELSE
+                       WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                            advance="no") lower_limit(m)
+                       WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                            advance="no") upper_limit(m)
+                    END IF
+                 END DO
+                 WRITE(getUnit(tmp_file),*)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NEW(tmp_file, TRIM(str) // &
+                   "_vov_sample_standard_deviations.out")
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (210)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                   advance="no") &
+                   getObservationalTimespan(obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "TRACE BACK (215)", 1)
+                 STOP
+              END IF
+              DO l=1,6
+                 CALL moments(elements_arr(:,l), &
+                      pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+                 IF (LEN_TRIM(errstr) /= 0) THEN
+                    CALL errorMessage("oorb / vov", &
+                         "Could not compute moments: " // TRIM(errstr), 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian" .AND. l>=3) THEN
+                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                         advance="no")  stdev/rad_deg
+                 ELSE
+                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                         advance="no") stdev
+                 END IF
+              END DO
+              WRITE(getUnit(tmp_file),*)
+              CALL NULLIFY(tmp_file)
+              DEALLOCATE(elements_arr, vov_map, stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / vov", &
+                      "Could not deallocate memory (10)", 1)
+                 STOP
+              END IF
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_vov_sampling_grid.out vov_sampling_grid.out")
+              CALL system("cp " // TRIM(str) // &
+                   "_vov_orbits.out vov_orbits.out")
+              CALL system("cp " // TRIM(str) // &
+                   "_vov_nominal_orbit.out vov_nominal_orbit.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/vov_plot_car.gp")
+              ELSE
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/vov_plot_kep.gp")
+              END IF
+              CALL system("cp vov_results.ps " // TRIM(str) // &
+                   "_vov_" // TRIM(element_type_comp_prm) // &
+                   "_results.ps")
+              CALL system("rm -f vov_sampling_grid.out vov_orbits.out " // &
+                   "vov_nominal_orbit.out vov_results.ps")
+              CALL system("rm -f " // TRIM(str) // &
+                   "_vov_sampling_grid.out " // TRIM(str) &
+                   // "_vov_orbits.out " // TRIM(str) // &
+                   "_vov_nominal_orbit.out " // TRIM(str) // &
+                   "_vov_sample_standard_deviations.out")
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_vov_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.ps &")
+              END IF
+           END IF
+           DEALLOCATE(orb_arr_cmp, pdf_arr_cmp, rchi2_arr_cmp, &
+                reg_apr_arr_cmp, jac_arr_cmp, stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / vov", &
+                   "Could not deallocate memory (10).", 1)
+              STOP
+           END IF
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+           ! No more trials needed:
+           EXIT
+        END DO vov_k
+        DEALLOCATE(orb_arr, stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / vov", &
+                "Could not deallocate memory (15)", 1)
+           STOP
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / vov", &
+             "Could not deallocate memory (20)", 1)
+        STOP
+     END IF
+
+  CASE ("vomcmc")
+
+     ! Orbit inversion using the virtual-observation MCMC sampling.
+
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model=dyn_model, &
+          perturbers=perturbers, &
+          integrator=integrator, &
+          integration_step=integration_step, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          ls_correction_factor=ls_correction_factor, &
+          ls_element_mask=ls_element_mask, &
+          ls_rchi2_acceptable=ls_rchi2_acceptable, &
+          vomcmc_type=vomcmc_type_prm, &
+          vomcmc_norb=vomcmc_norb, &
+          vomcmc_ntrial=vomcmc_ntrial, &
+          vomcmc_niter=vomcmc_niter, &
+          vomcmc_norb_iter=vomcmc_norb_iter, &
+          vomcmc_ntrial_iter=vomcmc_ntrial_iter, &
+          vomcmc_nmap=vomcmc_nmap, &
+          vomcmc_mapping_mask=vomcmc_mapping_mask, &
+          vomcmc_scaling=vomcmc_scaling_prm, &
+          accwin_multiplier=accwin_multiplier, &
+          generat_multiplier=generat_multiplier, &
+          generat_gaussian_deviates=generat_gaussian_deviates, &
+          os_norb=os_norb, &
+          os_ntrial=os_ntrial, &
+          os_sampling_type=os_sampling_type, &
+          smplx_niter=smplx_niter, &
+          smplx_similarity_tol=smplx_similarity_tol)
+     IF (error) THEN
+        CALL errorMessage("oorb / vomcmc", &
+             "TRACE BACK (2)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / vomcmc", &
+             "TRACE BACK (25)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")"
+        END IF
+        norb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    orb_arr => getSampleOrbits(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / vomcmc", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = SIZE(orb_arr)
+                    EXIT
+                 ELSE
+                    ALLOCATE(orb_arr(1))
+                    orb_arr(1) = getNominalOrbit(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / vomcmc", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = 1
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 norb = norb + 1
+                 IF (.NOT.ASSOCIATED(orb_arr)) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 ELSE IF (SIZE(orb_arr) < norb) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 END IF
+                 orb_arr(norb) = copy(orb_arr_in(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / vomcmc", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "Initial orbit not available.", 1)
+              STOP
+           ELSE
+              orb_arr => reallocate(orb_arr,norb)
+           END IF
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL propagate(orb_arr, t)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (65)", 1)
+           STOP
+        END IF
+        DO k=1,norb
+           CALL setParameters(orb_arr(k), &
+                dyn_model=dyn_model, &
+                perturbers=perturbers, &
+                integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (35)", 1)
+              STOP
+           END IF
+        END DO
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (70)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             t_inv=t, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             dchi2_rejection = dchi2_rejection, &
+             dchi2_max = dchi2_max, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             element_type=element_type_comp_prm, &
+             accept_multiplier=accwin_multiplier, &
+             vomcmc_norb=vomcmc_norb, &
+             vomcmc_ntrial=vomcmc_ntrial, &
+             vomcmc_niter=vomcmc_niter, &
+             vomcmc_norb_iter=vomcmc_norb_iter, &
+             vomcmc_ntrial_iter=vomcmc_ntrial_iter, &
+             vomcmc_nmap=vomcmc_nmap, &
+             vomcmc_mapping_mask=vomcmc_mapping_mask, &
+             vomcmc_scaling=vomcmc_scaling_prm, &
+             generat_multiplier=generat_multiplier, &
+             generat_gaussian_deviates=generat_gaussian_deviates, &
+             os_norb=os_norb, &
+             os_ntrial=os_ntrial, &
+             os_sampling_type=os_sampling_type, &
+             smplx_niter=smplx_niter, &
+             smplx_force=.FALSE., &
+             smplx_similarity_tol=smplx_similarity_tol)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (75)", 1)
+           STOP
+        END IF
+        SELECT CASE (vomcmc_type_prm)
+        CASE (1)
+           CALL virtualObservationMCMC(storb, orb_arr)
+        CASE (2)
+           CALL virtualObservationMCMC(storb, orb_arr)
+        CASE default
+           CALL errorMessage("oorb / vomcmc", &
+                "Unknown type of Vomcmc:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(2X,I0)") vomcmc_type_prm
+           END IF
+           STOP
+        END SELECT
+        IF (error .OR. getNrOfSampleOrbits(storb) < INT(0.5*vomcmc_norb)) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (80)", 1)
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets." // &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (85)", 1)
+              STOP
+           END IF
+           CALL setPositionAppend(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (90)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (95)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (100)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (105)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(storb)
+           CYCLE
+        END IF
+        ! In case of too many outliers and the 2-b
+        ! approximation, throw the observation set in a separate
+        ! bin:
+        IF (dyn_model == "2-body") THEN
+           obs_masks => getObservationMasks(storb)
+           noutlier = 0
+           DO l=1,SIZE(obs_masks,dim=1)
+              IF (ALL(.NOT.obs_masks(l,:))) THEN
+                 noutlier = noutlier + 1
+              END IF
+           END DO
+           IF (noutlier > 0) THEN
+              CALL NEW(out_file, "outliers." // TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (85)", 1)
+                 STOP
+              END IF
+              CALL setPositionAppend(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (90)", 1)
+                 STOP
+              END IF
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (95)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(out_file),"(1X)")
+              WRITE(getUnit(out_file),"(A,I0,A)",advance="no") "# ", &
+                   noutlier, " outliers: "
+              DO l=1,SIZE(obs_masks,dim=1)
+                 IF (ALL(.NOT.obs_masks(l,:))) THEN
+                    WRITE(getUnit(out_file),"(A)",advance="no") "*"
+                 ELSE
+                    WRITE(getUnit(out_file),"(A)",advance="no") "-"
+                 END IF
+              END DO
+              WRITE(getUnit(out_file),"(1X)")
+              CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (100)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (105)", 1)
+                 STOP
+              END IF
+           END IF
+           DEALLOCATE(obs_masks, stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "Could not deallocate memory (5)", 1)
+              STOP
+           END IF
+        END IF
+        CALL NEW(out_file, TRIM(id) // ".vomcmc")
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (115)", 1)
+           STOP
+        END IF
+        CALL OPEN(out_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (10)", 1)
+           STOP
+        END IF
+        ! WRITE OBSERVATIONS:
+        CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+             TRIM(observation_format_out)) 
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (85)", 1)
+           STOP
+        END IF
+        WRITE(getUnit(out_file),"(A)") "#"
+        CALL writeVOMCMCResults(storb, obss_sep(i), getUnit(out_file))
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK ()", 1)
+           STOP
+        END IF
+        CALL NULLIFY(out_file)
+        ! WRITE SAMPLE ORBITS TO OUTPUT FILE
+        orb_arr_cmp => getSampleOrbits(storb)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (120)", 1)
+           STOP
+        END IF
+        pdf_arr_cmp => getPDFValues(storb)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (125)", 1)
+           STOP
+        END IF
+        rchi2_arr_cmp => getReducedChi2Distribution(storb)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (130)", 1)
+           STOP
+        END IF
+        CALL getResults(storb, repetition_arr_cmp=repetition_arr_cmp)
+        IF (error) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "TRACE BACK (135)", 1)
+           STOP
+        END IF
+        IF (separately) THEN
+           CALL NEW(out_file, TRIM(id) // ".orb")
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (200)", 1)
+              STOP
+           END IF
+           lu_orb_out = getUnit(out_file)
+        END IF
+        DO l=1,SIZE(orb_arr_cmp,dim=1)
+           CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                print_header=l==1.AND.i==1, &
+                element_type_out=element_type_out_prm, &
+                id=id, &
+                orb=orb_arr_cmp(l), &
+                element_type_pdf=element_type_comp_prm, &
+                pdf=pdf_arr_cmp(l), &
+                rchi2=rchi2_arr_cmp(l), &
+                repetitions=repetition_arr_cmp(l))
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (140)", 1)
+              STOP
+           END IF
+        END DO
+        IF (separately) THEN
+           CALL NULLIFY(out_file)
+           IF (compress) THEN
+              CALL system("gzip -f " // TRIM(id) // ".orb")
+           END IF
+        END IF
+        IF (plot_results) THEN
+           CALL toString(dt, str, error, frmt="(F10.2)")
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (145)", 1)
+              STOP
+           END IF
+           str = TRIM(id) // "_"// TRIM(str)
+           CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                "_vomcmc_residual_stamps.ps",  compute=.TRUE.)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (142)", 1)
+              STOP
+           END IF
+           IF (plot_open) THEN
+              CALL system("gv " // TRIM(str) // "_vomcmc_residual_stamps.ps &")
+           END IF
+!!$           CALL getResults(storb, &
+!!$                vomcmc_map_cmp=vomcmc_map, &
+!!$                vomcmc_scaling_cmp=vomcmc_scaling_cmp)
+           !vomcmc_mapping_mask_prm=vomcmc_mapping_mask)
+           CALL getParameters(storb, &
+                vomcmc_mapping_mask=vomcmc_mapping_mask)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (135)", 1)
+              STOP
+           END IF
+           ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "Could not allocate memory (10)", 1)
+              STOP
+           END IF
+           CALL NEW(tmp_file, TRIM(str)// "_vomcmc_orbits.out")
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (150)", 1)
+              STOP
+           END IF
+           CALL OPEN(tmp_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (155)", 1)
+              STOP
+           END IF
+           DO l=1,SIZE(orb_arr_cmp,dim=1)
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL rotateToEcliptic(orb_arr_cmp(l))
+              END IF
+              elements_arr(l,1:6) = getElements(orb_arr_cmp(l), element_type_comp_prm)
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (160)", 1)
+                 STOP
+              END IF
+              elements_arr(l,7) = pdf_arr_cmp(l)
+              t = getTime(orb_arr_cmp(l))
+              IF (error) THEN
+                 CALL errorMessage("oorb / vomcmc", &
+                      "TRACE BACK (165)", 1)
+                 STOP
+              END IF
+              IF (element_type_comp_prm == "keplerian") THEN
+                 WRITE(getUnit(tmp_file),*) &
+                      elements_arr(l,1:2), &
+                      elements_arr(l,3:6)/rad_deg, &
+                      pdf_arr_cmp(l), &
+                      getCalendarDateString(t,"tdt")
+              ELSE
+                 WRITE(getUnit(tmp_file),*) &
+                      elements_arr(l,1:6), &
+                      pdf_arr_cmp(l), &
+                      getCalendarDateString(t,"tdt")
+              END IF
+              CALL NULLIFY(t)
+           END DO
+           CALL NULLIFY(tmp_file)
+           CALL NULLIFY(orb)
+           orb = getNominalOrbit(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (170)", 1)
+              STOP
+           END IF
+           elements = getElements(orb, element_type_comp_prm)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (175)", 1)
+              STOP
+           END IF
+           t = getTime(orb)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (180)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(orb)
+           CALL NEW(tmp_file, TRIM(str)// "_vomcmc_nominal_orbit.out")
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           CALL OPEN(tmp_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / vomcmc", &
+                   "TRACE BACK (190)", 1)
+              STOP
+           END IF
+           IF (element_type_comp_prm == "keplerian") THEN
+              WRITE(getUnit(tmp_file),*) elements(1:2), &
+                   elements(3:6)/rad_deg, &
+                   getCalendarDateString(t,"tdt")
+           ELSE
+              WRITE(getUnit(tmp_file),*) elements(1:6), &
+                   getCalendarDateString(t,"tdt")
+           END IF
+           CALL NULLIFY(tmp_file)
+           CALL NULLIFY(t)
+!!$           vomcmc_nmap = SIZE(vomcmc_map,dim=1)
+!!$           CALL NEW(tmp_file, TRIM(str)// "_vomcmc_sampling_grid.out")
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "TRACE BACK (195)", 1)
+!!$              STOP
+!!$           END IF
+!!$           CALL OPEN(tmp_file)
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "TRACE BACK (200)", 1)
+!!$              STOP
+!!$           END IF
+!!$           DO l=1,vomcmc_nmap
+!!$              IF (element_type_comp_prm == "keplerian") THEN
+!!$                 WRITE(getUnit(tmp_file), "(6(F22.15,1X))", &
+!!$                      advance="no") vomcmc_map(l,1:2), &
+!!$                      vomcmc_map(l,3:6)/rad_deg
+!!$              ELSE
+!!$                 WRITE(getUnit(tmp_file), "(6(F22.15,1X))", &
+!!$                      advance="no") vomcmc_map(l,1:6)
+!!$              END IF
+!!$              lower_limit = vomcmc_map(l,1:6) - &
+!!$                   vomcmc_scaling_cmp(:,1)*vomcmc_map(l,7:12)
+!!$              upper_limit = vomcmc_map(l,1:6) + &
+!!$                   vomcmc_scaling_cmp(:,2)*vomcmc_map(l,7:12)
+!!$              DO m=1,6
+!!$                 IF (vomcmc_mapping_mask(m)) THEN
+!!$                    CYCLE
+!!$                 END IF
+!!$                 IF (element_type_comp_prm == "keplerian" .AND. m>=3) THEN
+!!$                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                         advance="no") lower_limit(m)/rad_deg
+!!$                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                         advance="no") upper_limit(m)/rad_deg
+!!$                 ELSE
+!!$                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                         advance="no") lower_limit(m)
+!!$                    WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                         advance="no") upper_limit(m)
+!!$                 END IF
+!!$              END DO
+!!$              WRITE(getUnit(tmp_file),*)
+!!$           END DO
+!!$           CALL NULLIFY(tmp_file)
+!!$           CALL NEW(tmp_file, TRIM(str) // &
+!!$                "_vomcmc_sample_standard_deviations.out")
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "TRACE BACK (205)", 1)
+!!$              STOP
+!!$           END IF
+!!$           CALL OPEN(tmp_file)
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "TRACE BACK (210)", 1)
+!!$              STOP
+!!$           END IF
+!!$           WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                advance="no") &
+!!$                getObservationalTimespan(obss_sep(i))
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "TRACE BACK (215)", 1)
+!!$              STOP
+!!$           END IF
+!!$           DO l=1,6
+!!$              CALL moments(elements_arr(:,l), &
+!!$                   pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+!!$              IF (LEN_TRIM(errstr) /= 0) THEN
+!!$                 CALL errorMessage("oorb / vomcmc", &
+!!$                      "Could not compute moments: " // TRIM(errstr), 1)
+!!$                 STOP
+!!$              END IF
+!!$              IF (element_type_comp_prm == "keplerian" .AND. l>=3) THEN
+!!$                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                      advance="no")  stdev/rad_deg
+!!$              ELSE
+!!$                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+!!$                      advance="no") stdev
+!!$              END IF
+!!$           END DO
+!!$           WRITE(getUnit(tmp_file),*)
+!!$           CALL NULLIFY(tmp_file)
+!!$           DEALLOCATE(elements_arr, vomcmc_map, stat=err)
+!!$           IF (err /= 0) THEN
+!!$              CALL errorMessage("oorb / vomcmc", &
+!!$                   "Could not deallocate memory (10)", 1)
+!!$              STOP
+!!$           END IF
+!!$           ! Make plot using gnuplot:
+!!$           CALL system("cp " // TRIM(str) // &
+!!$                "_vomcmc_sampling_grid.out vomcmc_sampling_grid.out")
+           !CALL system("cp " // TRIM(str) // &
+           !     "_vomcmc_orbits.out vomcmc_orbits.out")
+           CALL system("cp " // TRIM(str) // &
+                "_vomcmc_orbits.out sor_orbits.out")
+!!$           CALL system("cp " // TRIM(str) // &
+!!$                "_vomcmc_nominal_orbit.out vomcmc_nominal_orbit.out")
+           !           IF (element_type_comp_prm == "cartesian") THEN
+           !              CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/vomcmc_plot_car.gp")
+           !           ELSE
+           !              CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/vomcmc_plot_kep.gp")
+           !           END IF
+           !           CALL system("cp vomcmc_results.ps " // TRIM(str) // &
+           !                "_vomcmc_" // TRIM(element_type_comp_prm) // &
+           !                "_results.ps")
+           IF (element_type_comp_prm == "cartesian") THEN
+              CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_car.gp")
+           ELSE
+              CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/sor_plot_kep.gp")
+           END IF
+           CALL system("cp sor_results.eps " // TRIM(str) // &
+                "_vomcmc_" // TRIM(element_type_comp_prm) // &
+                "_results.eps")
+           CALL system("rm -f vomcmc_sampling_grid.out vomcmc_orbits.out " // &
+                "vomcmc_nominal_orbit.out vomcmc_results.ps")
+           CALL system("rm -f " // TRIM(str) // &
+                "_vomcmc_sampling_grid.out " // TRIM(str) &
+                // "_vomcmc_orbits.out " // TRIM(str) // &
+                "_vomcmc_nominal_orbit.out " // TRIM(str) // &
+                "_vomcmc_sample_standard_deviations.out")
+           IF (plot_open) THEN
+              CALL system("gv " // TRIM(str) // "_vomcmc_" // &
+                   TRIM(element_type_comp_prm) // &
+                   "_results.ps &")
+           END IF
+        END IF
+        DEALLOCATE(orb_arr_cmp, pdf_arr_cmp, rchi2_arr_cmp, &
+             stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "Could not deallocate memory (15).", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(3(1X,A))") "Object", &
+                TRIM(id), "successfully processed."
+        END IF
+        DEALLOCATE(orb_arr, stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / vomcmc", &
+                "Could not deallocate memory (20)", 1)
+           STOP
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / vomcmc", &
+             "Could not deallocate memory (25)", 1)
+        STOP
+     END IF
+
+
+  CASE ("lsl")
+
+     ! Orbital inversion using least squares with linearized
+     ! covariances, that is, fixing the resulting shape of the
+     ! orbital-element pdf to a multidimensional Gaussian.
+
+     CALL NULLIFY(epoch)
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          ls_correction_factor=ls_correction_factor, &
+          ls_rchi2_acceptable=ls_rchi2_acceptable, &
+          ls_element_mask=ls_element_mask, &
+          ls_niter_major_max=ls_niter_major_max, &
+          ls_niter_major_min=ls_niter_major_min, &
+          ls_niter_minor=ls_niter_minor, &
+          sor_norb=sor_norb, &
+          sor_ntrial=sor_ntrial, &
+          sor_norb_sw=sor_norb_sw, &
+          sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, &
+          sor_rho_init=sor_rho_init, &
+          generat_multiplier=generat_multiplier, &
+          accwin_multiplier=accwin_multiplier)
+     IF (error) THEN
+        CALL errorMessage("oorb / lsl", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / lsl", &
+             "TRACE BACK (20)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DEALLOCATE(HG_arr_storb_in, stat=err)
+     ALLOCATE(HG_arr_storb_in(SIZE(obss_sep),1,4))
+     HG_arr_storb_in = 99.9_bp
+     ! Print header before printing first orbit:
+     first = .TRUE.
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (25)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")."
+        END IF
+        nobs = getNrOfObservations(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        IF (nobs < 4) THEN
+           CALL errorMessage("oorb / lsl", &
+                "Too few observations:", 1)
+           WRITE(stderr,*) "ID: ", TRIM(id), "  and number of observations: ", nobs
+           CYCLE
+        END IF
+        norb = 0
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    orb_arr => getSampleOrbits(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / lsl", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = SIZE(orb_arr)
+                    EXIT
+                 ELSE
+                    ALLOCATE(orb_arr(1))
+                    orb_arr(1) = getNominalOrbit(storb_arr_in(j))
+                    IF (error) THEN
+                       CALL errorMessage("oorb / lsl", &
+                            "TRACE BACK (35)", 1)
+                       STOP
+                    END IF
+                    norb = 1
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE IF (ASSOCIATED(orb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_in,dim=1)
+              IF (id_arr_in(j) == id) THEN
+                 norb = norb + 1
+                 IF (.NOT.ASSOCIATED(orb_arr)) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 ELSE IF (SIZE(orb_arr) < norb) THEN
+                    orb_arr => reallocate(orb_arr,2*norb)
+                 END IF
+                 orb_arr(norb) = copy(orb_arr_in(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / lsl", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+              END IF
+           END DO
+           IF (norb == 0) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "Initial orbit not available.", 1)
+              STOP
+           ELSE
+              orb_arr => reallocate(orb_arr,norb)
+           END IF
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL NEW(storb, obss_sep(i))        
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (75)", 1)
+           STOP
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             accept_multiplier=accwin_multiplier, &
+             ls_correction_factor=ls_correction_factor, &
+             ls_rchi2_acceptable=ls_rchi2_acceptable, &
+             ls_element_mask=ls_element_mask, &
+             ls_niter_major_max=ls_niter_major_max, &
+             ls_niter_major_min=ls_niter_major_min, &
+             ls_niter_minor=ls_niter_minor)
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "TRACE BACK (80)", 1)
+           STOP
+        END IF
+        DO j=1,SIZE(orb_arr,dim=1)
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(A,I0)") "Orbit #", j
+           END IF
+           CALL setParameters(orb_arr(j), &
+                dyn_model=dyn_model_init, &
+                perturbers=perturbers, &
+                integrator=integrator_init, &
+                integration_step=integration_step_init)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (85)", 1)
+              STOP
+           END IF
+           CALL propagate(orb_arr(j), t)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (90)", 1)
+              STOP
+           END IF
+           CALL setParameters(orb_arr(j), &
+                dyn_model=dyn_model, &
+                perturbers=perturbers, &
+                integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (95)", 1)
+              STOP
+           END IF
+           CALL levenbergMarquardt(storb, orb_arr(j))
+           IF (.NOT.error) THEN
+              EXIT
+           ELSE IF (j < norb) THEN
+              error = .FALSE.
+           END IF
+        END DO
+        IF (error) THEN
+           CALL errorMessage("oorb / lsl", &
+                "Least squares failed:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(3A,1X,I0)") "ID: ", TRIM(id), &
+                   " and number of observations: ", nobs
+           END IF
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+        ELSE
+           obs_masks => getObservationMasks(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (130)", 1)
+              STOP
+           END IF
+           noutlier = 0
+           DO j=1,SIZE(obs_masks,dim=1)
+              IF (ALL(.NOT.obs_masks(j,:))) THEN
+                 noutlier = noutlier + 1
+              END IF
+           END DO
+           IF (noutlier > SIZE(obs_masks,dim=1)/5) THEN
+              ! In case of too many outliers (>20% of obs), throw the
+              ! observation set in a separate bin:
+              CALL NEW(out_file, "observation_sets_with_many_outliers." // TRIM(observation_format_out))
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (145)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(out_file),"(1X)")
+              WRITE(getUnit(out_file),"(A,I0,A)",advance="no") "# ", &
+                   noutlier, " outliers: "
+              DO j=1,SIZE(obs_masks,dim=1)
+                 IF (ALL(.NOT.obs_masks(j,:))) THEN
+                    WRITE(getUnit(out_file),"(A)",advance="no") "*"
+                 ELSE
+                    WRITE(getUnit(out_file),"(A)",advance="no") "-"
+                 END IF
+              END DO
+              WRITE(getUnit(out_file),"(1X)")
+              CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                   TRIM(observation_format_out))
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (150)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (155)", 1)
+                 STOP
+              END IF
+              CYCLE
+           END IF
+           DEALLOCATE(obs_masks, stat=err)
+
+           IF (pp_H_estimation) THEN
+              CALL NEW(physparam, storb)
+              IF (pp_G > 99.0_bp) THEN
+                 CALL estimateHAndG(physparam, obss_sep(i))
+              ELSE
+                 CALL estimateHAndG(physparam, obss_sep(i), &
+                      input_G=pp_G, input_delta_G=pp_G_unc)
+              END IF
+              HG_arr_storb_in(i,1,1:2) = getH0(physparam)
+              HG_arr_storb_in(i,1,3:4) = getG(physparam)
+              CALL NULLIFY(physparam)
+           END IF
+
+           CALL NEW(out_file, TRIM(out_fname) // ".ls")
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (160)", 1)
+              STOP
+           END IF
+           CALL setPositionAppend(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (165)", 1)
+              STOP
+           END IF
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (170)", 1)
+              STOP
+           END IF
+
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (175)", 1)
+              WRITE(getUnit(out_file),"(A)") &
+                   "Could not write observations for object " // TRIM(id) 
+              error = .FALSE.
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#"
+
+           ! WRITE LS RESULTS
+           CALL writeNominalSolution(storb, obss_sep(i), &
+                element_type_out_prm, getUnit(out_file))
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (180)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+
+           ! ORBITAL ELEMENTS:
+           CALL NULLIFY(orb)
+           orb = getNominalOrbit(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           cov = getCovarianceMatrix(storb, element_type_out_prm, "ecliptic")
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (190)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           SELECT CASE (TRIM(orbit_format_out))
+           CASE ("des")
+              CALL errorMessage("oorb / lsl", &
+                   "DES format not yet supported for LSL output.", 1)
+              STOP                 
+           CASE ("orb")
+              CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                   print_header=first, &
+                   element_type_out=element_type_out_prm, &
+                   id=id, &
+                   orb=orb, &
+                   cov=cov, &
+                   H=HG_arr_storb_in(i,1,1), &
+                   G=HG_arr_storb_in(i,1,3), &
+                   mjd=mjd_epoch)
+           CASE default
+              CALL errorMessage("oorb / lsl", &
+                   "Orbit format " // TRIM(orbit_format_out) // &
+                   " not supported.",1)
+              STOP           
+           END SELECT
+           IF (error) THEN
+              CALL errorMessage("oorb / lsl", &
+                   "TRACE BACK (195)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           first = .FALSE.
+
+           IF (plot_results) THEN
+              ! Prepare data for plotting
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              elements = getElements(orb, element_type_comp_prm, "ecliptic")
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+              t = getTime(orb)
+              CALL NULLIFY(orb)
+              cov = getCovarianceMatrix(storb, element_type_comp_prm, "ecliptic")
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (207)", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// &
+                   "_ls_nominal_orbit_stdevs_corrs.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (215)", 1)
+                 STOP
+              END IF
+              IF (element_type_comp_prm == "keplerian") THEN
+                 elements(3:6) = elements(3:6)/rad_deg
+              END IF
+              WRITE(getUnit(tmp_file), "(6(E22.15,1X))", advance="no") &
+                   elements(1:6)
+              DO j=1,6
+                 CALL toString(elements(j), element_str_arr(j), error, frmt="(E22.15)")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / lsl", &
+                         "TRACE BACK (220)", 1)
+                    STOP
+                 END IF
+                 stdev = SQRT(cov(j,j))
+                 IF (element_type_comp_prm == "keplerian" .AND. j>=3) THEN
+                    stdev = stdev/rad_deg
+                 END IF
+                 WRITE(getUnit(tmp_file), "(E22.15,1X)", &
+                      advance="no") stdev
+                 CALL toString(stdev, stdev_str_arr(j), error, frmt="(E22.15)")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / lsl", &
+                         "TRACE BACK (225)", 1)
+                    STOP
+                 END IF
+              END DO
+              stdev = SQRT(cov(1,1))
+              DO j=2,6
+                 WRITE(getUnit(tmp_file), "(E22.15,1X)", &
+                      advance="no") cov(1,j)/(stdev*SQRT(cov(j,j)))
+                 CALL toString(cov(1,j)/(stdev*SQRT(cov(j,j))), &
+                      corr_str_arr(j-1), error, frmt="(E22.15)")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / lsl", &
+                         "TRACE BACK (230)", 1)
+                    STOP
+                 END IF
+              END DO
+              WRITE(getUnit(tmp_file), "(E22.15,1X,A)") &
+                   getObservationalTimespan(obss_sep(i)), &
+                   getCalendarDateString(t,"tdt")
+              IF (error) THEN
+                 CALL errorMessage("oorb / lsl", &
+                      "TRACE BACK (235)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(tmp_file)
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_ls_nominal_orbit_stdevs_corrs.out " // &
+                   "ls_nominal_orbit_stdevs_corrs.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("cp " // TRIM(gnuplot_scripts_dir) // "/ls_plot.gp " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'x [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'y [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(2)) // &
+                      "+" // TRIM(stdev_str_arr(2)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(1)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+ 3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // &
+                      TRIM(element_str_arr(2)) // &
+                      "+3*" // TRIM(stdev_str_arr(2)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(1)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:2 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.5,0.66 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'x [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'z [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(3)) // &
+                      "+" // TRIM(stdev_str_arr(3)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(2)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(3)) // &
+                      "+3*" // TRIM(stdev_str_arr(3)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(2)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:3 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.0,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'x [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'dx/dt [AU/d]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(4)) // &
+                      "+" // TRIM(stdev_str_arr(4)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(3)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(4)) // &
+                      "+3*" // TRIM(stdev_str_arr(4)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(3)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:4 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'x [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'dy/dt [AU/d]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(5)) // &
+                      "+" // TRIM(stdev_str_arr(5)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(4)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(5)) // &
+                      "+3*" // TRIM(stdev_str_arr(5)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(4)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:5 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.0,0.0 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'x [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'dz/dt [AU/d]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(6)) // &
+                      "+" // TRIM(stdev_str_arr(6)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(5)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(6)) // &
+                      "+3*" // TRIM(stdev_str_arr(6)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(5)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:6 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo unset parametric  >> " // TRIM(str) // ".gp")
+                 CALL system("echo unset multiplot >> " // TRIM(str) // ".gp")
+                 CALL system("echo reset >> " // TRIM(str) // ".gp")
+                 CALL system("echo set terminal x11 >> " // TRIM(str) // ".gp")
+                 CALL system("gnuplot " //  TRIM(str) // ".gp")
+              ELSE IF (element_type_comp_prm == "keplerian") THEN
+                 CALL system("cp " // TRIM(gnuplot_scripts_dir) // "/ls_plot.gp " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'a [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'e\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(2)) // &
+                      "+" // TRIM(stdev_str_arr(2)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(1)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+ 3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // &
+                      TRIM(element_str_arr(2)) // &
+                      "+3*" // TRIM(stdev_str_arr(2)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(1)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:2 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.5,0.66 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'a [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'i [deg]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(3)) // &
+                      "+" // TRIM(stdev_str_arr(3)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(2)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(3)) // &
+                      "+3*" // TRIM(stdev_str_arr(3)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(2)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:3 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.0,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'a [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'\{/Symbol O\} [deg]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(4)) // &
+                      "+" // TRIM(stdev_str_arr(4)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(3)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(4)) // &
+                      "+3*" // TRIM(stdev_str_arr(4)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(3)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:4 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'a [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'\{/Symbol o\} [deg]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(5)) // &
+                      "+" // TRIM(stdev_str_arr(5)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(4)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(5)) // &
+                      "+3*" // TRIM(stdev_str_arr(5)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(4)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:5 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo set size 0.5,0.33 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set origin 0.0,0.0 >> " // TRIM(str) // ".gp")
+                 CALL system("echo set xlabel \'a [AU]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set ylabel \'M [deg]\' >> " // TRIM(str) // ".gp")
+                 CALL system("echo set parametric >> " // TRIM(str) // ".gp")
+                 CALL system("echo plot " // TRIM(element_str_arr(1)) // "+" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(6)) // &
+                      "+" // TRIM(stdev_str_arr(6)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(5)) // "*pi/2\), " // &
+                      TRIM(element_str_arr(1)) // "+3*" // &
+                      TRIM(stdev_str_arr(1)) // "*cos\(t\)," // TRIM(element_str_arr(6)) // &
+                      "+3*" // TRIM(stdev_str_arr(6)) // "*sin\(t+" // &
+                      TRIM(corr_str_arr(5)) // "*pi/2\), " // &
+                      "\'ls_nominal_orbit_stdevs_corrs.out\' " // &
+                      "using 1:6 with points pt 3 ps 3.0 >> " // &
+                      TRIM(str) // ".gp")
+                 CALL system("echo unset parametric  >> " // TRIM(str) // ".gp")
+                 CALL system("echo unset multiplot >> " // TRIM(str) // ".gp")
+                 CALL system("echo reset >> " // TRIM(str) // ".gp")
+                 CALL system("echo set terminal x11 >> " // TRIM(str) // ".gp")
+                 CALL system("gnuplot " //  TRIM(str) // ".gp")
+              END IF
+              CALL system("cp ls_results.eps " // TRIM(str) // &
+                   "_ls_" // TRIM(element_type_comp_prm) // &
+                   "_results.eps")
+              CALL system("rm -f " // &
+                   "ls_nominal_orbit_stdevs_corrs.out " // &
+                   "ls_results.eps " // TRIM(str) // &
+                   "_ls_nominal_orbit_stdevs_corrs.out " // &
+                   TRIM(str) // ".gp")
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_ls_" // &
+                      TRIM(element_type_comp_prm) // "_results.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_ls_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.eps* &")
+              END IF
+           END IF
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+        END IF
+        DEALLOCATE(orb_arr, stat=err)
+        IF (err /= 0) THEN
+           CALL errorMessage("oorb / lsl", &
+                "Could not deallocate memory (10)", 1)
+           STOP
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb > 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / lsl", &
+             "Could not deallocate memory (15)", 1)
+        STOP
+     END IF
+
+  CASE ("covariance_sampling")
+
+     ! Guided orbital inversion by randomly sampling an error
+     ! hyperellipsoid defined by the covariance matrix of the global
+     ! least-squares solution.
+
+     CALL NULLIFY(epoch)
+     CALL readConfigurationFile(conf_file, &
+          t0=epoch, &
+          dyn_model_init=dyn_model_init, &
+          integrator_init=integrator_init, &
+          integration_step_init=integration_step_init, &
+          accwin_multiplier=accwin_multiplier, &
+          cos_gaussian=cos_gaussian, &
+          cos_nsigma=cos_nsigma, &
+          cos_norb=cos_norb, &
+          cos_ntrial=cos_ntrial)
+     IF (error) THEN
+        CALL errorMessage("oorb / covariance_sampling", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / covariance_sampling", &
+             "TRACE BACK (20)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     DEALLOCATE(HG_arr_storb_in, stat=err)
+     ALLOCATE(HG_arr_storb_in(SIZE(obss_sep),os_norb,4))
+     HG_arr_storb_in = 99.9_bp
+     ! Print header before printing first orbit:
+     first = .TRUE.
+     DO i=1,SIZE(obss_sep,dim=1)
+        id = getID(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (25)", 1)
+           STOP
+        END IF
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,"(1X,I0,3(A),1X,I0,A,I0)") i, &
+                ". observation set (", TRIM(id), ")."
+        END IF
+        nobs = getNrOfObservations(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (30)", 1)
+           STOP
+        END IF
+        IF (ALLOCATED(storb_arr_in)) THEN
+           DO j=1,SIZE(id_arr_storb_in,dim=1)
+              IF (id_arr_storb_in(j) == id) THEN
+                 IF (containsSampledPDF(storb_arr_in(j))) THEN
+                    CALL errorMessage("oorb / covariance_sampling", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 ELSE
+                    EXIT                    
+                 END IF
+              END IF
+           END DO
+           IF (j > SIZE(id_arr_storb_in,dim=1)) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "Initial orbit not available.", 1)
+              STOP
+           END IF
+        ELSE
+           CALL errorMessage("oorb / covariance_sampling", &
+                "Initial orbit + covariance matrix not available.", 1)
+           STOP
+        END IF
+        orb = getNominalOrbit(storb_arr_in(j))
+        frame = getFrame(orb)
+        cov = getCovarianceMatrix(storb_arr_in(j),element_type_comp_prm,frame)
+        CALL NEW(storb, orb, cov, element_type_comp_prm, &
+             element_type_comp_prm, obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (75)", 1)
+           STOP
+        END IF
+        dt = getObservationalTimespan(obss_sep(i))
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (40)", 1)
+           STOP
+        END IF
+        IF (.NOT.exist(epoch)) THEN
+           CALL NULLIFY(t)
+           obs = getObservation(obss_sep(i),1)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (45)", 1)
+              STOP
+           END IF
+           t = getTime(obs)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (50)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obs)
+           mjd = getMJD(t, "tt")
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (65)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(t)
+           mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+           CALL NEW(t, mjd, "tt")   
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (70)", 1)
+              STOP
+           END IF
+        ELSE
+           CALL NULLIFY(t)
+           t = copy(epoch)
+        END IF
+        CALL setParameters(storb, &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step, &
+             outlier_rejection=outlier_rejection_prm, &
+             outlier_multiplier=outlier_multiplier_prm, &
+             t_inv=t, &
+             element_type=element_type_comp_prm, &
+             accept_multiplier=accwin_multiplier, &
+             cos_gaussian=cos_gaussian, &
+             cos_nsigma=cos_nsigma, &
+             cos_norb=cos_norb, &
+             cos_ntrial=cos_ntrial)
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (80)", 1)
+           STOP
+        END IF
+        CALL propagate(storb, t)
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "TRACE BACK (90)", 1)
+           STOP
+        END IF
+        CALL covarianceSampling(storb)
+        IF (error) THEN
+           CALL errorMessage("oorb / covariance_sampling", &
+                "Covariance sampling failed:", 1)
+           IF (err_verb >= 1) THEN
+              WRITE(stderr,"(3A,1X,I0)") "ID: ", TRIM(id), &
+                   " and number of observations: ", nobs
+           END IF
+           error  = .FALSE.
+           CALL NEW(out_file, "problematic_observation_sets" // "." // &
+                TRIM(observation_format_out))
+           CALL setPositionAppend(out_file)
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out))
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (125)", 1)
+              STOP
+           END IF
+        ELSE
+
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Covariance sampling for object", &
+                   TRIM(id), "is ready."
+           END IF
+
+           IF (pp_H_estimation) THEN
+              IF (info_verb >= 2) THEN
+                 WRITE(stdout,"(1X,A)") "Computing HG parameters..."
+              END IF
+              CALL NEW(physparam, storb)
+              IF (pp_G > 99.0_bp) THEN
+                 CALL estimateHAndG(physparam, obss_sep(i))
+              ELSE
+                 CALL estimateHAndG(physparam, obss_sep(i), &
+                      input_G=pp_G, input_delta_G=pp_G_unc)
+              END IF
+              HG_arr_in => getH0Distribution(physparam)
+              HG_arr_storb_in(i,:,1:2) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              HG_arr_in => getGDistribution(physparam)
+              HG_arr_storb_in(i,:,3:4) = HG_arr_in
+              DEALLOCATE(HG_arr_in)
+              CALL NULLIFY(physparam)
+              IF (info_verb >= 2) THEN
+                 WRITE(stdout,"(1X,A)") "Computing HG parameters... done"
+              END IF
+           END IF
+
+           CALL NEW(out_file, TRIM(id) // ".cos")
+           CALL OPEN(out_file)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (150)", 1)
+              STOP
+           END IF
+           ! WRITE OBSERVATIONS:
+           CALL writeObservationFile(obss_sep(i), getUnit(out_file), &
+                TRIM(observation_format_out)) 
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (155)", 1)
+              STOP
+           END IF
+           WRITE(getUnit(out_file),"(A)") "#" 
+!!$           ! WRITE COVARIANCE_SAMPLING PARAMETERS
+!!$           CALL writeCOSResults(storb, obss_sep(i), getUnit(out_file))
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / covariance_sampling", &
+!!$                   "TRACE BACK (160)", 1)
+!!$              STOP
+!!$           END IF
+           CALL NULLIFY(out_file) 
+!!$           CALL getResults(storb, sor_rho_cmp=sor_rho_cmp)
+!!$           IF (error) THEN
+!!$              CALL errorMessage("oorb / covariance_sampling", &
+!!$                   "TRACE BACK (170)", 1)
+!!$              STOP
+!!$           END IF
+           ! WRITE ORBITAL-ELEMENT PDF
+           orb_arr_cmp => getSampleOrbits(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling ", &
+                   "TRACE BACK (175)", 1)
+              STOP
+           END IF
+           pdf_arr_cmp => getPDFValues(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling ", &
+                   "TRACE BACK (180)", 1)
+              STOP
+           END IF
+           rchi2_arr_cmp => getReducedChi2Distribution(storb)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling ", &
+                   "TRACE BACK (185)", 1)
+              STOP
+           END IF
+           CALL getResults(storb, &
+                reg_apr_arr=reg_apr_arr_cmp, &
+                jac_arr=jac_arr_cmp)
+           IF (error) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "TRACE BACK (190)", 1)
+              STOP
+           END IF
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "TRACE BACK (200)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+           DO j=1,SIZE(orb_arr_cmp,dim=1)
+              IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=j==1, &
+                      element_type_out=element_type_out_prm, &
+                      id=id, &
+                      orb=orb_arr_cmp(j), &
+                      element_type_pdf=element_type_comp_prm, &
+                      pdf=pdf_arr_cmp(j), &
+                      rchi2=rchi2_arr_cmp(j), &
+                      reg_apr=reg_apr_arr_cmp(j), &
+                      jac_sph_inv=jac_arr_cmp(j,1), &
+                      jac_car_kep=jac_arr_cmp(j,2), &
+                      jac_equ_kep=jac_arr_cmp(j,3), &
+                      H=HG_arr_in(j,1), &
+                      G=HG_arr_in(j,3), &
+                      mjd=mjd_epoch)
+              ELSE
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      TRIM(orbit_format_out) // &
+                      " format not yet supported for Covariance_sampling output.", 1)
+                 STOP                 
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling ", &
+                      "TRACE BACK (205)", 1)
+                 STOP
+              END IF
+           END DO
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id) // ".orb")
+              END IF
+           END IF
+           ! WRITE RESIDUALS
+           IF (write_residuals) THEN
+              CALL NEW(out_file, TRIM(out_fname) // ".res")
+              CALL setPositionAppend(out_file)
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "TRACE BACK (225)", 1)
+                 STOP
+              END IF
+              CALL writeResiduals(storb, obss_sep(i), getUnit(out_file))
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "TRACE BACK (230)", 1)
+                 STOP
+              END IF
+              CALL NULLIFY(out_file)
+           END IF
+           IF (plot_results) THEN
+              CALL toString(dt, str, error, frmt="(F10.2)")
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling ", &
+                      "TRACE BACK (235)", 1)
+                 STOP
+              END IF
+              str = TRIM(id) // "_"// TRIM(str)
+              CALL makeResidualStamps(storb, obss_sep(i), TRIM(str) // &
+                   "_cos_residual_stamps.eps")
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "TRACE BACK (240)", 1)
+                 STOP
+              END IF
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_cos_residual_stamps.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_cos_residual_stamps.eps* &")
+              END IF
+              ALLOCATE(elements_arr(SIZE(orb_arr_cmp,dim=1),7), stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "Could not allocate memory (3).", 1)
+                 STOP
+              END IF
+              CALL NEW(tmp_file, TRIM(str)// "_cos_orbits.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling ", &
+                      "TRACE BACK (250)", 1)
+                 STOP
+              END IF
+              DO j=1,SIZE(orb_arr_cmp,dim=1)
+                 IF (element_type_comp_prm == "cartesian") THEN
+                    CALL rotateToEcliptic(orb_arr_cmp(j))
+                 END IF
+                 elements_arr(j,1:6) = getElements(orb_arr_cmp(j), element_type_comp_prm)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / covariance_sampling", &
+                         "TRACE BACK (255)", 1)
+                    STOP
+                 END IF
+                 IF (element_type_comp_prm == "keplerian") THEN
+                    elements_arr(j,3:6) = elements_arr(j,3:6)/rad_deg
+                 END IF
+                 elements_arr(j,7) = pdf_arr_cmp(j)
+                 t = getTime(orb_arr_cmp(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / covariance_sampling ", &
+                         "TRACE BACK (260)", 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file),"(7(E23.15,1X),A)") &
+                      elements_arr(j,1:6), &
+                      pdf_arr_cmp(j), &
+                      getCalendarDateString(t,"tdt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / covariance_sampling ", &
+                         "TRACE BACK (265)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(t)
+              END DO
+              CALL NULLIFY(tmp_file)
+              CALL NEW(tmp_file, TRIM(str) // &
+                   "_cos_sample_standard_deviations.out")
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling ", &
+                      "TRACE BACK (275)", 1)
+                 STOP
+              END IF
+              WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                   advance="no") &
+                   getObservationalTimespan(obss_sep(i))
+              IF (error) THEN
+                 CALL errorMessage("oorb / covariance_sampling ", &
+                      "TRACE BACK (280)", 1)
+                 STOP
+              END IF
+              DO j=1,6
+                 CALL moments(elements_arr(:,j), &
+                      pdf=pdf_arr_cmp, std_dev=stdev, errstr=errstr)
+                 IF (LEN_TRIM(errstr) /= 0) THEN
+                    CALL errorMessage("oorb / covariance_sampling", &
+                         "Could not compute moments. " // TRIM(errstr), 1)
+                    STOP
+                 END IF
+                 WRITE(getUnit(tmp_file), "(F22.15,1X)", &
+                      advance="no") stdev
+              END DO
+              WRITE(getUnit(tmp_file),*)
+              CALL NULLIFY(tmp_file)
+              DEALLOCATE(elements_arr, stat=err)
+              IF (err /= 0) THEN
+                 CALL errorMessage("oorb / covariance_sampling", &
+                      "Could not deallocate memory (5).", 1)
+                 STOP
+              END IF
+              ! Make plot using gnuplot:
+              CALL system("cp " // TRIM(str) // &
+                   "_cos_orbits.out cos_orbits.out")
+              IF (element_type_comp_prm == "cartesian") THEN
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/cos_plot_car.gp")
+              ELSE
+                 CALL system("gnuplot " // TRIM(gnuplot_scripts_dir) // "/cos_plot_kep.gp")
+              END IF
+              CALL system("cp cos_results.eps " // TRIM(str) // &
+                   "_cos_" // TRIM(element_type_comp_prm) // &
+                   "_results.eps")
+              CALL system("rm -f cos_orbits.out cos_results.eps " // & 
+                   TRIM(str) // "_cos_orbits.out " // TRIM(str) // &
+                   "_cos_sample_standard_deviations.out")
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(str) // "_cos_" // &
+                      TRIM(element_type_comp_prm) // "_results.eps")
+              END IF
+              IF (plot_open) THEN
+                 CALL system("gv " // TRIM(str) // "_cos_" // &
+                      TRIM(element_type_comp_prm) // &
+                      "_results.eps* &")
+              END IF
+           END IF
+           DO j=1,SIZE(orb_arr_cmp)
+              CALL NULLIFY(orb_arr_cmp(j))
+           END DO
+           DEALLOCATE(orb_arr_cmp, stat=err)
+           DEALLOCATE(pdf_arr_cmp, stat=err)
+           DEALLOCATE(rchi2_arr_cmp, stat=err)
+           DEALLOCATE(reg_apr_arr_cmp, stat=err)
+           DEALLOCATE(jac_arr_cmp, stat=err)
+           IF (err /= 0) THEN
+              CALL errorMessage("oorb / covariance_sampling", &
+                   "Could not deallocate memory (10).", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obss_sep(i))
+           IF (info_verb >= 2) THEN
+              WRITE(stdout,"(3(1X,A))") "Object", &
+                   TRIM(id), "successfully processed."
+           END IF
+        END IF
+        CALL NULLIFY(storb)
+        CALL NULLIFY(orb)
+        IF (info_verb >= 2) THEN
+           WRITE(stdout,*)
+           WRITE(stdout,*)
+        END IF
+        IF (ASSOCIATED(HG_arr_in)) THEN
+           DEALLOCATE(HG_arr_in, stat=err)
+        END IF
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep, stat=err)
+     IF (err /= 0) THEN
+        CALL errorMessage("oorb / covariance_sampling", &
+             "Could not deallocate memory (15).", 1)
+        STOP
+     END IF
+
+
+  CASE ("propagation")
+
+     first = .TRUE.
+
+     CALL NULLIFY(epoch1)
+     IF (get_cl_option("--epoch-mjd-tt=", .FALSE.)) THEN
+        ! New epoch given as MJD TT
+        mjd_tt = get_cl_option("--epoch-mjd-tt=", 0.0_bp)
+        CALL NEW(epoch1, mjd_tt, "TT")
+        IF (error) THEN
+           CALL errorMessage("oorb / propagation", &
+                "TRACE BACK (5)", 1)
+           STOP
+        END IF
+     ELSE IF (get_cl_option("--epoch-mjd-utc=", .FALSE.)) THEN
+        mjd_utc = get_cl_option("--epoch-mjd-utc=", 0.0_bp)
+        ! New epoch given as MJD UTC
+        CALL NEW(epoch1, mjd_utc, "UTC")
+        IF (error) THEN
+           CALL errorMessage("oorb / propagation", &
+                "TRACE BACK (10)", 1)
+           STOP
+        END IF
+     END IF
+
+     IF (.NOT.exist(epoch1) .AND. &
+          .NOT.get_cl_option("--delta-epoch-mjd=", .FALSE.) .AND. &
+          .NOT.exist(obss_in)) THEN
+        CALL errorMessage("oorb / propagation", &
+             "No epoch specified (5).", 1)
+        STOP
+     END IF
+
+     first = .TRUE.
+     IF (ALLOCATED(storb_arr_in)) THEN
+        ! Input orbits contain uncertainty information.
+
+        DO i=1,SIZE(storb_arr_in)
+
+           separately_ = separately
+
+           IF (.NOT.exist(epoch1) .AND. &
+                .NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.)) .AND. & 
+                get_cl_option("--delta-epoch-mjd=", .FALSE.)) THEN
+              ! New epoch relative to current epoch of orbit 
+              dt = get_cl_option("--delta-epoch-mjd=", 0.0_bp)
+              epoch1 = getTime(storb_arr_in(i))
+              mjd_tt = getMJD(epoch1, "TT")
+              CALL NULLIFY(epoch1)
+              CALL NEW(epoch1, mjd_tt + dt, "TT")
+           ELSE IF (.NOT.exist(epoch1) .AND. &
+                .NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.) .OR. & 
+                get_cl_option("--delta-epoch-mjd=", .FALSE.)) .AND. &
+                ASSOCIATED(obss_sep)) THEN
+              ! New epoch relative to observations...
+              DO j=1,SIZE(obss_sep)
+                 IF (id_arr_storb_in(i) == getID(obss_sep(j))) THEN
+                    EXIT
+                 END IF
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (20)", 1)
+                    STOP
+                 END IF
+              END DO
+              IF (get_cl_option("--last-observation-date", .FALSE.)) THEN
+                 ! New epoch equal to last observation date
+                 obs = getObservation(obss_sep(j),getNrOfObservations(obss_sep(j)))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (25)", 1)
+                    STOP
+                 END IF
+                 epoch1 = getTime(obs)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (30)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(obs)                 
+              ELSE
+                 ! New epoch equal to observational mid-date
+                 dt = getObservationalTimespan(obss_sep(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (35)", 1)
+                    STOP
+                 END IF
+                 obs = getObservation(obss_sep(j),1)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (40)", 1)
+                    STOP
+                 END IF
+                 epoch1 = getTime(obs)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (45)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(obs)
+                 mjd = getMJD(epoch1, "tt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (50)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(epoch1)
+                 mjd = mjd + dt/2.0_bp
+                 CALL NEW(epoch1, mjd, "tt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (55)", 1)
+                    STOP
+                 END IF
+              END IF
+           ELSE IF (.NOT.exist(epoch1)) THEN
+              CALL errorMessage("oorb / propagation", &
+                   "No epoch specified (10).", 1)
+              STOP              
+           END IF
+           epoch0 = getTime(storb_arr_in(i))
+           mjd0 = getMJD(epoch0, "TT")
+           mjd = mjd0
+           mjd1 = getMJD(epoch1, "TT")
+
+           ! How frequently should the elements be reported? Default is to
+           ! only report them for the last epoch (output_interval < 0).
+           output_interval = get_cl_option("--output-interval-days=", -1.0_bp)
+           IF (output_interval > 0.0_bp .AND. output_interval >= integration_step) THEN
+              output_interval = SIGN(output_interval,mjd1-mjd0)
+           ELSE IF (output_interval > 0.0_bp .AND. output_interval < integration_step) THEN
+              integration_step = output_interval
+              output_interval = SIGN(output_interval,mjd1-mjd0)
+           ELSE
+              output_interval = mjd1 - mjd0
+           END IF
+
+           ! Set integration parameters
+           CALL setParameters(storb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / propagation", &
+                   "TRACE BACK (15)", 1)
+              STOP
+           END IF
+
+           IF (separately) THEN
+              CALL NEW(out_file, TRIM(id_arr_storb_in(i)) // ".orb")
+              CALL OPEN(out_file)
+              IF (error) THEN
+                 CALL errorMessage("oorb / propagation", &
+                      "TRACE BACK (85)", 1)
+                 STOP
+              END IF
+              lu_orb_out = getUnit(out_file)
+           END IF
+
+           ! Loop over the integration interval and output
+           ! intermediate results during each step if requested
+           DO WHILE ((output_interval > 0.0_bp .AND. mjd < mjd1) .OR. &
+                (output_interval < 0.0_bp .AND. mjd > mjd1))
+
+              IF ((output_interval > 0.0_bp .AND. mjd + output_interval >= mjd1) .OR. &
+                   (output_interval < 0.0_bp .AND. mjd + output_interval <= mjd1)) THEN
+                 mjd = mjd1
+              ELSE
+                 mjd = mjd + output_interval
+              END IF
+              CALL NEW(epoch, mjd, "TT")
+
+
+              ! Propagate orbital-element pdf from one epoch (=input) to another:
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 CALL propagate(storb_arr_in(i), epoch, encounters=encounters)
+              ELSE
+                 CALL propagate(storb_arr_in(i), epoch)
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / propagation", &
+                      "TRACE BACK (60)", 1)
+                 STOP
+              END IF
+
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 CALL getCalendarDate(epoch0, "TT", year0, month0, day0)
+                 CALL getCalendarDate(epoch, "TT", year1, month1, day1)
+                 WRITE(stderr,'(A)') ""
+                 WRITE(stderr,'(A,I0,A,I0,A,F0.5,A,I0,A,I0,A,F0.5,A)') &
+                      "Planetary encounters by object " // TRIM(id_arr_storb_in(i)) // &
+                      " between ", year0, "-", month0, "-", day0, " and ", &
+                      year1, "-", month1, "-", day1, ":"
+                 DO j=1,SIZE(encounters,dim=1)
+                    WRITE(stderr,'(A,I0,A)') "Orbit #", j, ":"
+                    DO k=1,SIZE(encounters,dim=2)
+                       IF (encounters(j,k,2) < 1.1_bp) THEN
+                          WRITE(stderr,'(A22,1X,A7,1X,A6,1X,F12.6,1X,A,1X,F0.6,1X,A)') &
+                               "!! I-M-P-A-C-T !! with", planetary_locations(k), &
+                               "at MJD", encounters(j,k,1), "TT given a stepsize of", &
+                               encounters(j,k,4), "days."
+                       ELSE
+                          WRITE(stderr,'(A22,1X,A7,1X,A6,1X,F12.6,1X,A,1X,F11.8,1X,A,1X,F0.6,1X,A)') &
+                               "Closest encounter with", planetary_locations(k), &
+                               "at MJD", encounters(j,k,1), &
+                               "TT at a distance of", encounters(j,k,3), &
+                               "AU given a stepsize of", encounters(j,k,4), "days."
+                       END IF
+                    END DO
+                 END DO
+              END IF
+              DEALLOCATE(encounters, stat=err)
+              CALL NULLIFY(epoch0)
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 epoch0 = copy(epoch)
+              END IF
+              CALL NULLIFY(epoch)
+
+              IF (containsSampledPDF(storb_arr_in(i))) THEN
+                 ! Sampled orbital-element pdf:
+                 orb_arr_cmp => getSampleOrbits(storb_arr_in(i))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation ", &
+                         "TRACE BACK (65)", 1)
+                    STOP
+                 END IF
+                 pdf_arr_cmp => getPDFValues(storb_arr_in(i))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation ", &
+                         "TRACE BACK (70)", 1)
+                    STOP
+                 END IF
+                 rchi2_arr_cmp => getReducedChi2Distribution(storb_arr_in(i))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation ", &
+                         "TRACE BACK (75)", 1)
+                    STOP
+                 END IF
+                 CALL getResults(storb_arr_in(i), &
+                      reg_apr_arr=reg_apr_arr_cmp, &
+                      jac_arr=jac_arr_cmp)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation ", &
+                         "TRACE BACK (80)", 1)
+                    STOP
+                 END IF
+                 DO j=1,SIZE(orb_arr_cmp,dim=1)
+                    IF (orbit_format_out == "orb") THEN
+                       CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                            print_header=first.OR.separately_, &
+                            element_type_out=element_type_out_prm, &
+                            id=id_arr_storb_in(i), &
+                            orb=orb_arr_cmp(j), &
+                            element_type_pdf=element_type_comp_prm, &
+                            pdf=pdf_arr_cmp(j), &
+                            rchi2=rchi2_arr_cmp(j), &
+                            reg_apr=reg_apr_arr_cmp(j), &
+                            jac_sph_inv=jac_arr_cmp(j,1), &
+                            jac_car_kep=jac_arr_cmp(j,2), &
+                            jac_equ_kep=jac_arr_cmp(j,3), &
+                            H=HG_arr_storb_in(i,j,1), &
+                            G=HG_arr_storb_in(i,j,3), &
+                            mjd=mjd_epoch)
+                    ELSE IF (orbit_format_out == "des") THEN
+                       CALL errorMessage("oorb / propagation", &
+                            "DES format not yet supported for propagation of sampled pdfs.", 1)
+                       STOP                 
+                    END IF
+                    IF (error) THEN
+                       CALL errorMessage("oorb / propagation ", &
+                            "TRACE BACK (90)", 1)
+                       STOP
+                    END IF
+                    CALL NULLIFY(orb_arr_cmp(j))
+                    first = .FALSE.
+                    separately_ = .FALSE.
+                 END DO
+                 DEALLOCATE(orb_arr_cmp, pdf_arr_cmp, rchi2_arr_cmp, &
+                      reg_apr_arr_cmp, jac_arr_cmp)
+              ELSE
+                 ! LSL orbit:
+                 orb = getNominalOrbit(storb_arr_in(i))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (95)", 1)
+                    STOP
+                 END IF
+                 cov = getCovarianceMatrix(storb_arr_in(i), element_type_out_prm, "ecliptic")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (100)", 1)
+                    STOP
+                 END IF
+                 IF (orbit_format_out == "orb") THEN
+                    CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                         print_header=first.OR.separately_, &
+                         element_type_out=element_type_out_prm, &
+                         id=id_arr_storb_in(i), &
+                         orb=orb, &
+                         cov=cov, &
+                         H=HG_arr_storb_in(i,1,1), &
+                         G=HG_arr_storb_in(i,1,3), &
+                         mjd=mjd_epoch)
+                 ELSE IF (orbit_format_out == "des") THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "DES format not yet supported for propagation of covariance matrices.", 1)
+                    STOP                 
+                 END IF
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (110)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(orb)
+                 first = .FALSE.
+                 separately_ = .FALSE.
+              END IF
+
+           END DO
+
+           IF (separately) THEN
+              CALL NULLIFY(out_file)
+              IF (compress) THEN
+                 CALL system("gzip -f " // TRIM(id_arr_storb_in(i)) // ".orb")
+              END IF
+           END IF
+
+           IF (.NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.))) THEN
+              CALL NULLIFY(epoch1)
+           END IF
+
+        END DO
+
+     ELSE
+
+        IF (exist(obss_in)) THEN
+           obss_sep => getSeparatedSets(obss_in)
+           IF (error) THEN
+              CALL errorMessage("oorb / propagation", &
+                   "TRACE BACK (115)", 1)
+              STOP
+           END IF
+           CALL NULLIFY(obss_in)
+        END IF
+
+        dt = get_cl_option("--delta-epoch-mjd=", 0.0_bp)
+
+        IF (info_verb >= 2) THEN
+           WRITE(stderr,"(A,1X,I0,1X,A)") "Integrating", &
+                SIZE(orb_arr_in), "particles."
+        END IF
+        DO i=1,SIZE(orb_arr_in)
+           IF (.NOT.exist(epoch1) .AND. &
+                .NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.)) .AND. & 
+                get_cl_option("--delta-epoch-mjd=", .FALSE.)) THEN
+              ! New epoch relative to current epoch of orbit 
+              dt = get_cl_option("--delta-epoch-mjd=", 0.0_bp)
+              epoch1 = getTime(orb_arr_in(i))
+              mjd_tt = getMJD(epoch1, "TT")
+              CALL NULLIFY(epoch1)
+              CALL NEW(epoch1, mjd_tt + dt, "TT")
+           ELSE IF (.NOT.exist(epoch1) .AND. &
+                .NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.) .OR. & 
+                get_cl_option("--delta-epoch-mjd=", .FALSE.)) .AND. &
+                ASSOCIATED(obss_sep)) THEN
+              ! New epoch relative to observations...
+              DO j=1,SIZE(obss_sep)
+                 IF (id_arr_in(i) == getID(obss_sep(j))) THEN
+                    EXIT
+                 END IF
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (125)", 1)
+                    STOP
+                 END IF
+              END DO
+              IF (get_cl_option("--last-observation-date", .FALSE.)) THEN
+                 ! New epoch equal to last observation date
+                 obs = getObservation(obss_sep(j),getNrOfObservations(obss_sep(j)))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (130)", 1)
+                    STOP
+                 END IF
+                 epoch1 = getTime(obs)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (135)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(obs)                 
+              ELSE
+                 ! New epoch equal to observational mid-date
+                 dt = getObservationalTimespan(obss_sep(j))
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (140)", 1)
+                    STOP
+                 END IF
+                 obs = getObservation(obss_sep(j),1)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (145)", 1)
+                    STOP
+                 END IF
+                 epoch1 = getTime(obs)
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (150)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(obs)
+                 mjd = getMJD(epoch1, "tt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (155)", 1)
+                    STOP
+                 END IF
+                 CALL NULLIFY(epoch1)
+                 mjd = mjd + dt/2.0_bp
+                 CALL NEW(epoch1, mjd, "tt")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / propagation", &
+                         "TRACE BACK (160)", 1)
+                    STOP
+                 END IF
+              END IF
+           ELSE IF (.NOT.exist(epoch1)) THEN
+              CALL errorMessage("oorb / propagation", &
+                   "No epoch specified (15).", 1)
+              STOP              
+           END IF
+           epoch0 = getTime(orb_arr_in(i))
+           mjd0 = getMJD(epoch0, "TT")
+           mjd = mjd0
+           mjd1 = getMJD(epoch1, "TT")
+
+           ! How frequently should the elements be reported? Default is to
+           ! only report them for the last epoch (output_interval < 0).
+           output_interval = get_cl_option("--output-interval-days=", -1.0_bp)
+           IF (output_interval > 0.0_bp .AND. output_interval >= integration_step) THEN
+              output_interval = SIGN(output_interval,mjd1-mjd0)
+           ELSE IF (output_interval > 0.0_bp .AND. output_interval < integration_step) THEN
+              integration_step = output_interval
+              output_interval = SIGN(output_interval,mjd1-mjd0)
+           ELSE
+              output_interval = mjd1 - mjd0
+           END IF
+
+           ! Set integration parameters
+           CALL setParameters(orb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / propagation", &
+                   "TRACE BACK (120)", 1)
+              STOP
+           END IF
+
+           ! Loop over the integration interval and output
+           ! intermediate results during each step if requested
+           first = .TRUE. ! cycle at least once for printing purposes
+           DO WHILE (first .OR. &
+                (output_interval > 0.0_bp .AND. mjd < mjd1) .OR. &
+                (output_interval < 0.0_bp .AND. mjd > mjd1))
+
+              first = .FALSE.
+              IF ((output_interval > 0.0_bp .AND. mjd + output_interval >= mjd1) .OR. &
+                   (output_interval < 0.0_bp .AND. mjd + output_interval <= mjd1)) THEN
+                 mjd = mjd1
+              ELSE
+                 mjd = mjd + output_interval
+              END IF
+              CALL NEW(epoch, mjd, "TT")
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 CALL propagate(orb_arr_in(i), epoch, encounters=encounters)
+              ELSE
+                 CALL propagate(orb_arr_in(i), epoch)
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / propagation", &
+                      "TRACE BACK (165)", 1)
+                 STOP
+              END IF
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 CALL getCalendarDate(epoch0, "TT", year0, month0, day0)
+                 CALL getCalendarDate(epoch, "TT", year1, month1, day1)
+                 WRITE(stderr,'(A)') ""
+                 WRITE(stderr,'(A,I0,A,I0,A,I0,A,F0.5,A,I0,A,I0,A,F0.5,A)') &
+                      "Planetary encounters by object " // TRIM(id_arr_in(i)) // &
+                      " (orbit #", i, ") between ", year0, "-", month0, &
+                      "-", day0, " and ", year1, "-", month1, "-", day1, ":"
+                 DO j=1,SIZE(encounters,dim=2)
+                    IF (encounters(1,j,2) < 1.1_bp) THEN
+                       WRITE(stderr,'(A22,1X,A7,1X,A6,1X,F12.6,1X,A,1X,F0.6,1X,A)') &
+                            "!! I-M-P-A-C-T !! with", planetary_locations(j), &
+                            "at MJD", encounters(1,j,1), "TT given a stepsize of", &
+                            encounters(1,j,4), "days."
+                    ELSE
+                       WRITE(stderr,'(A22,1X,A7,1X,A6,1X,F12.6,1X,A,1X,F11.8,1X,A,1X,F0.6,1X,A)') &
+                            "Closest encounter with", planetary_locations(j), &
+                            "at MJD", encounters(1,j,1), "TT at a distance of", &
+                            encounters(1,j,3), "AU given a stepsize of", encounters(1,j,4), "days."
+                    END IF
+                 END DO
+              END IF
+              DEALLOCATE(encounters, stat=err)
+              CALL NULLIFY(epoch0)
+              IF (info_verb >= 2 .AND. dyn_model /= "2-body") THEN
+                 epoch0 = copy(epoch)
+              END IF
+              CALL NULLIFY(epoch)
+
+              IF (orbit_format_out == "des") THEN
+                 CALL writeDESOrbitFile(lu_orb_out, & 
+                      first, element_type_out_prm, &
+                      id_arr_in(i), orb_arr_in(i), HG_arr_in(i,1), &
+                      1, 6, -1.0_bp, "OPENORB")
+              ELSE IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=first, &
+                      element_type_out=element_type_out_prm, &
+                      id=TRIM(id_arr_in(i)), orb=orb_arr_in(i), &
+                      H=HG_arr_in(i,1), G=HG_arr_in(i,3), &
+                      mjd=mjd_epoch)
+              END IF
+              IF (error) THEN
+                 CALL errorMessage("oorb / propagation", &
+                      "TRACE BACK (170) " // TRIM(id_arr_in(i)), 1)
+                 STOP              
+              END IF
+              first = .FALSE.
+
+           END DO
+
+           IF (.NOT.(get_cl_option("--epoch-mjd-tt=", .FALSE.) .OR. &
+                get_cl_option("--epoch-mjd-utc=", .FALSE.))) THEN
+              CALL NULLIFY(epoch1)
+           END IF
+
+        END DO
+
+     END IF
+
+
+  CASE ("credible_region")
+
+     probability_mass = get_cl_option("--probability_mass=", 0.9973_bp)
+
+     force_pdf = get_cl_option("--force_pdf", .FALSE.)
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+        ! Input orbits contain uncertainty information.
+
+        first = .TRUE.
+        DO i=1,SIZE(storb_arr_in)
+
+           orb_arr => getSampleOrbits(storb_arr_in(i), probability_mass, force_pdf=force_pdf)
+
+           DO j=1,SIZE(orb_arr)
+              IF (orbit_format_out == "des") THEN
+                 CALL writeDESOrbitFile(lu_orb_out, & 
+                      first, element_type_out_prm, &
+                      id_arr_storb_in(i), orb_arr(j), HG_arr_storb_in(i,j,1), &
+                      1, 6, -1.0_bp, "OPENORB")
+              ELSE IF (orbit_format_out == "orb") THEN
+                 CALL writeOpenOrbOrbitFile(lu_orb_out, &
+                      print_header=first, &
+                      element_type_out=element_type_out_prm, &
+                      id=TRIM(id_arr_storb_in(i)), orb=orb_arr(j), &
+                      H=HG_arr_storb_in(i,j,1), G=HG_arr_storb_in(i,j,3), &
+                      mjd=mjd_epoch)
+              END IF
+              first = .FALSE.
+              CALL NULLIFY(orb_arr(j))
+           END DO
+
+           DEALLOCATE(orb_arr)
+
+        END DO
+
+     ELSE
+        CALL errorMessage("oorb / credible_region", &
+             "Cannot compute credible region due to lack of uncertainty information", 1)
+        STOP
+     END IF
+
+  CASE ("ephemeris")
+
+     ! Input observatory code
+     obsy_code = get_cl_option("--code=", obsy_code)
+
+     ! Input evolutionary timespan [days]
+     timespan = get_cl_option("--timespan=", 0.0_bp)
+
+     ! Input time step [days]
+     step = get_cl_option("--step=", 1.0_bp)
+     IF (step == 0.0_bp) THEN
+        nstep = 1        
+     ELSE
+        step = SIGN(ABS(step),timespan)
+        IF (ABS(timespan) > 10.0_bp*EPSILON(timespan) .AND. &
+             ABS(timespan) < ABS(step)) THEN
+           step = timespan
+        END IF
+        nstep = NINT(timespan/step) + 1
+     END IF
+     integration_step = MIN(ABS(step),integration_step)
+
+     CALL NEW(obsies)
+     IF (error) THEN
+        CALL errorMessage('oorb / ephemeris', &
+             'TRACE BACK (5)',1)
+        STOP
+     END IF
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+        ! Input orbits contain uncertainty information.
+
+        DO i=1,SIZE(storb_arr_in)
+
+           ! Use equatorial coordinates:
+           CALL toCartesian(storb_arr_in(i), "equatorial")
+
+           IF (exist(obss_in)) THEN
+              observers => getObservatoryCCoords(obss_in)
+              DO j=1,SIZE(observers)
+                 CALL rotateToEquatorial(observers(j))
+              END DO
+              obsy_code_arr => getObservatoryCodes(obss_in)
+           ELSE
+              t = getTime(storb_arr_in(i))
+              mjd_tt = getMJD(t, "TT")
+              CALL NULLIFY(t)
+              ALLOCATE(observers(nstep), obsy_code_arr(nstep))
+              DO j=1,nstep
+                 CALL NEW(t, mjd_tt+(j-1)*step, "TT")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / ephemeris", &
+                         "TRACE BACK (10)", 1)
+                    STOP
+                 END IF
+                 obsy_code_arr(j) = obsy_code
+                 ! Compute heliocentric observatory coordinates
+                 observers(j) = getObservatoryCCoord(obsies, obsy_code_arr(j), t)
+                 IF (error) THEN
+                    CALL errorMessage('oorb / ephemeris', &
+                         'TRACE BACK (15)',1)
+                    STOP
+                 END IF
+                 CALL rotateToEquatorial(observers(j))
+                 CALL NULLIFY(t)
+              END DO
+           END IF
+
+           ! Set integration parameters
+           CALL setParameters(storb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / ephemeris", &
+                   "TRACE BACK (20)", 1)
+              STOP
+           END IF
+
+           ! Compute topocentric ephemerides
+           CALL getEphemerides(storb_arr_in(i), observers, ephemerides_arr, &
+                cov_arr=cov_arr, pdfs_arr=pdfs_arr)
+           IF (error) THEN
+              CALL errorMessage('oorb / ephemeris', &
+                   'TRACE BACK (25)',1)
+              STOP
+           END IF
+
+           ! Prepare output file
+           IF (separately) THEN
+              CALL NEW(tmp_file, TRIM(id_arr_storb_in(i)) // ".eph")
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (25)',1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (30)',1)
+                 STOP
+              END IF
+              lu = getUnit(tmp_file)
+           ELSE
+              lu = stdout
+           END IF
+           IF (separately .OR. i == 1) THEN
+              IF (containsSampledPDF(storb_arr_in(1))) THEN
+                 WRITE(lu,"(A,A11,5X,9(1X,A18))") "#", "Designation  ", &
+                      "Observatory_code ", "MJD_UTC  ", "Delta  ", "RA  ", &
+                      "Dec  ", "dDelta/dt  ", "dRA/dt  ", "dDec/dt  ", "PDF_value  "
+              ELSE
+                 WRITE(lu,"(A,A11,5X,29(1X,A18))") "#", "Designation  ", &
+                      "Observatory_code ", "MJD_UTC  ", "Delta  ", "RA  ", "Dec  ", &
+                      "dDelta/dt  ", "dRA/dt  ", "dDec/dt  ", "Delta_unc  ", &
+                      "RA_unc  ", "Dec_unc  ", "dDelta/dt_unc  ", "dRA/dt_unc  ", &
+                      "dDec/dt_unc  ", "cor(Delta,RA)  ", "cor(Delta,Dec)  ", &
+                      "cor(Delta,dDelta)  ", "cor(Delta,dRA)  ", &
+                      "cor(Delta,dDec)  ", "cor(RA,Dec)  ", &
+                      "cor(RA,dDelta)  ", "cor(RA,dRA)  ", &
+                      "cor(RA,dDec)  ", "cor(Dec,dDelta)  ", &
+                      "cor(Dec,dRA)  ", "cor(Dec,dDec)  ", &
+                      "cor(dDelta,dRA)  ", "cor(dDelta,dDec)  ", &
+                      "cor(dRA,dDec)  "
+              END IF
+           END IF
+
+           ! Loop over time steps:
+           DO j=1,SIZE(observers)
+              t = getTime(observers(j))
+              mjd_utc = getMJD(t, "UTC")
+              CALL NULLIFY(t)
+              IF (containsSampledPDF(storb_arr_in(i))) THEN
+                 ! Input orbits correspond to one or more sampled pdfs.
+                 ! Loop over sampled orbits:
+                 DO k=1,SIZE(ephemerides_arr,dim=1)
+                    ! Make sure that the ephemeris is equatorial:
+                    CALL rotateToEquatorial(ephemerides_arr(k,j))
+                    coordinates = getCoordinates(ephemerides_arr(k,j))
+                    WRITE(lu,"(2(A18,1X),7(F18.10,1X),E18.10)") &
+                         TRIM(id_arr_storb_in(i)), TRIM(obsy_code_arr(j)), &
+                         mjd_utc, coordinates(1), &
+                         coordinates(2:3)/rad_deg, coordinates(4), &
+                         coordinates(5:6)/rad_deg, pdfs_arr(k,j)
+                    CALL NULLIFY(ephemerides_arr(k,j))
+                 END DO
+              ELSE
+                 ! Input orbits correspond to one or more single-point estimates of the pdf.
+                 ! Make sure that the ephemeris is equatorial:
+                 CALL rotateToEquatorial(ephemerides_arr(1,j))
+                 coordinates = getCoordinates(ephemerides_arr(1,j))
+                 DO k=1,6
+                    stdev_arr(k) = SQRT(cov_arr(k,k,j)) 
+                 END DO
+                 DO k=1,6
+                    DO l=1,6
+                       corr(k,l) = cov_arr(k,l,j) / &
+                            (stdev_arr(k)*stdev_arr(l))
+                    END DO
+                 END DO
+                 WRITE(lu,"(2(A18,1X),28(F18.10,1X))") TRIM(id_arr_storb_in(i)), &
+                      TRIM(obsy_code_arr(j)), mjd_utc, coordinates(1), &
+                      coordinates(2:3)/rad_deg, coordinates(4), &
+                      coordinates(5:6)/rad_deg, stdev_arr(1), &
+                      stdev_arr(2:3)/rad_deg, stdev_arr(4), &
+                      stdev_arr(5:6)/rad_deg, corr(1,2:6), &
+                      corr(2,3:6), corr(3,4:6), corr(4,5:6), corr(5,6)
+                 CALL NULLIFY(ephemerides_arr(1,j))
+              END IF
+           END DO
+           DEALLOCATE(ephemerides_arr)
+           IF (ASSOCIATED(pdfs_arr)) THEN
+              DEALLOCATE(pdfs_arr)
+           END IF
+           IF (ASSOCIATED(cov_arr)) THEN
+              DEALLOCATE(cov_arr)
+           END IF
+           CALL NULLIFY(storb_arr_in(i))
+           IF (separately) THEN
+              CALL NULLIFY(tmp_file)
+           END IF
+        END DO
+        DEALLOCATE(storb_arr_in, observers)
+
+     ELSE
+
+        IF (exist(obss_in)) THEN
+           obss_sep => getSeparatedSets(obss_in)           
+           id_arr => getObjects(obss_in)
+        ELSE
+           obss_sep => NULL()
+        END IF
+
+        DO i=1,norb
+
+           IF (ASSOCIATED(obss_sep)) THEN
+              k = -1
+              DO j=1,SIZE(id_arr)
+                 IF (TRIM(id_arr_in(i)) == TRIM(id_arr(j))) THEN
+                    k = j
+                    EXIT
+                 END IF
+              END DO
+              IF (k < 0) THEN
+                 IF (err_verb >= 1) THEN
+                    WRITE(stderr,*) "WARNING: Observations for object " // &
+                         TRIM(id_arr_in(i)) // " not found..."
+                 END IF
+                 CYCLE
+              END IF
+              observers => getObservatoryCCoords(obss_sep(k))
+              IF (info_verb >= 3) THEN
+                 WRITE(stdout,"(9(1X,A17))") "GEO2OBSY X [KM]", &
+                      "GEO2OBSY Y [KM]", "GEO2OBSY Z [KM]", &
+                      "HELIO2GEO X [AU]", "HELIO2GEO Y [AU]", &
+                      "HELIO2GEO Z [AU]", "HELIO2OBSY X [AU]", &
+                      "HELIO2OBSY Y [AU]", "HELIO2OBSY Z [AU]" 
+                 DO j=1,SIZE(observers)
+                    CALL rotateToEcliptic(observers(j))
+                    obsy_pos = getPosition(observers(j))
+                    t = getTime(observers(j))
+                    ccoord = getObservatoryCCoord(obsies,"500",t)
+                    CALL rotateToEcliptic(ccoord)
+                    pos = getPosition(ccoord)
+                    geoc_obsy = obsy_pos - pos
+                    WRITE(stdout,"(3(1X,F17.5),6(1X,F17.13))") &
+                         geoc_obsy*km_au, pos, obsy_pos
+                 END DO
+              END IF
+              DO j=1,SIZE(observers)
+                 CALL rotateToEquatorial(observers(j))
+              END DO
+              obsy_code_arr => getObservatoryCodes(obss_sep(k))
+              CALL NULLIFY(obss_sep(k))
+           ELSE
+              t = getTime(orb_arr_in(i))
+              mjd_tt = getMJD(t, "TT")
+              ALLOCATE(observers(nstep), obsy_code_arr(nstep))
+              DO j=1,nstep
+                 obsy_code_arr(j) = obsy_code
+                 ! Compute heliocentric observatory coordinates
+                 observers(j) = getObservatoryCCoord(obsies, obsy_code_arr(j), t)
+                 IF (error) THEN
+                    CALL errorMessage('oorb / ephemeris', &
+                         'TRACE BACK (10)',1)
+                    STOP
+                 END IF
+                 CALL rotateToEquatorial(observers(j))
+                 CALL NULLIFY(t)
+                 CALL NEW(t, mjd_tt+j*step, "TT")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / ephemeris", &
+                         "TRACE BACK (15)", 1)
+                    STOP
+                 END IF
+              END DO
+           END IF
+
+           ! Set integration parameters
+           CALL setParameters(orb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / ephemeris", &
+                   "TRACE BACK (15)", 1)
+              STOP
+           END IF
+
+           ! Compute topocentric ephemerides
+           CALL getEphemerides(orb_arr_in(i), observers, ephemerides, &
+                this_lt_corr_arr=orb_lt_corr_arr)
+           IF (error) THEN
+              CALL errorMessage('oorb / ephemeris', &
+                   'TRACE BACK (20)',1)
+              STOP
+           END IF
+
+           IF (separately) THEN
+              CALL NEW(tmp_file, TRIM(id_arr_in(i)) // ".eph")
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (25)',1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (30)',1)
+                 STOP
+              END IF
+              lu = getUnit(tmp_file)
+           ELSE
+              lu = stdout
+           END IF
+
+           IF (separately .OR. i == 1) THEN
+              WRITE(lu,'(A,A11,1X,A,1X,35(A18,1X))') "#", &
+                   "Designation", "Code", "MJD_UTC/UT1", "Delta", &
+                   "RA", "Dec", "dDelta/dt", "dRA/dt", "dDec/dt", &
+                   "VMag", "Alt", "Phase", "LunarElon", "LunarAlt", &
+                   "LunarPhase", "SolarElon", "SolarAlt", "r", &
+                   "HLon", "HLat", "TLon", "TLat", "TOCLon", &
+                   "TOCLat", "HOCLon", "HOCLat", "TOppLon", &
+                   "TOppLat", "HEclObj_X", "HEclObj_Y", "HEclObj_Z", &
+                   "HEclObj_dX/dt", "HEclObj_dY/dt", & 
+                   "HEclObj_dZ/dt", "HEclObsy_X", "HEclObsy_Y", &
+                   "HEclObsy_Z" 
+           END IF
+
+           DO j=1,SIZE(observers)
+
+              t = getTime(observers(j))
+              mjd_tt = getMJD(t, "TT")
+              err_verb_ = err_verb
+              err_verb = 0
+              mjd_utc = getMJD(t, "UTC")
+              err_verb = err_verb_
+              IF (error) THEN
+                 error = .FALSE.
+                 mjd_utc = getMJD(t, "UT1")
+                 IF (error) THEN
+                    CALL errorMessage('oorb / ephemeris', &
+                         'TRACE BACK (30)',1)
+                    STOP
+                 END IF
+              END IF
+
+              ! Extract topocentic equatorial coordinates
+              CALL rotateToEquatorial(ephemerides(j))        
+              comp_coord = getCoordinates(ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (35)',1)
+                 STOP
+              END IF
+              Delta = comp_coord(1)
+              ra = comp_coord(2)
+              dec = comp_coord(3)
+
+              ! Extract instantaneous topocentric equatorial sky
+              ! motions (for coordinate motions, divide sky dra by
+              ! cos(dec), ie remove cos(comp_coord(3)))
+              dDelta = comp_coord(4)
+              dra = comp_coord(5)*COS(comp_coord(3))
+              ddec = comp_coord(6)
+
+              ! Extract topocentric ecliptic lon and lat
+              CALL rotateToEcliptic(ephemerides(j))        
+              comp_coord = getCoordinates(ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (40)',1)
+                 STOP
+              END IF
+              tlon = comp_coord(2)
+              tlat = comp_coord(3)
+
+              ! Compute topocentric opposition coordinates (actually,
+              ! get heliocentric observatory coordinates)
+              scoord = getSCoord(observers(j))
+              CALL rotateToEcliptic(scoord)
+              pos_opp = getPosition(scoord)
+              opplon = pos_opp(2)
+              opplat = pos_opp(3)
+              CALL NULLIFY(scoord)
+
+              ! Compute opposition-centered topocentric ecliptic coordinates
+              toclon = tlon - opplon
+              toclat = tlat - opplat
+              IF (toclon > pi) THEN
+                 toclon = toclon - two_pi
+              ELSE IF (toclon < -pi) THEN
+                 toclon = toclon + two_pi
+              END IF
+
+              ! Extract heliocentric ecliptic lon and lat
+              ccoord = getCCoord(orb_lt_corr_arr(j), "ecliptic")
+              scoord = getSCoord(ccoord)
+              comp_coord = getCoordinates(scoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (45)',1)
+                 STOP
+              END IF
+              hlon = comp_coord(2)
+              hlat = comp_coord(3)
+              CALL NULLIFY(ccoord)
+              CALL NULLIFY(scoord)
+
+              ! Compute opposition-centered topocentric ecliptic coordinates
+              hoclon = hlon - opplon
+              hoclat = hlat - opplat
+              IF (hoclon > pi) THEN
+                 hoclon = hoclon - two_pi
+              ELSE IF (hoclon < -pi) THEN
+                 hoclon = hoclon + two_pi
+              END IF
+
+              ! Compute phase angle
+              CALL NEW(ccoord, ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (50)',1)
+                 STOP
+              END IF
+              CALL rotateToEquatorial(ccoord)
+              obsy_obj = getPosition(ccoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (55)',1)
+                 STOP
+              END IF
+              ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+              CALL toCartesian(orb_lt_corr_arr(j), frame='equatorial')
+              pos = getPosition(orb_lt_corr_arr(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (60)',1)
+                 STOP
+              END IF
+              heliocentric_r2 = DOT_PRODUCT(pos,pos)
+              obsy_pos = getPosition(observers(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (65)',1)
+                 STOP
+              END IF
+              observer_r2 = DOT_PRODUCT(obsy_pos,obsy_pos)
+              cos_obj_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+                   observer_r2) / SQRT(heliocentric_r2 * ephemeris_r2)
+              obj_phase = ACOS(cos_obj_phase)
+
+              ! Compute apparent brightness:
+              ! Input slope parameter
+              G_value = get_cl_option("--G=", HG_arr_in(i,3))
+              obj_vmag = getApparentMagnitude(H=HG_arr_in(i,1), &
+                   G=G_value, r=SQRT(heliocentric_r2), &
+                   Delta=Delta, phase_angle=obj_phase)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (70)',1)
+                 STOP
+              END IF
+
+              ! Compute (approximate) altitude of the target
+              obsy_ccoord = getGeocentricObservatoryCCoord(obsies, obsy_code_arr(j), t)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (75)',1)
+                 STOP
+              END IF
+              CALL rotateToEquatorial(obsy_ccoord)
+              geoc_obsy = getPosition(obsy_ccoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (80)',1)
+                 STOP
+              END IF
+              vec3 = cross_product(geoc_obsy,obsy_obj)
+              obj_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_obj))
+
+              ! Compute (approximate) altitude of the Sun
+              ! Position of the geocenter as seen from the Sun:
+              planeph => JPL_ephemeris(mjd_tt, 3, 11, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (85)',1)
+                 STOP
+              END IF
+              ! Position of the Sun as seen from the observatory:
+              obsy_sun = -(planeph(1,1:3) + geoc_obsy)
+              DEALLOCATE(planeph)
+              vec3 = cross_product(geoc_obsy,obsy_sun)
+              solar_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_sun))
+              ! Compute the solar elongation:
+              vec3 = cross_product(obsy_obj,obsy_sun)
+              solar_elongation = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_sun))
+
+              ! Compute phase of the Moon:
+              ! Position of the geocenter as seen from the Moon:
+              planeph => JPL_ephemeris(mjd_tt, 3, 10, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (90)',1)
+                 STOP
+              END IF
+              ! Position of the Moon as seen from the observatory:
+              obsy_moon = -(planeph(1,1:3) + geoc_obsy)
+              DEALLOCATE(planeph)
+              ! Position of the Sun as seen from the Moon:
+              planeph => JPL_ephemeris(mjd_tt, 10, 11, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (95)',1)
+                 STOP
+              END IF
+              sun_moon = planeph(1,1:3)
+              DEALLOCATE(planeph)
+              obsy_moon_r2 = DOT_PRODUCT(obsy_moon,obsy_moon)
+              sun_moon_r2 = DOT_PRODUCT(sun_moon,sun_moon)
+              cos_obj_phase = 0.5_bp * (sun_moon_r2 + obsy_moon_r2 - &
+                   observer_r2) / (SQRT(sun_moon_r2) * &
+                   SQRT(obsy_moon_r2))
+              lunar_phase = (pi-ACOS(cos_obj_phase))/pi
+              ! Compute (approximate) distance between the target and the Moon:
+              vec3 = cross_product(obsy_obj,obsy_moon)
+              lunar_elongation = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_moon))
+              ! Compute (approximate) altitude of the Moon:
+              vec3 = cross_product(geoc_obsy,obsy_moon)
+              lunar_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_moon))
+
+              ! Extract heliocentric distance
+              hdist = SQRT(heliocentric_r2)
+
+              ! Extract heliocentric ecliptic cartesian coordinates for the object
+              h_ecl_car_coord_obj = getElements(orb_lt_corr_arr(j), "cartesian", "ecliptic")
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (90)',1)
+                 STOP
+              END IF
+
+              ! Extract heliocentric ecliptic cartesian coordinates for the observer
+              CALL rotateToEcliptic(observers(j))
+              h_ecl_car_coord_obsy = getCoordinates(observers(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / ephemeris', &
+                      'TRACE BACK (95)',1)
+                 STOP
+              END IF
+
+              CALL NULLIFY(observers(j))
+              CALL NULLIFY(ephemerides(j))
+              CALL NULLIFY(orb_lt_corr_arr(j))
+              CALL NULLIFY(ccoord)
+              CALL NULLIFY(obsy_ccoord)
+
+              ra = ra/rad_deg
+              dec = dec/rad_deg
+              dDelta = dDelta
+              dra = dra/rad_deg
+              ddec = ddec/rad_deg
+              obj_alt = obj_alt/rad_deg
+              obj_phase = obj_phase/rad_deg
+              lunar_elongation = lunar_elongation/rad_deg
+              lunar_alt = lunar_alt/rad_deg
+              solar_elongation = solar_elongation/rad_deg
+              solar_alt = solar_alt/rad_deg
+              tlon = tlon/rad_deg
+              tlat = tlat/rad_deg
+              toclon = toclon/rad_deg
+              toclat = toclat/rad_deg
+              hlon = hlon/rad_deg
+              hlat = hlat/rad_deg
+              hoclon = hoclon/rad_deg
+              hoclat = hoclat/rad_deg
+              opplon = opplon/rad_deg
+              opplat = opplat/rad_deg
+
+              WRITE(lu,'(2(A,1X),35(F18.10,1X))') &
+                   id_arr_in(i), TRIM(obsy_code_arr(j)), mjd_utc, Delta, &
+                   ra, dec, dDelta, dra, ddec, obj_vmag, obj_alt, &
+                   obj_phase, lunar_elongation, lunar_alt, &
+                   lunar_phase, solar_elongation, solar_alt, hdist, &
+                   hlon, hlat, tlon, tlat, toclon, toclat, hoclon, &
+                   hoclat, opplon, opplat, h_ecl_car_coord_obj, &
+                   h_ecl_car_coord_obsy(1:3)
+
+           END DO
+
+           IF (separately) THEN
+              CALL NULLIFY(tmp_file)
+           END IF
+           DEALLOCATE(observers, ephemerides, orb_lt_corr_arr, &
+                obsy_code_arr, stat=err)
+
+        END DO
+
+        IF (ASSOCIATED(obss_sep)) THEN
+           first = .TRUE.
+           DO i=1,SIZE(obss_sep)
+              IF (exist(obss_sep(i))) THEN
+                 IF (first) THEN
+                    WRITE(stderr,"(A)") "Orbit missing for the following observation set(s):"
+                    first = .FALSE.
+                 END IF
+                 WRITE(stderr,"(A)") TRIM(id_arr(i))
+              END IF
+           END DO
+        END IF
+
+     END IF
+
+
+  CASE ("classification")
+
+     ! Compute probability for an object with the input
+     ! orbital-element pdf to belong to a group of asteroids. Caveat:
+     ! an, ap, M are not currently taken into account, that is,
+     ! e.g. Jupiter Trojans not correctly accounted for.
+
+     IF (.NOT.ALLOCATED(storb_arr_in)) THEN
+        CALL errorMessage("oorb / classification", &
+             "Input orbits do not contain uncertainty " // &
+             "information required for this task.", 1)        
+        STOP
+     END IF
+
+     ! Write header
+     WRITE(stdout,"(A2,3X,A12,9X,A6,7X,A12)") "# ", &
+          "Designation", "Group", "Probability"
+
+     ! Compute probabilities for each object
+     DO i=1,SIZE(storb_arr_in)
+        IF (.NOT.containsSampledPDF(storb_arr_in(i))) THEN
+           CALL errorMessage("oorb / classification", &
+                "Input orbits do not contain sampled " // &
+                "uncertainty information required for this task.", 1)        
+           STOP
+        END IF
+        ! Propagate input orbital-element pdf to Keplerian-element pdf:
+        CALL toKeplerian(storb_arr_in(i))
+        ! Compute weights for each class that has been defined:
+        CALL getGroupWeights(storb_arr_in(i), weight_arr, group_name_arr)
+        ! Write output
+        DO j=1,SIZE(weight_arr)
+           WRITE(stdout,"(3X,A16,1X,A18,1X,F12.7)") TRIM(id_arr_storb_in(i)), &
+                group_name_arr(j), weight_arr(j)
+        END DO
+        WRITE(stdout,*)
+        DEALLOCATE(group_name_arr, weight_arr)
+        CALL NULLIFY(storb_arr_in(i))
+     END DO
+     DEALLOCATE(storb_arr_in, id_arr_storb_in)
+
+  CASE ("classification_apriori")
+
+     ! Compute probability for an object with the input
+     ! orbital-element pdf to belong to a group of asteroids. Caveat:
+     ! an, ap, M are not currently taken into account, that is,
+     ! e.g. Jupiter Trojans not correctly accounted for.
+
+     IF (.NOT.ALLOCATED(storb_arr_in)) THEN
+        CALL errorMessage("oorb / classification", &
+             "Input orbits do not contain uncertainty " // &
+             "information required for this task.", 1)        
+        STOP
+     END IF
+
+     ! Write header
+     WRITE(stdout,"(A2,3X,A12,9X,A6,7X,A12)") "# ", &
+          "Designation", "Group", "Probability"
+
+     ! Compute probabilities for each object
+     DO i=1,SIZE(storb_arr_in)
+        IF (.NOT.containsSampledPDF(storb_arr_in(i))) THEN
+           CALL errorMessage("oorb / classification", &
+                "Input orbits do not contain sampled " // &
+                "uncertainty information required for this task.", 1)        
+           STOP
+        END IF
+        ! Propagate input orbital-element pdf to Keplerian-element pdf:
+        CALL toKeplerian(storb_arr_in(i))
+        ! Compute weights for each class that has been defined:
+        CALL getGroupWeights(storb_arr_in(i), weight_arr, group_name_arr)
+        weight_arr(5) = weight_arr(5)*35.0_bp
+        !weight_arr(6:SIZE(weight_arr)-1) = weight_arr(6:SIZE(weight_arr)-1)*400.0_bp
+        weight_arr(6:10) = weight_arr(6:10)*500.0_bp
+        weight_arr = weight_arr/SUM(weight_arr)
+        ! Write output
+        DO j=1,SIZE(weight_arr)
+           WRITE(stdout,"(3X,A16,1X,A18,1X,F12.7)") TRIM(id_arr_storb_in(i)), &
+                group_name_arr(j), weight_arr(j)
+        END DO
+        WRITE(stdout,*)
+        DEALLOCATE(group_name_arr, weight_arr)
+        CALL NULLIFY(storb_arr_in(i))
+     END DO
+     DEALLOCATE(storb_arr_in, id_arr_storb_in)
+
+  CASE ("ephemeris_planets")
+
+     IF (get_cl_option("--epoch-mjd-tt=", .FALSE.)) THEN
+        ! Epoch given as MJD TT
+        mjd_tt = get_cl_option("--epoch-mjd-tt=", 0.0_bp)
+     ELSE IF (get_cl_option("--epoch-mjd-utc=", .FALSE.)) THEN
+        mjd_utc = get_cl_option("--epoch-mjd-utc=", 0.0_bp)
+        ! Epoch given as MJD UTC
+        CALL NEW(epoch, mjd_utc, "UTC")
+        IF (error) THEN
+           CALL errorMessage("oorb / propagation", &
+                "TRACE BACK (10)", 1)
+           STOP
+        END IF
+        mjd_tt = getMJD(epoch, "TT")
+        CALL NULLIFY(epoch)
+     END IF
+     CALL NEW(epoch, mjd_tt, "TT")
+
+     planeph => JPL_ephemeris(mjd_tt, -10, 11, error)
+     DO i=1,SIZE(planeph,dim=1)
+        CALL NEW(ccoord, planeph(i,:), "equatorial", epoch)
+        CALL rotateToEcliptic(ccoord)
+        coordinates = getCoordinates(ccoord)
+        CALL NULLIFY(ccoord)
+        WRITE(stdout,"(A,9(1X,E25.18))") TRIM(planetary_locations(i)), &
+             coordinates, 2400000.5_bp+mjd_tt, planetary_masses(i), &
+             planetary_densities(i)/kgm3_smau3/1000.0_bp
+     END DO
+     DEALLOCATE(planeph)
+
+     ! JPL_ephemeris PRODUCES BOGUS RESULTS FOR EMB 
+     !planeph => JPL_ephemeris(mjd_tt, 13, 11, error)
+     !call new(ccoord, planeph(1,:), "equatorial", epoch)
+     !call rotateToEcliptic(ccoord)
+     !coordinates = getCoordinates(ccoord)
+     !call nullify(ccoord)
+     !write(stdout,"(A,6(1X,F20.15))") trim(planetary_locations(13)), coordinates
+     !deallocate(planeph)
+
+  CASE ("tisserand_parameters")
+
+     ! Compute Tisserand's parameter(s) for input orbit(s)
+     IF (ALLOCATED(storb_arr_in)) THEN
+        WRITE(stdout,*) "--task=tisserand_parameters is not yet implemented for orbit PDFs."
+     ELSE
+        DO i=1,SIZE(orb_arr_in)
+           tisserands_parameters = getTisserandsParameters(orb_arr_in(i))
+           WRITE(stdout,*) TRIM(id_arr_in(i)), tisserands_parameters 
+        END DO
+     END IF
+
+
+  CASE ("jacobi_constants")
+
+     ! Compute Jacobi constants for input orbit(s)
+     IF (ALLOCATED(storb_arr_in)) THEN
+        WRITE(stdout,*) "--task=jacobi_constants is not yet implemented for orbit PDFs."
+     ELSE
+        DO i=1,SIZE(orb_arr_in)
+           jacobi_constants = getJacobiConstants(orb_arr_in(i))
+           WRITE(stdout,"(A,10(1X,F10.5))") TRIM(id_arr_in(i)), jacobi_constants
+        END DO
+     END IF
+
+
+  CASE ("apoapsis_distance")
+
+     ! Compute apoapsis distance(s) for input orbit(s)
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)
+           CALL getApoapsisDistance(storb_arr_in(i), apoapsis_distance_pdf)
+           IF (containsSampledPDF(storb_arr_in(i))) THEN
+              DO j=1,SIZE(apoapsis_distance_pdf,dim=1)
+                 WRITE(stdout,*) apoapsis_distance_pdf(j,:) 
+              END DO
+           ELSE
+              WRITE(stdout,*) apoapsis_distance_pdf(1,:) 
+           END IF
+           DEALLOCATE(apoapsis_distance_pdf)
+        END DO
+     ELSE
+        DO i=1,SIZE(orb_arr_in)
+           CALL getApoapsisDistance(orb_arr_in(i), apoapsis_distance)
+           WRITE(stdout,*) apoapsis_distance 
+        END DO
+     END IF
+
+
+  CASE ("periapsis_distance")
+
+     ! Compute periapsis distance(s) for input orbit(s)
+     IF (ALLOCATED(storb_arr_in)) THEN
+        DO i=1,SIZE(storb_arr_in)
+           CALL getPeriapsisDistance(storb_arr_in(i), periapsis_distance_pdf)
+           IF (containsSampledPDF(storb_arr_in(i))) THEN
+              DO j=1,SIZE(periapsis_distance_pdf,dim=1)
+                 WRITE(stdout,*) periapsis_distance_pdf(j,:) 
+              END DO
+           ELSE
+              WRITE(stdout,*) periapsis_distance_pdf(1,:) 
+           END IF
+           DEALLOCATE(periapsis_distance_pdf)
+        END DO
+     ELSE
+        DO i=1,SIZE(orb_arr_in)
+           CALL getPeriapsisDistance(orb_arr_in(i), periapsis_distance)
+           WRITE(stdout,*) periapsis_distance 
+        END DO
+     END IF
+
+
+  CASE ("moid")
+
+     ! Compute Earth MOID (w/o uncertainty) for input orbits and write
+     ! a DES orbit file with the results.
+
+     DO i=1,SIZE(orb_arr_in)
+        elements = getElements(orb_arr_in(i), "cometary")
+        IF (elements(2) > 1.0_bp) THEN
+           ! MOID for hyperbolic orbits currently not computed...
+           moid = -1.0_bp
+        ELSE
+           err_verb_ = err_verb 
+           err_verb = 0
+           ! Epoch of the asteroid orbit:
+           epoch = getTime(orb_arr_in(i))
+           mjd_tt = getMJD(epoch, "TT")
+           ! Earth's osculating elements for the epoch of the asteroid orbit:
+           planeph => JPL_ephemeris(mjd_tt, 3, 11, error)
+           CALL NEW(ref_orb, planeph(1,:), "cartesian", "equatorial", epoch)
+           ! MOID between Earth and asteroid orbits:
+           moid = getMOID(orb_arr_in(i), ref_orb)
+           CALL NULLIFY(epoch)
+           CALL NULLIFY(ref_orb)
+           DEALLOCATE(planeph, stat=err)
+           err_verb = err_verb_
+           IF (error) THEN
+              moid = -1.0_bp
+              error = .FALSE.
+           END IF
+        END IF
+        IF (orbit_format_out == "des") THEN
+           CALL writeDESOrbitFile(lu_orb_out, i==1, element_type_out_prm, &
+                id_arr_in(i), orb_arr_in(i), HG_arr_in(i,1), 1, 6, &
+                moid, "OPENORB")
+        ELSE IF (orbit_format_out == "orb") THEN
+           CALL writeOpenOrbOrbitFile(lu_orb_out, print_header=i==1, &
+                element_type_out=element_type_out_prm, &
+                id=TRIM(id_arr_in(i)), orb=orb_arr_in(i), &
+                H=HG_arr_in(i,1), G=HG_arr_in(i,3), &
+                mjd=mjd_epoch)
+        END IF
+        IF (error) THEN
+           WRITE(stderr,*) i
+           error = .FALSE.
+        END IF
+     END DO
+     CALL NULLIFY(orb_out_file)
+
+
+  CASE ("obsplanner")
+
+     ! Input observatory code
+     obsy_code = get_cl_option("--code=", obsy_code)
+     !write(*,*) obsy_code
+     ! Input evolutionary timespan [days]
+     timespan = get_cl_option("--timespan=", 0.0_bp)
+
+     ! Input time step [days]
+     step = get_cl_option("--step=", 1.0_bp)
+     IF (step == 0.0_bp) THEN
+        nstep = 1        
+     ELSE
+        step = SIGN(ABS(step),timespan)
+        IF (ABS(timespan) > 10.0_bp*EPSILON(timespan) .AND. &
+             ABS(timespan) < ABS(step)) THEN
+           step = timespan
+        END IF
+        nstep = NINT(timespan/step) + 1
+     END IF
+     integration_step = MIN(ABS(step),integration_step)
+
+     ! Input how long the requirements have to be fulfilled each night
+     dt_fulfill_night = get_cl_option("--timespan-fulfill-night=", 0.05_bp)
+     minstep = MAX(1,CEILING(dt_fulfill_night/step))
+     ALLOCATE(temp_arr(minstep,35))
+
+     ! Input minimum altitude for object (wrt the horizon)
+     obj_alt_min = get_cl_option("--object-altitude-min=", 30.0_bp)
+     obj_alt_min = obj_alt_min*rad_deg
+
+     ! Input maximum apparent magnitude (minimum brightness) for object
+     obj_vmag_max = get_cl_option("--object-magnitude-max=", HUGE(obj_vmag_max))
+
+     ! Input maximum altitude for Sun
+     solar_alt_max = get_cl_option("--solar-altitude-max=", -18.0_bp)
+     solar_alt_max = solar_alt_max*rad_deg
+
+     ! Input maximum solar elongation
+     solar_elon_max = get_cl_option("--solar-elongation-max=", 180.0_bp)
+     solar_elon_max = solar_elon_max*rad_deg
+
+     ! Input minimum solar elongation
+     solar_elon_min = get_cl_option("--solar-elongation-min=", 45.0_bp)
+     solar_elon_min = solar_elon_min*rad_deg
+
+     ! Input maximum altitude for Moon
+     lunar_alt_max = get_cl_option("--lunar-altitude-max=", 90.0_bp)
+     lunar_alt_max = lunar_alt_max*rad_deg
+
+     ! Input minimum distance to Moon
+     lunar_elongation_min = get_cl_option("--lunar-elongation-min=", 45.0_bp)
+     lunar_elongation_min = lunar_elongation_min*rad_deg
+
+     ! Input minimum phase of Moon
+     lunar_phase_min = get_cl_option("--lunar-phase-min=", 0.0_bp)
+
+     ! Input maximum phase of Moon
+     lunar_phase_max = get_cl_option("--lunar-phase-max=", 1.0_bp)
+
+     CALL NEW(obsies)
+     IF (error) THEN
+        CALL errorMessage('oorb / obsplanner', &
+             'TRACE BACK (5)',1)
+        STOP
+     END IF
+
+     ! Write header
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+
+        CALL errorMessage("oorb / obsplanner", &
+             "storb option not available yet", 1)
+        STOP
+
+     ELSE
+
+        DO i=1,norb
+           t = getTime(orb_arr_in(i))
+           mjd_tt = getMJD(t, "TT")
+           ALLOCATE(observers(nstep))
+           DO j=1,nstep
+              ! Compute heliocentric observatory coordinates
+              observers(j) = getObservatoryCCoord(obsies, obsy_code, t)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (10)',1)
+                 STOP
+              END IF
+              CALL rotateToEquatorial(observers(j))
+              CALL NULLIFY(t)
+              CALL NEW(t, mjd_tt+j*step, "TT")
+              IF (error) THEN
+                 CALL errorMessage("oorb / obsplanner", &
+                      "TRACE BACK (15)", 1)
+                 STOP
+              END IF
+           END DO
+
+           ! Set integration parameters
+           CALL setParameters(orb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / obsplanner", &
+                   "TRACE BACK (15)", 1)
+              STOP
+           END IF
+
+           ! Compute topocentric ephemerides
+           CALL getEphemerides(orb_arr_in(i), observers, ephemerides, &
+                this_lt_corr_arr=orb_lt_corr_arr)
+           IF (error) THEN
+              CALL errorMessage('oorb / obsplanner', &
+                   'TRACE BACK (20)',1)
+              STOP
+           END IF
+
+           IF (separately) THEN
+              CALL NEW(tmp_file, TRIM(id_arr_in(i)) // ".eph")
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (25)',1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (30)',1)
+                 STOP
+              END IF
+              lu = getUnit(tmp_file)
+           ELSE
+              lu = stdout
+           END IF
+
+           IF (separately .OR. i == 1) THEN
+              WRITE(lu,'(A3,1X,A11,1X,A,1X,35(A18,1X))') "#RN", &
+                   "Designation", "Code", "MJD_UTC/UT1", "Delta", &
+                   "RA", "Dec", "dDelta/dt", "dRA/dt", "dDec/dt", &
+                   "VMag", "Alt", "Phase", "LunarElon", "LunarAlt", &
+                   "LunarPhase", "SolarElon", "SolarAlt", "r", &
+                   "HLon", "HLat", "TLon", "TLat", "TOCLon", &
+                   "TOCLat", "HOCLon", "HOCLat", "TOppLon", &
+                   "TOppLat", "HEclObj X", "HEclObj Y", "HEclObj Z", &
+                   "HEclObj dX/dt", "HEclObj dY/dt", & 
+                   "HEclObj dZ/dt", "HEclObsy X", "HEclObsy Y", &
+                   "HEclObsy Z" 
+           END IF
+
+           istep = 0
+           DO j=1,nstep
+
+              istep = istep + 1
+              t = getTime(observers(j))
+              mjd_tt = getMJD(t, "TT")
+              err_verb_ = err_verb
+              err_verb = 0
+              mjd_utc = getMJD(t, "UTC")
+              err_verb = err_verb_
+              IF (error) THEN
+                 error = .FALSE.
+                 mjd_utc = getMJD(t, "UT1")
+                 IF (error) THEN
+                    CALL errorMessage('oorb / obsplanner', &
+                         'TRACE BACK (30)',1)
+                    STOP
+                 END IF
+              END IF
+
+              ! Extract topocentic equatorial coordinates
+              CALL rotateToEquatorial(ephemerides(j))        
+              comp_coord = getCoordinates(ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (35)',1)
+                 STOP
+              END IF
+              Delta = comp_coord(1)
+              ra = comp_coord(2)
+              dec = comp_coord(3)
+
+              ! Extract instantaneous topocentric equatorial coordinate velocities
+              dDelta = comp_coord(4)
+              dra = comp_coord(5)*COS(comp_coord(3))
+              ddec = comp_coord(6)
+
+              ! Extract topocentric ecliptic lon and lat
+              CALL rotateToEcliptic(ephemerides(j))        
+              comp_coord = getCoordinates(ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (40)',1)
+                 STOP
+              END IF
+              tlon = comp_coord(2)
+              tlat = comp_coord(3)
+
+              ! Compute topocentric opposition coordinates (actually,
+              ! get heliocentric observatory coordinates)
+              scoord = getSCoord(observers(j))
+              CALL rotateToEcliptic(scoord)
+              pos_opp = getPosition(scoord)
+              opplon = pos_opp(2)
+              opplat = pos_opp(3)
+              CALL NULLIFY(scoord)
+
+              ! Compute opposition-centered topocentric ecliptic coordinates
+              toclon = tlon - opplon
+              toclat = tlat - opplat
+              IF (toclon > pi) THEN
+                 toclon = toclon - two_pi
+              ELSE IF (toclon < -pi) THEN
+                 toclon = toclon + two_pi
+              END IF
+
+              ! Extract heliocentric ecliptic lon and lat
+              ccoord = getCCoord(orb_lt_corr_arr(j), "ecliptic")
+              scoord = getSCoord(ccoord)
+              comp_coord = getCoordinates(scoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (45)',1)
+                 STOP
+              END IF
+              hlon = comp_coord(2)
+              hlat = comp_coord(3)
+              CALL NULLIFY(ccoord)
+              CALL NULLIFY(scoord)
+
+              ! Compute opposition-centered topocentric ecliptic coordinates
+              hoclon = hlon - opplon
+              hoclat = hlat - opplat
+              IF (hoclon > pi) THEN
+                 hoclon = hoclon - two_pi
+              ELSE IF (hoclon < -pi) THEN
+                 hoclon = hoclon + two_pi
+              END IF
+
+              ! Compute phase angle
+              CALL NEW(ccoord, ephemerides(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (50)',1)
+                 STOP
+              END IF
+              CALL rotateToEquatorial(ccoord)
+              obsy_obj = getPosition(ccoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (55)',1)
+                 STOP
+              END IF
+              ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+              CALL toCartesian(orb_lt_corr_arr(j), frame='equatorial')
+              pos = getPosition(orb_lt_corr_arr(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (60)',1)
+                 STOP
+              END IF
+              heliocentric_r2 = DOT_PRODUCT(pos,pos)
+              obsy_pos = getPosition(observers(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (65)',1)
+                 STOP
+              END IF
+              observer_r2 = DOT_PRODUCT(obsy_pos,obsy_pos)
+              cos_obj_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+                   observer_r2) / (SQRT(heliocentric_r2) * &
+                   SQRT(ephemeris_r2))
+              obj_phase = ACOS(cos_obj_phase)
+
+              ! Compute apparent brightness:
+              ! Input slope parameter
+              G_value = get_cl_option("--G=", HG_arr_in(i,3))
+              obj_vmag = getApparentMagnitude(H=HG_arr_in(i,1), &
+                   G=G_value, r=SQRT(heliocentric_r2), &
+                   Delta=Delta, phase_angle=obj_phase)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (70)',1)
+                 STOP
+              END IF
+              !write(*,*) "obj_vmag: ", obj_vmag
+              IF (obj_vmag > obj_vmag_max) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+
+              ! Compute (approximate) altitude of the target
+              obsy_ccoord = getGeocentricObservatoryCCoord(obsies, obsy_code, t)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (75)',1)
+                 STOP
+              END IF
+              CALL rotateToEquatorial(obsy_ccoord)
+              geoc_obsy = getPosition(obsy_ccoord)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (80)',1)
+                 STOP
+              END IF
+              vec3 = cross_product(geoc_obsy,obsy_obj)
+              obj_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_obj))
+              !write(*,*) "obj_alt: ", obj_alt/rad_deg
+              IF (obj_alt < obj_alt_min) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+
+              ! Compute (approximate) altitude of the Sun
+              ! Position of the geocenter as seen from the Sun:
+              planeph => JPL_ephemeris(mjd_tt, 3, 11, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (85)',1)
+                 STOP
+              END IF
+              ! Position of the Sun as seen from the observatory:
+              obsy_sun = -(planeph(1,1:3) + geoc_obsy)
+              DEALLOCATE(planeph)
+              vec3 = cross_product(geoc_obsy,obsy_sun)
+              solar_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_sun))
+              !write(*,*) "solar_alt: ", solar_alt/rad_deg
+              IF (solar_alt > solar_alt_max) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+              ! Compute the solar elongation:
+              vec3 = cross_product(obsy_obj,obsy_sun)
+              solar_elongation = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_sun))
+              !write(*,*) "solar_elongation: ", solar_elongation/rad_deg
+              IF (solar_elongation < solar_elon_min) THEN
+                 istep = 0
+                 CYCLE
+              ELSE IF (solar_elongation > solar_elon_max) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+
+              ! Compute phase of the Moon:
+              ! Position of the geocenter as seen from the Moon:
+              planeph => JPL_ephemeris(mjd_tt, 3, 10, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (90)',1)
+                 STOP
+              END IF
+              ! Position of the Moon as seen from the observatory:
+              obsy_moon = -(planeph(1,1:3) + geoc_obsy)
+              DEALLOCATE(planeph)
+              ! Position of the Sun as seen from the Moon:
+              planeph => JPL_ephemeris(mjd_tt, 10, 11, error)
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (95)',1)
+                 STOP
+              END IF
+              sun_moon = planeph(1,1:3)
+              DEALLOCATE(planeph)
+              obsy_moon_r2 = DOT_PRODUCT(obsy_moon,obsy_moon)
+              sun_moon_r2 = DOT_PRODUCT(sun_moon,sun_moon)
+              cos_obj_phase = 0.5_bp * (sun_moon_r2 + obsy_moon_r2 - &
+                   observer_r2) / (SQRT(sun_moon_r2) * &
+                   SQRT(obsy_moon_r2))
+              lunar_phase = (pi-ACOS(cos_obj_phase))/pi
+              IF (lunar_phase < lunar_phase_min) THEN
+                 istep = 0
+                 CYCLE
+              ELSE IF (lunar_phase > lunar_phase_max) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+              ! Compute (approximate) distance between the target and the Moon:
+              vec3 = cross_product(obsy_obj,obsy_moon)
+              lunar_elongation = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_moon))
+              !write(*,*) "lunar_elongation: ", lunar_elongation/rad_deg
+              IF (lunar_elongation < lunar_elongation_min) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+              ! Compute (approximate) altitude of the Moon:
+              vec3 = cross_product(geoc_obsy,obsy_moon)
+              lunar_alt = pi/2.0_bp - ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(geoc_obsy,obsy_moon))
+              !write(*,*) "lunar_alt: ", lunar_alt/rad_deg
+              IF (lunar_alt > lunar_alt_max) THEN
+                 istep = 0
+                 CYCLE
+              END IF
+
+              ! Extract heliocentric distance
+              hdist = SQRT(heliocentric_r2)
+
+              ! Extract heliocentric ecliptic cartesian coordinates for the object
+              h_ecl_car_coord_obj = getElements(orb_lt_corr_arr(j), "cartesian", "ecliptic")
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (90)',1)
+                 STOP
+              END IF
+
+              ! Extract heliocentric ecliptic cartesian coordinates for the observer
+              CALL rotateToEcliptic(observers(j))
+              h_ecl_car_coord_obsy = getCoordinates(observers(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / obsplanner', &
+                      'TRACE BACK (95)',1)
+                 STOP
+              END IF
+
+              CALL NULLIFY(observers(j))
+              CALL NULLIFY(ephemerides(j))
+              CALL NULLIFY(orb_lt_corr_arr(j))
+              CALL NULLIFY(ccoord)
+              CALL NULLIFY(obsy_ccoord)
+
+              ra = ra/rad_deg
+              dec = dec/rad_deg
+              dDelta = dDelta
+              dra = dra/rad_deg
+              ddec = ddec/rad_deg
+              obj_alt = obj_alt/rad_deg
+              obj_phase = obj_phase/rad_deg
+              lunar_elongation = lunar_elongation/rad_deg
+              lunar_alt = lunar_alt/rad_deg
+              solar_elongation = solar_elongation/rad_deg
+              solar_alt = solar_alt/rad_deg
+              tlon = tlon/rad_deg
+              tlat = tlat/rad_deg
+              toclon = toclon/rad_deg
+              toclat = toclat/rad_deg
+              hlon = hlon/rad_deg
+              hlat = hlat/rad_deg
+              hoclon = hoclon/rad_deg
+              hoclat = hoclat/rad_deg
+              opplon = opplon/rad_deg
+              opplat = opplat/rad_deg
+
+              IF (istep <= minstep) THEN
+                 temp_arr(istep,:) = &
+                      (/ mjd_utc, Delta, &
+                      ra, dec, dDelta, dra, ddec, obj_vmag, obj_alt, &
+                      obj_phase, lunar_elongation, lunar_alt, &
+                      lunar_phase, solar_elongation, solar_alt, hdist, &
+                      hlon, hlat, tlon, tlat, toclon, toclat, hoclon, &
+                      hoclat, opplon, opplat, h_ecl_car_coord_obj, &
+                      h_ecl_car_coord_obsy(1:3) /)
+              END IF
+
+              IF (istep == minstep) THEN
+                 DO k=1,istep
+                    WRITE(lu,'(I0,1X,2(A,1X),35(F18.10,1X))') &
+                         i, id_arr_in(i), TRIM(obsy_code), temp_arr(k,:)
+                 END DO
+              ELSE IF (istep > minstep) THEN
+                 WRITE(lu,'(I0,1X,2(A,1X),35(F18.10,1X))') &
+                      i, id_arr_in(i), TRIM(obsy_code), mjd_utc, Delta, &
+                      ra, dec, dDelta, dra, ddec, obj_vmag, obj_alt, &
+                      obj_phase, lunar_elongation, lunar_alt, &
+                      lunar_phase, solar_elongation, solar_alt, hdist, &
+                      hlon, hlat, tlon, tlat, toclon, toclat, hoclon, &
+                      hoclat, opplon, opplat, h_ecl_car_coord_obj, &
+                      h_ecl_car_coord_obsy(1:3)
+              END IF
+
+           END DO
+
+           IF (separately) THEN
+              CALL NULLIFY(tmp_file)
+           END IF
+           DEALLOCATE(observers, ephemerides, orb_lt_corr_arr)
+
+        END DO
+
+     END IF
+
+     DEALLOCATE(temp_arr)
+
+
+  CASE ("fou")
+
+     !! Produces a table with the quantities required for the
+     !! computation of the Figure of Urgency proposed for scheduling
+     !! follow-up observations with NEOSSat. The three key quantities
+     !! are the minimum solar elongation, the minimum apparent
+     !! brightness (max mag), and the 3-sigma (~equivalent) ephemeris
+     !! uncertainty.
+
+     ! Input observatory code
+     obsy_code = get_cl_option("--code=", obsy_code)
+
+     ! Input evolutionary timespan [days]
+     timespan = get_cl_option("--timespan=", 0.0_bp)
+
+     ! Input time step [days]
+     step = get_cl_option("--step=", 1.0_bp)
+     IF (step == 0.0_bp) THEN
+        nstep = 1        
+     ELSE
+        step = SIGN(ABS(step),timespan)
+        IF (ABS(timespan) > 10.0_bp*EPSILON(timespan) .AND. &
+             ABS(timespan) < ABS(step)) THEN
+           step = timespan
+        END IF
+        nstep = NINT(timespan/step) + 1
+     END IF
+     integration_step = MIN(ABS(step),integration_step)
+
+     CALL NEW(obsies)
+     IF (error) THEN
+        CALL errorMessage('oorb / fou', &
+             'TRACE BACK (5)',1)
+        STOP
+     END IF
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+        ! Input orbits contain uncertainty information.
+
+        DO i=1,SIZE(storb_arr_in)
+
+           ! Use equatorial coordinates:
+           CALL toCartesian(storb_arr_in(i), "equatorial")
+
+           IF (exist(obss_in)) THEN
+              observers => getObservatoryCCoords(obss_in)
+              DO j=1,SIZE(observers)
+                 CALL rotateToEquatorial(observers(j))
+              END DO
+              obsy_code_arr => getObservatoryCodes(obss_in)
+           ELSE
+              t = getTime(storb_arr_in(i))
+              mjd_tt = getMJD(t, "TT")
+              CALL NULLIFY(t)
+              ALLOCATE(observers(nstep), obsy_code_arr(nstep))
+              DO j=1,nstep
+                 CALL NEW(t, mjd_tt+(j-1)*step, "TT")
+                 IF (error) THEN
+                    CALL errorMessage("oorb / fou", &
+                         "TRACE BACK (10)", 1)
+                    STOP
+                 END IF
+                 obsy_code_arr(j) = obsy_code
+                 ! Compute heliocentric observatory coordinates
+                 observers(j) = getObservatoryCCoord(obsies, obsy_code_arr(j), t)
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (15)',1)
+                    STOP
+                 END IF
+                 CALL rotateToEquatorial(observers(j))
+                 CALL NULLIFY(t)
+              END DO
+           END IF
+
+           ! Set integration parameters
+           CALL setParameters(storb_arr_in(i), dyn_model=dyn_model, &
+                perturbers=perturbers, integrator=integrator, &
+                integration_step=integration_step)
+           IF (error) THEN
+              CALL errorMessage("oorb / fou", &
+                   "TRACE BACK (20)", 1)
+              STOP
+           END IF
+
+           ! Compute topocentric ephemerides
+           CALL getEphemerides(storb_arr_in(i), observers, ephemerides_arr, &
+                cov_arr=cov_arr, pdfs_arr=pdfs_arr, this_lt_corr_arr=orb_lt_corr_arr2)
+           IF (error) THEN
+              CALL errorMessage('oorb / fou', &
+                   'TRACE BACK (25)',1)
+              STOP
+           END IF
+
+           IF (separately) THEN
+              CALL NEW(tmp_file, TRIM(id_arr_storb_in(i)) // ".fou")
+              IF (error) THEN
+                 CALL errorMessage('oorb / fou', &
+                      'TRACE BACK (30)',1)
+                 STOP
+              END IF
+              CALL OPEN(tmp_file)
+              IF (error) THEN
+                 CALL errorMessage('oorb / fou', &
+                      'TRACE BACK (35)',1)
+                 STOP
+              END IF
+              lu = getUnit(tmp_file)
+           ELSE
+              lu = stdout
+           END IF
+
+           IF (separately .OR. i == 1) THEN
+              WRITE(lu,'(9(A,2X))') "#JD", "SolElon_min", &
+                   "SolElon_max", "VMag_max", "EELon", "ELat", &
+                   "EphWidth", "RA", "Dec"
+           END IF
+
+           ! Loop over time steps:
+           DO j=1,nstep
+
+              t = getTime(observers(j))
+              mjd_tt = getMJD(t, "TT")
+              mjd_utc = getMJD(t, "UTC")
+
+              obsy_pos = getPosition(observers(j))
+              IF (error) THEN
+                 CALL errorMessage('oorb / fou', &
+                      'TRACE BACK (40)',1)
+                 STOP
+              END IF
+              observer_r2 = DOT_PRODUCT(obsy_pos,obsy_pos)
+
+              obsy_ccoord = getObservatoryCCoord(obsies, obsy_code_arr(j), t)
+              IF (error) THEN
+                 CALL errorMessage('oorb / fou', &
+                      'TRACE BACK (45)',1)
+                 STOP
+              END IF
+              CALL rotateToEcliptic(obsy_ccoord)
+              sun_ccoord = opposite(obsy_ccoord)
+              CALL NULLIFY(obsy_ccoord)
+              obsy_sun = getPosition(sun_ccoord)
+
+              ! Compute topocentric coordinates for the Sun (actually,
+              ! get heliocentric observatory coordinates)
+              scoord = getSCoord(sun_ccoord)
+              CALL NULLIFY(sun_ccoord)
+              CALL rotateToEcliptic(scoord)
+              pos_sun = getPosition(scoord)
+              sunlon = pos_sun(2)
+              sunlat = pos_sun(3)
+              CALL NULLIFY(scoord)
+
+              IF (containsSampledPDF(storb_arr_in(i))) THEN
+
+                 ! Input orbits correspond to one or more sampled pdfs.
+                 ! Loop over sampled orbits:
+                 norb = SIZE(ephemerides_arr,dim=1)
+                 ALLOCATE(temp_arr(norb,6))
+                 DO k=1,norb
+
+                    ! RA & DEC
+                    CALL rotateToEquatorial(ephemerides_arr(k,j))        
+                    comp_coord = getCoordinates(ephemerides_arr(k,j))
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (50)',1)
+                       STOP
+                    END IF
+                    Delta = comp_coord(1)
+                    temp_arr(k,5:6) = comp_coord(2:3)
+
+                    ! Compute topocentric ecliptic coordinates
+                    ! relative to the Sun
+                    CALL rotateToEcliptic(ephemerides_arr(k,j))        
+                    comp_coord = getCoordinates(ephemerides_arr(k,j))
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (55)',1)
+                       STOP
+                    END IF
+                    tsclon = comp_coord(2) - sunlon
+                    tsclat = comp_coord(3) - sunlat
+                    IF (tsclon > pi) THEN
+                       tsclon = tsclon - two_pi
+                    ELSE IF (tsclon < -pi) THEN
+                       tsclon = tsclon + two_pi
+                    END IF
+                    temp_arr(k,1:2) = (/ tsclon, tsclat /)
+
+                    ! APPARENT BRIGHTNESS:
+                    ! Compute phase angle
+                    CALL NEW(ccoord, ephemerides_arr(k,j))
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (60)',1)
+                       STOP
+                    END IF
+                    CALL rotateToEcliptic(ccoord)
+                    obsy_obj = getPosition(ccoord)
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (65)',1)
+                       STOP
+                    END IF
+                    ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+                    CALL toCartesian(orb_lt_corr_arr2(k,j), frame='ecliptic')
+                    pos = getPosition(orb_lt_corr_arr2(k,j))
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (70)',1)
+                       STOP
+                    END IF
+                    heliocentric_r2 = DOT_PRODUCT(pos,pos)
+                    cos_obj_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+                         observer_r2) / (SQRT(heliocentric_r2) * &
+                         SQRT(ephemeris_r2))
+                    obj_phase = ACOS(cos_obj_phase)
+                    ! Input absolute magnitude
+                    H_value = get_cl_option("--H=", HG_arr_storb_in(i,k,1))
+                    ! Input slope parameter
+                    G_value = get_cl_option("--G=", HG_arr_storb_in(i,k,3))
+                    temp_arr(k,3) = getApparentMagnitude(H=H_value, &
+                         G=G_value, r=SQRT(heliocentric_r2), &
+                         Delta=Delta, phase_angle=obj_phase)
+                    IF (error) THEN
+                       CALL errorMessage('oorb / fou', &
+                            'TRACE BACK (75)',1)
+                       STOP
+                    END IF
+
+                    ! SOLAR ELONGATION
+                    vec3 = cross_product(obsy_obj,obsy_sun)
+                    temp_arr(k,4) = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_sun))
+
+                    CALL NULLIFY(ccoord)
+                    CALL NULLIFY(ephemerides_arr(k,j))
+                    CALL NULLIFY(orb_lt_corr_arr2(k,j))
+
+                 END DO
+
+                 CALL NULLIFY(observers(j))
+
+                 ! WIDTH OF EPHEMERIS UNCERTAINTY
+                 ! First, try in measuring largest width in RA:
+                 nhist = 360
+                 ALLOCATE(hist(nhist,2))
+                 CALL histogram(temp_arr(:,5), hist, 0.0_bp, two_pi)
+                 DO k=1,nhist
+                    IF (hist(k,2) == 0.0_bp) THEN
+                       EXIT
+                    END IF
+                 END DO
+                 DEALLOCATE(hist)
+                 ALLOCATE(ephem_(norb,2))
+                 WHERE (temp_arr(1:norb,5) < two_pi*((k-1)/nhist))
+                    ephem_(1:norb,1) = temp_arr(1:norb,5) + two_pi*(1 - (k-1)/nhist)
+                    ephem_(1:norb,2) = temp_arr(1:norb,6)
+                 END WHERE
+                 WHERE (temp_arr(1:norb,5) > two_pi*((k-1)/nhist))
+                    ephem_(1:norb,1) = temp_arr(1:norb,5) - two_pi*((k-1)/nhist)
+                    ephem_(1:norb,2) = temp_arr(1:norb,6)
+                 END WHERE
+                 indx_min = MINLOC(ephem_(1:norb,1),dim=1)
+                 indx_max = MAXLOC(ephem_(1:norb,1),dim=1)
+                 angular_distance_ra = angularDistance(ephem_(indx_min,1), ephem_(indx_min,2), &
+                      ephem_(indx_max,1), ephem_(indx_max,2))
+                 DEALLOCATE(ephem_)
+                 ! Second, try in measuring largest width in Dec:
+                 indx_min = MINLOC(temp_arr(1:norb,6),dim=1)
+                 indx_max = MAXLOC(temp_arr(1:norb,6),dim=1)
+                 angular_distance_dec = angularDistance(temp_arr(indx_min,5), temp_arr(indx_min,6), &
+                      temp_arr(indx_max,5), temp_arr(indx_max,6))
+
+                 WRITE(lu,"(F13.5,8(2X,F9.4))") &
+                      2400000.5_bp + mjd_utc, &
+                      MINVAL(temp_arr(:,4))/rad_deg, & 
+                      MAXVAL(temp_arr(:,4))/rad_deg, & 
+                      MAXVAL(temp_arr(:,3)), & 
+                      SUM(temp_arr(:,1))/REAL(SIZE(temp_arr,dim=1),bp)/rad_deg, &
+                      SUM(temp_arr(:,2))/REAL(SIZE(temp_arr,dim=1),bp)/rad_deg, &
+                      MAX(angular_distance_ra,angular_distance_dec)/rad_deg, &
+                      SUM(temp_arr(:,5))/REAL(SIZE(temp_arr,dim=1),bp)/rad_deg, &
+                      SUM(temp_arr(:,6))/REAL(SIZE(temp_arr,dim=1),bp)/rad_deg
+
+                 DEALLOCATE(temp_arr)
+
+              ELSE
+
+                 ! Input orbits correspond to one or more single-point estimates of the pdf.
+                 ALLOCATE(temp_arr(1,6))
+
+                 ! RA & DEC
+                 CALL rotateToEquatorial(ephemerides_arr(1,j))        
+                 comp_coord = getCoordinates(ephemerides_arr(1,j))
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (80)',1)
+                    STOP
+                 END IF
+                 Delta = comp_coord(1)
+                 temp_arr(1,5:6) = comp_coord(2:3)
+
+                 ! Compute topocentric ecliptic coordinates
+                 ! relative to the Sun
+                 CALL rotateToEcliptic(ephemerides_arr(1,j))        
+                 comp_coord = getCoordinates(ephemerides_arr(1,j))
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (85)',1)
+                    STOP
+                 END IF
+                 tsclon = comp_coord(2) - sunlon
+                 tsclat = comp_coord(3) - sunlat
+                 IF (tsclon > pi) THEN
+                    tsclon = tsclon - two_pi
+                 ELSE IF (tsclon < -pi) THEN
+                    tsclon = tsclon + two_pi
+                 END IF
+                 temp_arr(1,1:2) = (/ tsclon, tsclat /)
+
+                 ! APPARENT BRIGHTNESS:
+                 ! Compute phase angle
+                 CALL NEW(ccoord, ephemerides_arr(1,j))
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (90)',1)
+                    STOP
+                 END IF
+                 CALL rotateToEcliptic(ccoord)
+                 obsy_obj = getPosition(ccoord)
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (95)',1)
+                    STOP
+                 END IF
+                 ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+                 CALL toCartesian(orb_lt_corr_arr2(1,j), frame='ecliptic')
+                 pos = getPosition(orb_lt_corr_arr2(1,j))
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (100)',1)
+                    STOP
+                 END IF
+                 heliocentric_r2 = DOT_PRODUCT(pos,pos)
+                 cos_obj_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+                      observer_r2) / (SQRT(heliocentric_r2) * &
+                      SQRT(ephemeris_r2))
+                 obj_phase = ACOS(cos_obj_phase)
+                 ! Input absolute magnitude
+                 H_value = get_cl_option("--H=", HG_arr_storb_in(i,1,1))
+                 ! Input slope parameter
+                 G_value = get_cl_option("--G=", HG_arr_storb_in(i,1,3))
+                 temp_arr(1,3) = getApparentMagnitude(H=H_value, &
+                      G=G_value, r=SQRT(heliocentric_r2), &
+                      Delta=Delta, phase_angle=obj_phase)
+                 IF (error) THEN
+                    CALL errorMessage('oorb / fou', &
+                         'TRACE BACK (105)',1)
+                    STOP
+                 END IF
+
+                 ! SOLAR ELONGATION
+                 vec3 = cross_product(obsy_obj,obsy_sun)
+                 temp_arr(1,4) = ATAN2(SQRT(SUM(vec3**2)),DOT_PRODUCT(obsy_obj,obsy_sun))
+
+                 CALL NULLIFY(ccoord)
+                 CALL NULLIFY(ephemerides_arr(1,j))
+                 CALL NULLIFY(orb_lt_corr_arr2(1,j))
+
+                 CALL NULLIFY(observers(j))
+
+                 ! WIDTH OF EPHEMERIS UNCERTAINTY
+                 ! Make sure that the ephemeris is equatorial:
+                 DO k=1,6
+                    stdev_arr(k) = SQRT(cov_arr(k,k,j)) 
+                 END DO
+
+                 ! First, try measuring largest width in RA:
+                 angular_distance_ra = 3.0_bp*2.0_bp*stdev_arr(2)
+                 ! Second, try measuring largest width in Dec:
+                 angular_distance_dec = 3.0_bp*2.0_bp*stdev_arr(3)
+
+                 ! MG 20100202:
+                 ! NOTE THAT THE MIN,MAX VALUES FOR SOLELON ARE FOR
+                 ! NOW USING A TEMPORARY SOLUTION WHICH PROVIDES AN
+                 ! APPROXIMATION OF THE UNCERTAINTY. ASSUMPTION IS THE
+                 ! ELONGATION UNCERTAINTY IS MOSTLY DEPENDENT ON THE
+                 ! RA UNCERTAINTY AND LESS ON THE DEC UNCERTAINTY.
+                 ! MG 20100414:
+                 ! NEED TO MAKE SURE THAT THE MIN/MAX FOR SOLELON ARE
+                 ! REASONABLE (IE BETWEEN 0 AND 180 DEG AT ALL TIMES).
+
+                 solelon_min = (temp_arr(1,4)-angular_distance_ra/2.0_bp)/rad_deg
+                 IF (solelon_min < 0.0_bp) THEN
+                    solelon_min = 0.0_bp
+                 END IF
+                 solelon_max = (temp_arr(1,4)+angular_distance_ra/2.0_bp)/rad_deg
+                 IF (solelon_max > 180.0_bp) THEN
+                    solelon_max = 180.0_bp
+                 END IF
+
+                 WRITE(lu,"(F13.5,8(2X,F9.4))") &
+                      2400000.5_bp + mjd_utc, &
+                      solelon_min, & 
+                      solelon_max, & 
+                      temp_arr(1,3), & 
+                      temp_arr(1,1)/rad_deg, &
+                      temp_arr(1,2)/rad_deg, &
+                      MAX(angular_distance_ra,angular_distance_dec)/rad_deg, &
+                      temp_arr(:,5:6)/rad_deg
+
+                 DEALLOCATE(temp_arr)
+
+              END IF
+
+              CALL NULLIFY(t)
+
+           END DO
+
+           DEALLOCATE(observers, obsy_code_arr)
+           DEALLOCATE(ephemerides_arr, orb_lt_corr_arr2)
+           IF (ASSOCIATED(pdfs_arr)) THEN
+              DEALLOCATE(pdfs_arr)
+           END IF
+           IF (ASSOCIATED(cov_arr)) THEN
+              DEALLOCATE(cov_arr)
+           END IF
+           CALL NULLIFY(storb_arr_in(i))
+           IF (separately) THEN
+              CALL NULLIFY(tmp_file)
+           END IF
+
+        END DO
+        DEALLOCATE(storb_arr_in)
+
+     ELSE
+
+        CALL errorMessage("oorb / fou", &
+             "Uncertainty information not available for input orbits.",1)
+        STOP
+
+     END IF
+
+  CASE ("obs_timespan")
+
+     !! Returns the total observational timespan of the input
+     !! observations.
+
+     WRITE(stdout,"(F20.6)") getObservationalTimespan(obss_in)
+
+  CASE ("afrac")
+
+     !! Fractional uncertainty on the semimajor axis; da/a where da
+     !! either covers 99.73% of the total probability mass or is equal
+     !! to the 3-sigma limits.
+
+     DO i=1,SIZE(storb_arr_in)
+        IF (containsSampledPDF(storb_arr_in(i))) THEN
+           orb_arr_in => getSampleOrbits(storb_arr_in(i))
+           ALLOCATE(elements_arr(SIZE(orb_arr_in),6))
+           DO j=1,SIZE(orb_arr_in)
+              elements_arr(j,:) = getElements(orb_arr_in(j), "keplerian")
+              CALL NULLIFY(orb_arr_in(j))
+           END DO
+           pdf_arr_in => getPDFValues(storb_arr_in(i), "keplerian")
+           CALL confidence_limits(elements_arr(:,1), pdf_arr_in, &
+                probability_mass=0.9973_bp, peak=peak, bounds=bounds, &
+                errstr=errstr)
+           WRITE(stdout,'(F12.6)') (bounds(2)-bounds(1))/peak
+           DEALLOCATE(orb_arr_in, elements_arr, pdf_arr_in)
+        ELSE
+           orb = getNominalOrbit(storb_arr_in(i))
+           elements = getElements(orb, "keplerian")
+           CALL NULLIFY(orb)
+           cov = getCovarianceMatrix(storb_arr_in(i), "keplerian")
+           WRITE(stdout,'(F12.6)') (3.0_bp*2.0_bp*SQRT(cov(1,1)))/elements(1)           
+        END IF
+     END DO
+
+  CASE ("tai2utc")
+
+     mjd_tai = get_cl_option("--epoch-mjd-tai=", 0.0_bp)
+     CALL NEW(epoch, mjd_tai, "TAI")
+     IF (error) THEN
+        CALL errorMessage("oorb / tai2utc", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+     mjd_utc = getMJD(epoch, "UTC")
+     IF (error) THEN
+        CALL errorMessage("oorb / tai2utc", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_utc
+     CALL NULLIFY(epoch)
+
+
+  CASE ("utc2tai")
+
+     mjd_utc = get_cl_option("--epoch-mjd-utc=", 0.0_bp)
+     CALL NEW(epoch, mjd_utc, "UTC")
+     IF (error) THEN
+        CALL errorMessage("oorb / utc2tai", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+     mjd_tai = getMJD(epoch, "TAI")
+     IF (error) THEN
+        CALL errorMessage("oorb / utc2tai", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_tai
+     CALL NULLIFY(epoch)
+
+
+  CASE ("utc2tt")
+
+     mjd_utc = get_cl_option("--epoch-mjd-utc=", 0.0_bp)
+     CALL NEW(epoch, mjd_utc, "UTC")
+     IF (error) THEN
+        CALL errorMessage("oorb / utc2tt", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+     mjd_tt = getMJD(epoch, "TT")
+     IF (error) THEN
+        CALL errorMessage("oorb / utc2tt", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_tt
+     CALL NULLIFY(epoch)
+
+
+  CASE ("deg2radec", "degreestosexagesimal")
+
+     ! Input RA in degrees
+     IF (get_cl_option("--ra-degrees=", .FALSE.)) THEN
+        ra = get_cl_option("--ra-degrees=", -1.0_bp)
+        IF (ra < 0.0_bp) THEN
+           CALL errorMessage("oorb / degreestosexagesimal", &
+                "Negative degrees not possible for RA.", 1)        
+           STOP
+        END IF
+        ra = ra*rad_deg
+        CALL radiansToHMS(ra, i, j, sec)
+        WRITE(stdout,"(A,1X,2(I0,1X),F15.12)") "RA = ", i, j, sec
+     END IF
+
+     ! Input Dec in degrees
+     IF (get_cl_option("--dec-degrees=", .FALSE.)) THEN     
+        dec = get_cl_option("--dec-degrees=", -1.0_bp)
+        IF (dec < -90.0_bp .OR. dec > 90.0_bp) THEN
+           CALL errorMessage("oorb / degreestosexagesimal", &
+                "Declination not in the interval [-90 deg,90 deg].", 1)        
+           STOP
+        END IF
+        dec = dec*rad_deg
+        CALL radiansToDAMAS(dec, i, j, sec)
+        WRITE(stdout,"(A,1X,2(I0,1X),F15.12)") "Dec = ", i, j, sec
+     END IF
+
+  CASE ("encode_designation")
+
+     IF (.NOT.(get_cl_option("--mpc", .FALSE.) .OR. &
+          get_cl_option("--9char-mpc", .FALSE.))) THEN     
+        CALL errorMessage("oorb / encode_designation", &
+             "Either the '--mpc' or the '--9char-mpc' option has to be specified.", 1)                
+        STOP
+     ELSE IF (get_cl_option("--mpc", .FALSE.) .AND. &
+          get_cl_option("--9char-mpc", .FALSE.)) THEN     
+        CALL errorMessage("oorb / encode_designation", &
+             "Both '--mpc' and '--9char-mpc' options cannot be used simultaneously.", 1)                
+        STOP
+     END IF
+
+     IF (get_cl_option("--data-in=", .FALSE.)) THEN     
+        tmp_fname = get_cl_option("--data-in="," ")
+        CALL NEW(tmp_file, TRIM(tmp_fname))
+        CALL setStatusOld(tmp_file)
+        CALL OPEN(tmp_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / encode_designation", &
+                "TRACE BACK", 1)        
+           STOP
+        END IF
+        DO 
+           READ(getUnit(tmp_file),"(A)",iostat=err) id
+           IF (err < 0) THEN
+              EXIT
+           ELSE IF (err > 0) THEN
+              CALL errorMessage("oorb / encode_designation", &
+                   "Could not read designation from file.", 1)        
+              STOP
+           END IF
+           IF (get_cl_option("--mpc", .FALSE.)) THEN
+              CALL encodeMPCDesignation(id)
+           ELSE IF (get_cl_option("--9char-mpc", .FALSE.)) THEN
+              CALL encodeMPC3Designation(id)
+           END IF
+           WRITE(stdout,"(A)") TRIM(id)
+        END DO
+        CALL NULLIFY(tmp_file)
+     ELSE
+        CALL errorMessage("oorb / encode_designation", &
+             "No input file given (use '--data-in=' option).", 1)                
+     END IF
+
+
+  CASE ("decode_designation")
+
+     IF (get_cl_option("--data-in=", .FALSE.)) THEN     
+        tmp_fname = get_cl_option("--data-in="," ")
+        CALL NEW(tmp_file, TRIM(tmp_fname))
+        CALL setStatusOld(tmp_file)
+        CALL OPEN(tmp_file)
+        IF (error) THEN
+           CALL errorMessage("oorb / decode_designation", &
+                "TRACE BACK", 1)        
+           STOP
+        END IF
+        DO 
+           READ(getUnit(tmp_file),"(A)",iostat=err) id
+           IF (err < 0) THEN
+              EXIT
+           ELSE IF (err > 0) THEN
+              CALL errorMessage("oorb / decode_designation", &
+                   "Could not read designation from file.", 1)        
+              STOP
+           END IF
+           IF (LEN_TRIM(id) > 7) THEN
+              CALL decodeMPC3Designation(id)
+           ELSE
+              CALL decodeMPCDesignation(id)
+           END IF
+           WRITE(stdout,"(A)") TRIM(id)
+        END DO
+        CALL NULLIFY(tmp_file)
+     END IF
+
+  CASE ("synthetic_astrometry")
+
+     noise = .NOT.get_cl_option("--no-noise", .FALSE.)
+
+     IF (ALLOCATED(storb_arr_in)) THEN
+        ALLOCATE(orb_arr_in(SIZE(storb_arr_in)), id_arr_in(SIZE(storb_arr_in)))
+        DO i=1,SIZE(storb_arr_in)
+           orb_arr_in(i) = getNominalOrbit(storb_arr_in(i))
+           id_arr_in(i) = id_arr_storb_in(i)
+        END DO
+     END IF
+     norb = SIZE(orb_arr_in)
+     obss_sep => getSeparatedSets(obss_in)
+     nobj = SIZE(obss_sep)
+     DO i=1,norb
+
+        CALL setParameters(orb_arr_in(i), &
+             dyn_model=dyn_model, &
+             perturbers=perturbers, &
+             integrator=integrator, &
+             integration_step=integration_step)
+
+        ! find astrometry for this orbit
+        iobj = -1
+        DO j=1,nobj
+           IF (TRIM(id_arr_in(i)) == TRIM(getID(obss_sep(j)))) THEN
+              iobj = j
+           END IF
+        END DO
+        IF (iobj < 0 ) THEN
+           WRITE(stderr,*) "astrometry not available for " // TRIM(id_arr_in(i))  
+           STOP 
+        END IF
+
+        observers => getObservatoryCCoords(obss_sep(iobj))
+        obs_arr => getObservations(obss_sep(iobj))
+        mean = 0.0_bp
+        CALL getEphemerides(orb_arr_in(i), observers, ephemerides)
+        DO j=1,SIZE(ephemerides)
+           CALL rotateToEquatorial(ephemerides(j))
+           CALL setObservationSCoord(obs_arr(j), ephemerides(j))
+           IF (noise) THEN
+              cov = getCovarianceMatrix(obs_arr(j))
+              CALL addMultinormalDeviate(obs_arr(j), mean, cov)
+           END IF
+           IF (error) THEN
+              CALL errorMessage('oorb4research / ephemeris', &
+                   'TRACE BACK (20)',1)
+              STOP
+           END IF
+        END DO
+        CALL NULLIFY(orb)
+
+        CALL NEW(obss, obs_arr)
+        CALL writeObservationFile(obss, stdout, &
+             TRIM(observation_format_out))
+        CALL NULLIFY(obss)
+
+        DO j=1,SIZE(observers)
+           CALL NULLIFY(obs_arr(j))
+           CALL NULLIFY(observers(j))
+           CALL NULLIFY(ephemerides(j))
+        END DO
+        DEALLOCATE(observers, obs_arr, ephemerides)
+
+     END DO
+
+
+  CASE ("add_noise")
+
+     obss_sep => getSeparatedSets(obss_in)
+     IF (error) THEN
+        CALL errorMessage("oorb / add_noise", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+     CALL NULLIFY(obss_in)
+     mean = 0.0_bp
+     cov = 0.0_bp
+     cov(2,2) = (1.0_bp*rad_asec)**2
+     cov(3,3) = (1.0_bp*rad_asec)**2
+     DO i=1,SIZE(obss_sep)
+        ALLOCATE(mean_arr(getNrOfObservations(obss_sep(i)),6), &
+             cov_arr(getNrOfObservations(obss_sep(i)),6,6))
+        DO j=1,SIZE(mean_arr,dim=1)
+           mean_arr(j,:) = mean
+           cov_arr(j,:,:) = cov
+        END DO
+        CALL addMultinormalDeviates(obss_sep(i), mean_arr, cov_arr)
+        CALL writeObservationFile(obss_sep(i), stdout, "des")
+        CALL NULLIFY(obss_sep(i))
+        DEALLOCATE(mean_arr, cov_arr)
+     END DO
+     DEALLOCATE(obss_sep)
+
+
+  CASE default
+
+     IF (LEN_TRIM(task) == 0) THEN
+        CALL errorMessage("oorb", &
+             "No task specified.", 1)
+     ELSE
+        CALL errorMessage("oorb", &
+             "No task such as '" // TRIM(task) // "' available.", 1)
+     END IF
+     STOP
+
+  END SELECT
+
+  ! Close output orbit file
+  CALL NULLIFY(orb_out_file)
+
+  ! Deallocate memory
+  IF (ASSOCIATED(id_arr_in)) THEN
+     DEALLOCATE(id_arr_in)
+  END IF
+  IF (ASSOCIATED(id_arr_storb_in)) THEN
+     DEALLOCATE(id_arr_storb_in)
+  END IF
+  IF (ASSOCIATED(orb_arr_in)) THEN
+     DO i=1,SIZE(orb_arr_in)
+        CALL NULLIFY(orb_arr_in(i))
+     END DO
+     DEALLOCATE(orb_arr_in)
+  END IF
+  IF (ALLOCATED(storb_arr_in)) THEN
+     DO i=1,SIZE(storb_arr_in)
+        CALL NULLIFY(storb_arr_in(i))
+     END DO
+     DEALLOCATE(storb_arr_in)
+  END IF
+  IF (exist(obss_in)) THEN
+     CALL NULLIFY(obss_in)
+  END IF
+  IF (ASSOCIATED(obss_sep)) THEN
+     DO i=1,SIZE(obss_sep)
+        CALL NULLIFY(obss_sep(i))
+     END DO
+     DEALLOCATE(obss_sep)
+  END IF
+  IF (ASSOCIATED(HG_arr_in)) THEN
+     DEALLOCATE(HG_arr_in)
+  END IF
+  CALL JPL_ephemeris_nullify()
+  CALL nullifyTime()
+  IF (ASSOCIATED(perturbers)) THEN
+     DEALLOCATE(perturbers, stat=err)
+  END IF
+  DEALLOCATE(element_type_pdf_arr_in, stat=err)
+  DEALLOCATE(cov_arr_in, stat=err)
+  DEALLOCATE(pdf_arr_in, stat=err)
+  DEALLOCATE(rchi2_arr_in, stat=err)
+  DEALLOCATE(jac_arr_in, stat=err)
+  DEALLOCATE(reg_apr_arr_in, stat=err)
+
+END PROGRAM oorb
Index: trunk/mops/oorb/main/tico.f90
===================================================================
--- trunk/mops/oorb/main/tico.f90	(revision 34646)
+++ trunk/mops/oorb/main/tico.f90	(revision 34646)
@@ -0,0 +1,164 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!!
+!! DESCRIPTION
+!!
+!! tico performs conversions between timescales (TAI, TT, UTC).  
+!!
+!!
+!! USAGE
+!!
+!!  For example, to convert MJD 53653.36413 TAI to UTC do
+!!
+!!     tico --tai_in=53653.36413 --utc_out
+!!
+!!
+!! REQUIREMENTS
+!!
+!! Environment variable $OORB_DATA has to point to a directory which
+!! contains files ET-UT.dat and TAI-UTC.dat. Make sure these files are
+!! updated regularly.  
+!!
+!!
+!! AUTHOR
+!!
+!! Mikael Granvik 2010-09-17
+!!
+PROGRAM tico
+
+  USE cl_options
+  USE Base_cl
+  USE Time_cl
+
+  IMPLICIT NONE
+  TYPE (Time) :: t
+  CHARACTER(len=64) :: str
+  REAL(bp) :: mjd_in, mjd_out
+
+  ! Set path to data files:
+  CALL setAccessToDataFiles()
+
+  ! Input
+  IF (get_cl_option("--tai_in=", .FALSE.)) THEN
+     str = get_cl_option("--tai_in=", "")
+     CALL readDate(str, "TAI", t)
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (5)", 1)
+        STOP
+     END IF
+  ELSE IF (get_cl_option("--utc_in=", .FALSE.)) THEN
+     str = get_cl_option("--utc_in=", "")
+     CALL readDate(str, "UTC", t)
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (10)", 1)
+        STOP
+     END IF
+  ELSE IF (get_cl_option("--tt_in=", .FALSE.)) THEN
+     str = get_cl_option("--tt_in=", "")
+     CALL readDate(str, "TT", t)
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (15)", 1)
+        STOP
+     END IF
+  ELSE
+     CALL errorMessage("tico", &
+          "Input time/timescale not specified. Use the '--[tai|utc|tt]_in=' option.", 1)     
+     STOP
+  END IF
+
+  ! Output
+  IF (get_cl_option("--utc_out", .FALSE.)) THEN
+     mjd_out = getMJD(t, "UTC")
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (20)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_out
+  ELSE IF (get_cl_option("--tai_out", .FALSE.)) THEN
+     mjd_out = getMJD(t, "TAI")
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (25)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_out
+  ELSE IF (get_cl_option("--tt_out", .FALSE.)) THEN
+     mjd_out = getMJD(t, "TT")
+     IF (error) THEN
+        CALL errorMessage("tico", &
+             "TRACE BACK (30)", 1)
+        STOP
+     END IF
+     WRITE(stdout,'(F15.8)') mjd_out
+  ELSE
+     CALL errorMessage("tico", &
+          "Output timescale not specified. Use the '--[tai|utc|tt]_out' option.", 1)
+  END IF
+  CALL NULLIFY(t)
+
+CONTAINS
+
+  SUBROUTINE readDate(str, timescale, t)
+
+    IMPLICIT NONE
+    TYPE (Time), INTENT(out) :: t
+    CHARACTER(len=*), INTENT(in) :: str, timescale
+    REAL(bp) :: mjd_in, day
+    INTEGER, DIMENSION(0:2) :: indx_arr
+    INTEGER :: i, j, year, month
+
+    ! Count hyphens to figure out if this is a calendar date or MJD:
+    indx_arr = 0
+    i = 0
+    j = 1
+    DO WHILE (j > 0)
+       j = INDEX(str(indx_arr(i)+1:),"-")
+       IF (j > 0) THEN
+          indx_arr(i+1) = indx_arr(i) + j
+          i = i + 1
+       END IF
+    END DO
+    IF (i > 1) THEN
+       CALL toInt(str(1:indx_arr(1)-1), year, error)
+       CALL toInt(str(indx_arr(1)+1:indx_arr(2)-1), month, error)
+       CALL toReal(TRIM(str(indx_arr(2)+1:)), day, error)
+       CALL NEW(t, year, month, day, TRIM(timescale))
+    ELSE
+       CALL toReal(str, mjd_in, error)
+       CALL NEW(t, mjd_in, TRIM(timescale))
+    END IF
+    IF (error) THEN
+       CALL errorMessage("tico / readDate", &
+            "TRACE BACK", 1)
+       RETURN
+    END IF
+
+  END SUBROUTINE readDate
+
+
+END PROGRAM tico
Index: trunk/mops/oorb/make.config
===================================================================
--- trunk/mops/oorb/make.config	(revision 34646)
+++ trunk/mops/oorb/make.config	(revision 34646)
@@ -0,0 +1,142 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# This file contains all variables needed to run make.
+#
+# Author:  MG
+# Version: 2010-04-15
+
+# Project name:
+PROJNAME          = OOrb
+# Version:
+VERSION           = 1.0
+# Make command
+MAKE              = make
+
+
+# Compiler command and options:
+
+# g95: 
+FC_G95               = g95
+FCOPTIONS_OPT_G95    = -O3 -fzero -fshort-circuit -std=f95 -fintrinsic-extensions 
+FCOPTIONS_DEB_G95    = -g -O0 -fbounds-check -fintrinsic-extensions -fzero -fshort-circuit -ftrace=full -std=f95
+FC_INC_G95           = -I
+FC_SHARED_G95        = -dynamiclib -single_module -read_only_relocs suppress
+
+# gfortran: 
+FC_GFORTRAN               = gfortran
+FCOPTIONS_OPT_GFORTRAN    = -O3 -fPIC -std=f95 -fall-intrinsics
+FCOPTIONS_DEB_GFORTRAN    = -g -O0 -fPIC -fbounds-check -pedantic -Wall -std=f95 -fall-intrinsics 
+FC_INC_GFORTRAN           = -I
+FC_SHARED_GFORTRAN        = -shared
+
+# Absoft: 
+FC_ABSOFT            = f90
+FCOPTIONS_OPT_ABSOFT = -en -O2 -cpu:p7 -lU77 -YDEALLOC=ALL
+FCOPTIONS_DEB_ABSOFT = -g -P -en -g
+FC_INC_ABSOFT        = -p
+FC_SHARED_ABSOFT     = -bundle
+
+# Compaq:
+FC_COMPAQ            = f95
+FCOPTIONS_OPT_COMPAQ = -O2 -C -std95
+FCOPTIONS_DEB_COMPAQ = -g2 -pg -C -std95
+FC_INC_COMPAQ        = -I
+FC_SHARED_COMPAQ     = -bundle
+
+# IBM:
+FC_SER_IBM           = xlf90
+FC_PAR_IBM           = xlf90_r
+FCOPTIONS_PAR_IBM    = -qsuffix=f=f90 -qarch=pwr4 -qtune=pwr4 -qsmp=omp -g
+FCOPTIONS_OPT_IBM    = -qsuffix=f=f90 -O -qmaxmem=-1
+FCOPTIONS_DEB_IBM    = -qsuffix=f=f90 -g -qfullpath -qlist -qsource -qxref -qcheck
+FC_INC_IBM           = -I
+FC_SHARED_IBM        = -bundle
+
+# Intel: 
+FC_INTEL             = ifort
+FCOPTIONS_OPT_INTEL  = -O3 -ip -fPIC
+FCOPTIONS_DEB_INTEL  = -g -fPIC
+FC_INC_INTEL         = -I
+FC_SHARED_INTEL      = -dynamiclib
+
+# Lahey: 
+FC_LAHEY             = lf95
+FCOPTIONS_OPT_LAHEY  = --f95 --wo --warn --o2 --staticlink
+# Warning: use of --chkglobal will lead to mysterious crashes.
+FCOPTIONS_DEB_LAHEY  = --f95 -g -O0 --staticlink
+FC_INC_LAHEY         = -M
+FC_SHARED_LAHEY      = -bundle
+
+# Sun: 
+FC_SUN               = f90
+FCOPTIONS_OPT_SUN    = -C -e -m32 -fast -Bstatic
+FCOPTIONS_PAR_SUN    = -ansi -xarch=v9b -O3 -openmp -vpara -g
+FCOPTIONS_DEB_SUN    = -g -C -e -m32
+FC_INC_SUN           = -M
+FC_SHARED_SUN        = -bundle
+
+# Output name of the orbit computation executable: 
+ORBITBIN          = oorb
+# Name of orbit computation program source file:
+ORBITSRC          = oorb.f90
+
+# Path to main programs:
+MAINPATH          = main
+# Path to documentation:
+DOCPATH           = doc
+# Path to classes:
+CLASSPATH         = classes
+# Path to modules:
+MODULEPATH        = modules
+# Path to Python source:
+PYTHONPATH        = python
+# Path to OpenOrb library:
+LIBPATH           = lib
+
+F90_CLASS_SOURCES = Base_class.f90 \
+                    Unit_class.f90 \
+                    File_class.f90 \
+                    Time_class.f90 \
+                    Observatory_class.f90 \
+                    SphericalCoordinates_class.f90 \
+                    CartesianCoordinates_class.f90 \
+                    Observation_class.f90 \
+                    Observatories_class.f90 \
+                    Orbit_class.f90 \
+                    Observations_class.f90 \
+                    StochasticOrbit_class.f90 \
+		    PhysicalParameters_class.f90
+
+F90_MODULE_SOURCES = parameters.f90 \
+                     utilities.f90 \
+                     random.f90 \
+                     sort.f90 \
+                     statistics.f90 \
+                     functions.f90 \
+                     linal.f90 \
+                     estimators.f90 \
+                     planetary_data.f90 \
+                     cl_options.f90 \
+                     integrators.f90
+
Index: trunk/mops/oorb/modules/Makefile
===================================================================
--- trunk/mops/oorb/modules/Makefile	(revision 34646)
+++ trunk/mops/oorb/modules/Makefile	(revision 34646)
@@ -0,0 +1,40 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Makefile for helper modules.
+#
+# Author: MG
+# Date:   2009-11-09
+
+include ../make.config
+include ../Makefile.include
+MODFILES := $(notdir $(patsubst %.f90,%.o,$(F90_MODULE_SOURCES)))
+
+# Make everything:
+all: $(MODFILES)
+
+%.o : %.f90
+	$(FC) -c $(FCOPTIONS) $<
+
+clean:
+	rm -f *~ *.o *.mod
Index: trunk/mops/oorb/modules/cl_options.f90
===================================================================
--- trunk/mops/oorb/modules/cl_options.f90	(revision 34646)
+++ trunk/mops/oorb/modules/cl_options.f90	(revision 34646)
@@ -0,0 +1,222 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains generic functions that return command line options.
+!!
+!! @author  MG
+!! @version 2008-08-12
+!!
+MODULE cl_options
+
+  IMPLICIT NONE
+  INTEGER, PARAMETER :: CL_LEN = 4096
+
+  PRIVATE :: get_cl_option_char
+  PRIVATE :: get_cl_option_real8
+  PRIVATE :: get_cl_option_real
+  PRIVATE :: get_cl_option_integer
+  PRIVATE :: get_cl_option_logical
+
+  INTERFACE get_cl_option
+     MODULE PROCEDURE get_cl_option_char
+     MODULE PROCEDURE get_cl_option_real8
+     MODULE PROCEDURE get_cl_option_real
+     MODULE PROCEDURE get_cl_option_integer
+     MODULE PROCEDURE get_cl_option_logical
+  END INTERFACE
+
+
+CONTAINS
+
+
+
+
+
+  CHARACTER(len=256) FUNCTION get_cl_option_char(option, default) RESULT(value)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: option, default
+    CHARACTER(len=CL_LEN) :: cl = ""
+    INTEGER :: i, di, j, err
+
+    CALL get_command_line(cl)
+    i = INDEX(TRIM(cl), TRIM(option))
+    di = LEN_TRIM(option)
+    IF (i /= 0) THEN
+       READ(cl(i+di:),'(a)',iostat=err) value
+       IF (err /= 0) value = TRIM(default)
+    ELSE
+       value = TRIM(default)
+    END IF
+    ! Remove blanks in the beginning:
+    j = 0
+    DO WHILE (value(1:1) == " ")
+       j = j + 1
+       IF (j>256) RETURN
+       value = TRIM(value(2:))
+    END DO
+    ! Return empty value, if no value is given:
+    IF (value(2:2) == "-") THEN
+       value = ""
+       RETURN
+    END IF
+    ! Remove a blank found in the middle and everything
+    ! coming after it:
+    i = INDEX(TRIM(value)," ")
+    IF (i /= 0) value = TRIM(value(1:i-1))
+
+  END FUNCTION get_cl_option_char
+
+
+
+
+
+  REAL(kind=8) FUNCTION get_cl_option_real8(option, default) RESULT(value)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: option
+    REAL(kind=8), INTENT(in) :: default
+    CHARACTER(len=CL_LEN) :: cl = ""
+    INTEGER :: i, di, err
+
+    CALL get_command_line(cl)
+    i = INDEX(TRIM(cl), TRIM(option))
+    di = LEN_TRIM(option) - 1
+    IF (i /= 0) THEN
+       READ(cl(i+di+1:),*,iostat=err) value
+       IF (err /= 0) value = default
+    ELSE
+       value = default
+    END IF
+
+  END FUNCTION get_cl_option_real8
+
+
+
+
+
+  REAL FUNCTION get_cl_option_real(option, default) RESULT(value)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: option
+    REAL, INTENT(in) :: default
+    CHARACTER(len=CL_LEN) :: cl = ""
+    INTEGER :: i, di, err
+
+    CALL get_command_line(cl)
+    i = INDEX(TRIM(cl), TRIM(option))
+    di = LEN_TRIM(option) - 1
+    IF (i /= 0) THEN
+       READ(cl(i+di+1:),*,iostat=err) value
+       IF (err /= 0) value = default
+    ELSE
+       value = default
+    END IF
+
+  END FUNCTION get_cl_option_real
+
+
+
+
+
+  INTEGER FUNCTION get_cl_option_integer(option, default) RESULT(value)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: option
+    INTEGER, INTENT(in) :: default
+    CHARACTER(len=CL_LEN) :: cl = ""
+    INTEGER :: i, di, err
+
+    CALL get_command_line(cl)
+    i = INDEX(TRIM(cl), TRIM(option))
+    di = LEN_TRIM(option) - 1
+    IF (i /= 0) THEN
+       READ(cl(i+di+1:),*,iostat=err) value
+       IF (err /= 0) value = default
+    ELSE
+       value = default
+    END IF
+
+  END FUNCTION get_cl_option_integer
+
+
+
+
+
+  ! Returns true if the option is found, and the given default value otherwise.
+  !
+  LOGICAL FUNCTION get_cl_option_logical(option, default) RESULT(value)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: option
+    LOGICAL, INTENT(in) :: default
+    CHARACTER(len=CL_LEN) :: cl = " "
+    INTEGER :: i
+
+    CALL get_command_line(cl)
+    i = INDEX(TRIM(cl), TRIM(option))
+    IF (i /= 0) THEN
+       value = .TRUE.
+    ELSE
+       value = default
+    END IF
+
+  END FUNCTION get_cl_option_logical
+
+
+
+
+
+  SUBROUTINE get_command_line(cl)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(out) :: cl
+    EXTERNAL :: getarg
+    INTEGER, EXTERNAL :: iargc
+    CHARACTER(len=256) :: arg
+    INTEGER :: iarg, narg
+
+    cl = " "
+    ! If an error occurs during compilation, comment the section
+    ! between the ='s in/out and the section between the +'s out/in:
+    !=======================================
+!!$    narg = iargc()
+!!$    DO iarg=1, narg
+!!$       CALL getarg(iarg, arg)
+!!$       cl = TRIM(cl) // " " // TRIM(arg)
+!!$    END DO
+    !=======================================
+    !+++++++++++++++++++
+    CALL get_command(cl)
+    !+++++++++++++++++++
+
+  END SUBROUTINE get_command_line
+
+
+
+
+
+END MODULE cl_options
+
Index: trunk/mops/oorb/modules/estimators.f90
===================================================================
--- trunk/mops/oorb/modules/estimators.f90	(revision 34646)
+++ trunk/mops/oorb/modules/estimators.f90	(revision 34646)
@@ -0,0 +1,737 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains generic routines for parameter estimation.
+!!
+!! @author  MG
+!! @version 2010-03-02
+!!
+MODULE estimators
+
+  USE parameters
+  USE linal
+  USE statistics
+  IMPLICIT NONE
+
+  PRIVATE :: LevenbergMarquardt_r8_blockdiag
+
+  INTERFACE leastSquares
+     MODULE PROCEDURE leastSquares_r8_matrix
+     MODULE PROCEDURE leastSquares_r8_blockdiag
+  END INTERFACE
+
+  INTERFACE LevenbergMarquardt
+     MODULE PROCEDURE LevenbergMarquardt_r8_blockdiag
+  END INTERFACE
+
+CONTAINS
+
+
+
+  SUBROUTINE leastSquares_r8_matrix(indata, inform_mat_indata, &
+       mask_indata, computed, design_mat, correction_factor, mask_param, &
+       cov_mat_param, parameters, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: indata ! incl. cos(dec_obs)
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: inform_mat_indata ! incl. cos(dec_obs)
+    LOGICAL, DIMENSION(:,:), INTENT(in)   :: mask_indata
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: computed ! incl. cos(dec_comp)
+    REAL(rprec8), DIMENSION(:,:,:), INTENT(in) :: design_mat ! (type,data,param) incl. cos(dec_obs)
+    REAL(rprec8), INTENT(in)                   :: correction_factor
+    LOGICAL, DIMENSION(:), INTENT(in)        :: mask_param
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)  :: cov_mat_param
+    REAL(rprec8), DIMENSION(:), INTENT(inout)  :: parameters
+    CHARACTER(len=*), INTENT(inout)                   :: error
+    REAL(rprec8), DIMENSION(SIZE(cov_mat_param,dim=1),SIZE(cov_mat_param,dim=2)) :: &
+         inform_mat_param!, identity, test, matrix
+    REAL(rprec8), DIMENSION(SIZE(indata,dim=1),SIZE(indata,dim=2)) :: data_minus_computed 
+    REAL(rprec8), DIMENSION(SIZE(parameters)) :: param_corrections, tmp, d
+    INTEGER :: i, j, ndata, nparam, nmultidata
+
+    ndata = SIZE(indata,dim=1)
+    nmultidata = SIZE(indata,dim=2)
+    nparam = SIZE(parameters) 
+
+    ! Check shapes of matrices:
+    IF (nmultidata*ndata /= SIZE(inform_mat_indata,dim=1) .OR. &
+         nmultidata*ndata /= SIZE(inform_mat_indata,dim=2) .OR. &
+         nmultidata /= SIZE(design_mat,dim=1) .OR. &
+         ndata /= SIZE(design_mat,dim=2) .OR. &
+         nparam /= SIZE(design_mat,dim=3) .OR. &
+         ndata < SIZE(mask_indata,dim=1) .OR. &
+         nmultidata < SIZE(mask_indata,dim=2) .OR. &
+         ndata /= SIZE(computed,dim=1) .OR. &
+         nmultidata /= SIZE(computed,dim=2) .OR. &
+         nparam < SIZE(mask_param) .OR. &
+         nparam /= SIZE(cov_mat_param,dim=1) .OR. &
+         nparam /= SIZE(cov_mat_param,dim=2)) THEN
+       error = " -> estimators : leastSquares : Shapes of arrays do not conform." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+    ! (1) Compute the parameters' covariance matrix COV_MAT_PARAM and
+    !     its inverse INFORM_MAT_PARAM.
+
+    ! Sigma_param^(-1) = A^T Sigma_data^(-1) A:
+    inform_mat_param(:,:) = 0.0_rprec8
+    DO i=1,nmultidata
+       inform_mat_param(:,:) = inform_mat_param(:,:) + &
+            MATMUL(MATMUL(TRANSPOSE(design_mat(i,:,:)), &
+            inform_mat_indata(i:nmultidata*ndata:nmultidata, &
+            i:nmultidata*ndata:nmultidata)), design_mat(i,:,:))
+    END DO
+
+    ! Check which parameters are not used:
+    DO i=1,nparam
+       IF (.NOT.mask_param(i)) THEN
+          ! Nullify the corresponding row..
+          inform_mat_param(i,:) = 0.0_rprec8
+          ! ..and column,
+          inform_mat_param(:,i) = 0.0_rprec8
+          ! and set the diagonal element to 1.
+          inform_mat_param(i,i) = 1.0_rprec8
+       END IF
+    END DO
+
+    ! Renormalize to gain accuracy:
+    DO i=1,nparam
+       tmp(i) = SQRT(inform_mat_param(i,i)) 
+    END DO
+    DO i=1,nparam
+       DO j=i,nparam
+          inform_mat_param(i,j) = inform_mat_param(i,j)/(tmp(i)*tmp(j))
+          ! Due to symmetry:
+          inform_mat_param(j,i) = inform_mat_param(i,j)
+       END DO
+    END DO
+
+    ! Sigma_param = (Sigma_param^(-1))^(-1) 
+    cov_mat_param(:,:) = matinv(inform_mat_param(:,:), error, method="Cholesky")
+    IF (LEN_TRIM(error) /= 0) THEN
+       WRITE(0,*) "Could not find inverse of inverse covariance matrix."
+       RETURN
+    END IF
+    !CALL matrix_print(MATMUL(cov_mat_param(:,:),inform_mat_param(:,:)),0)
+
+    ! Enforce symmetry:
+    DO i=1,nparam
+       DO j=i,nparam
+          cov_mat_param(i,j) = 0.5_rprec8*(cov_mat_param(i,j) + cov_mat_param(j,i)) 
+          cov_mat_param(j,i) = cov_mat_param(i,j)
+       END DO
+    END DO
+
+    ! Renormalize back:
+    DO i=1,nparam
+       DO j=i,nparam
+          cov_mat_param(i,j) = cov_mat_param(i,j)/(tmp(i)*tmp(j))
+          ! Due to symmetry:
+          cov_mat_param(j,i) = cov_mat_param(i,j)
+          inform_mat_param(i,j) = inform_mat_param(i,j)*(tmp(i)*tmp(j))
+          ! Due to symmetry
+          inform_mat_param(j,i) = inform_mat_param(i,j)
+       END DO
+    END DO
+
+!!$    ! Is AA^(-1)=I ?
+!!$    identity(:,:) = 0.0_rprec8
+!!$    FORALL(i=1:nparam)
+!!$       identity(i,i) = 1.0_rprec8
+!!$    END FORALL
+!!$    test(:,:) = MATMUL(inform_mat_param, cov_mat_param)
+!!$    IF (ANY(ABS(test(:,:) - identity(:,:)) > 10*EPSILON(test(:,:)))) THEN
+!!$       error = .TRUE.
+!!$       WRITE(0,*) 'Error: Identity criterion not fulfilled:'
+!!$       call matrix_print(test,0)
+!!$       RETURN
+!!$    END IF
+
+    ! (2) Compute parameter corrections and make the scaled
+    !     corrections. If COMPUTED and PARAMETERS are zero,
+    !     and CORRECTION_FACTOR is one, this corresponds to the 
+    !     linear least-squares fit.
+
+    data_minus_computed(:,:) = indata(:,:) - computed(:,:)
+    WHERE (.NOT.mask_indata(:,:))
+       data_minus_computed(:,:) = 0.0_rprec8
+    END WHERE
+
+    ! d = A^T Sigma^(-1) y:
+    d(:) = 0.0_rprec8
+    DO i=1,nmultidata
+       d(:) = d(:) + MATMUL(MATMUL(TRANSPOSE(design_mat(i,:,:)), &
+            inform_mat_indata(i:nmultidata*ndata:nmultidata, &
+            i:nmultidata*ndata:nmultidata)), data_minus_computed(:,i))
+    END DO
+    WHERE (.NOT.mask_param(:))
+       d(:) = 0.0_rprec8
+    END WHERE
+
+    ! param = Sigma_param d:
+    param_corrections(:) = MATMUL(cov_mat_param(:,:), d(:))
+    WHERE (.NOT.mask_param(:))
+       param_corrections(:) = 0.0_rprec8
+    END WHERE
+    parameters(:) = parameters(:) + correction_factor*param_corrections(:)
+
+  END SUBROUTINE leastSquares_r8_matrix
+
+
+
+
+
+  SUBROUTINE leastSquares_r8_blockdiag(indata, block_diag_inform_mat_indata, &
+       mask_indata, computed, design_mat, correction_factor, mask_param, &
+       cov_mat_param, parameters, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: indata ! incl. cos(dec_obs)
+    REAL(rprec8), DIMENSION(:,:,:), INTENT(in) :: block_diag_inform_mat_indata ! incl. cos(dec_obs)
+    LOGICAL, DIMENSION(:,:), INTENT(in)   :: mask_indata
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: computed ! incl. cos(dec_comp)
+    REAL(rprec8), DIMENSION(:,:,:), INTENT(in) :: design_mat ! (type,data,param) incl. cos(dec_obs)
+    REAL(rprec8), INTENT(in)                   :: correction_factor
+    LOGICAL, DIMENSION(:), INTENT(in)        :: mask_param
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)  :: cov_mat_param
+    REAL(rprec8), DIMENSION(:), INTENT(inout)  :: parameters
+    CHARACTER(len=*), INTENT(inout)                   :: error
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: &
+         inform_mat_param!, identity, test, matrix
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: data_minus_computed 
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: param_corrections, tmp, d
+    INTEGER :: i, j, ndata, nparam, nmultidata, err
+
+    ndata = SIZE(indata,dim=1)
+    nmultidata = SIZE(indata,dim=2)
+    nparam = SIZE(parameters)
+
+    ! Check shapes of matrices:
+    IF (ndata /= SIZE(block_diag_inform_mat_indata,dim=1) .OR. &
+         nmultidata /= SIZE(block_diag_inform_mat_indata,dim=2) .OR. &
+         nmultidata /= SIZE(block_diag_inform_mat_indata,dim=3) .OR. &
+         nmultidata /= SIZE(design_mat,dim=1) .OR. &
+         ndata /= SIZE(design_mat,dim=2) .OR. &
+         nparam /= SIZE(design_mat,dim=3) .OR. &
+         ndata < SIZE(mask_indata,dim=1) .OR. &
+         nmultidata < SIZE(mask_indata,dim=2) .OR. &
+         ndata /= SIZE(computed,dim=1) .OR. &
+         nmultidata /= SIZE(computed,dim=2) .OR. &
+         nparam < SIZE(mask_param) .OR. &
+         nparam /= SIZE(cov_mat_param,dim=1) .OR. &
+         nparam /= SIZE(cov_mat_param,dim=2)) THEN
+       error = " -> estimators : leastSquares : Shapes of arrays do not conform." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+    ALLOCATE(inform_mat_param(nparam,nparam), &
+         data_minus_computed(ndata,nmultidata), &
+         param_corrections(nparam), &
+         tmp(nparam), &
+         d(nparam), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = " -> estimators : leastSquares : Could not allocate memory." // &
+            TRIM(error)
+       DEALLOCATE(inform_mat_param, stat=err)
+       DEALLOCATE(data_minus_computed, stat=err)
+       DEALLOCATE(param_corrections, stat=err)
+       DEALLOCATE(tmp, stat=err)
+       DEALLOCATE(d, stat=err)
+       RETURN
+    END IF
+
+    ! (1) Compute the parameters' covariance matrix COV_MAT_PARAM and
+    !     its inverse INFORM_MAT_PARAM.
+
+    ! Sigma_param^(-1) = A^T Sigma_data^(-1) A:
+    inform_mat_param(:,:) = 0.0_rprec8
+    DO i=1,ndata
+       inform_mat_param(:,:) = inform_mat_param(:,:) + &
+            MATMUL(MATMUL(TRANSPOSE(design_mat(1:nmultidata,i,1:nparam)), &
+            block_diag_inform_mat_indata(i,1:nmultidata,1:nmultidata)), &
+            design_mat(1:nmultidata,i,1:nparam))
+    END DO
+
+    ! Check which parameters are not used:
+    DO i=1,nparam
+       IF (.NOT.mask_param(i)) THEN
+          ! Nullify the corresponding row..
+          inform_mat_param(i,:) = 0.0_rprec8
+          ! ..and column,
+          inform_mat_param(:,i) = 0.0_rprec8
+          ! and set the diagonal element to 1.
+          inform_mat_param(i,i) = 1.0_rprec8
+       END IF
+    END DO
+
+    ! Renormalize to gain accuracy:
+    DO i=1,nparam
+       tmp(i) = SQRT(inform_mat_param(i,i)) 
+    END DO
+    DO i=1,nparam
+       DO j=i,nparam
+          inform_mat_param(i,j) = inform_mat_param(i,j)/(tmp(i)*tmp(j))
+          ! Due to symmetry:
+          inform_mat_param(j,i) = inform_mat_param(i,j)
+       END DO
+    END DO
+
+    ! Sigma_param = (Sigma_param^(-1))^(-1) 
+    cov_mat_param(:,:) = matinv(inform_mat_param(:,:), error, method="Cholesky")
+    IF (LEN_TRIM(error) /= 0) THEN
+       WRITE(0,*) "Could not find inverse of inverse covariance matrix."
+       DEALLOCATE(inform_mat_param, stat=err)
+       DEALLOCATE(data_minus_computed, stat=err)
+       DEALLOCATE(param_corrections, stat=err)
+       DEALLOCATE(tmp, stat=err)
+       DEALLOCATE(d, stat=err)
+       RETURN
+    END IF
+
+    ! Enforce symmetry:
+    DO i=1,nparam
+       DO j=i,nparam
+          cov_mat_param(i,j) = 0.5_rprec8*(cov_mat_param(i,j) + cov_mat_param(j,i)) 
+          cov_mat_param(j,i) = cov_mat_param(i,j)
+       END DO
+    END DO
+
+    ! Renormalize back:
+    DO i=1,nparam
+       DO j=i,nparam
+          cov_mat_param(i,j) = cov_mat_param(i,j)/(tmp(i)*tmp(j))
+          ! Due to symmetry:
+          cov_mat_param(j,i) = cov_mat_param(i,j)
+          inform_mat_param(i,j) = inform_mat_param(i,j)*(tmp(i)*tmp(j))
+          ! Due to symmetry
+          inform_mat_param(j,i) = inform_mat_param(i,j)
+       END DO
+    END DO
+
+!!$    ! Is AA^(-1)=I ?
+!!$    identity(:,:) = 0.0_rprec8
+!!$    FORALL(i=1:nparam)
+!!$       identity(i,i) = 1.0_rprec8
+!!$    END FORALL
+!!$    test(:,:) = MATMUL(inform_mat_param, cov_mat_param)
+!!$    IF (ANY(ABS(test(:,:) - identity(:,:)) > 10*EPSILON(test(:,:)))) THEN
+!!$       error = .TRUE.
+!!$       WRITE(0,*) 'Error: Identity criterion not fulfilled:'
+!!$       call matrix_print(test,0)
+!!$       RETURN
+!!$    END IF
+
+    ! (2) Compute parameter corrections and make the scaled
+    !     corrections. If COMPUTED and PARAMETERS are zero,
+    !     and CORRECTION_FACTOR is one, this corresponds to the 
+    !     linear least-squares fit.
+
+    data_minus_computed(:,:) = indata(:,:) - computed(:,:)
+    WHERE (.NOT.mask_indata(:,:))
+       data_minus_computed(:,:) = 0.0_rprec8
+    END WHERE
+
+    ! d = A^T Sigma^(-1) y:
+    d(:) = 0.0_rprec8
+    DO i=1,ndata
+       d(:) = d(:) + MATMUL(MATMUL(TRANSPOSE(design_mat(1:nmultidata,i,1:nparam)), &
+            block_diag_inform_mat_indata(i,1:nmultidata,1:nmultidata)), &
+            data_minus_computed(i,1:nmultidata))
+    END DO
+    WHERE (.NOT.mask_param(:))
+       d(:) = 0.0_rprec8
+    END WHERE
+
+    ! param = Sigma_param d:
+    param_corrections(:) = MATMUL(cov_mat_param(:,:), d(:))
+    WHERE (.NOT.mask_param(:))
+       param_corrections(:) = 0.0_rprec8
+    END WHERE
+    parameters(:) = parameters(:) + correction_factor*param_corrections(:)
+
+    DEALLOCATE(inform_mat_param, data_minus_computed, &
+         param_corrections, tmp, d, stat=err)
+    IF (err /= 0) THEN
+       error = " -> estimators : leastSquares : Could not deallocate memory." // &
+            TRIM(error)
+       DEALLOCATE(inform_mat_param, stat=err)
+       DEALLOCATE(data_minus_computed, stat=err)
+       DEALLOCATE(param_corrections, stat=err)
+       DEALLOCATE(tmp, stat=err)
+       DEALLOCATE(d, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE leastSquares_r8_blockdiag
+
+
+
+
+
+  SUBROUTINE LevenbergMarquardt_r8_blockdiag(x, measur, &
+       information_matrix_measur, mask_measur, sub, &
+       niter, chi2_frac, cov_mat_param, params, &
+       residuals, chi2, errstr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: x
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: measur ! incl. cos(dec_obs)
+    REAL(rprec8), DIMENSION(:,:,:), INTENT(in) :: information_matrix_measur ! incl. cos(dec_obs)
+    LOGICAL, DIMENSION(:,:), INTENT(in)        :: mask_measur
+    INTERFACE
+       SUBROUTINE sub(x, measur, params, residuals, jacobians, chi2, errstr)
+         USE parameters
+         IMPLICIT NONE
+         REAL(rprec8), DIMENSION(:,:), INTENT(in)    :: x
+         REAL(rprec8), DIMENSION(:,:), INTENT(in)    :: measur         
+         REAL(rprec8), DIMENSION(:), INTENT(inout)   :: params
+         REAL(rprec8), DIMENSION(:,:), INTENT(out)   :: residuals
+         REAL(rprec8), DIMENSION(:,:,:), INTENT(out) :: jacobians 
+         REAL(rprec8), INTENT(out)                   :: chi2
+         CHARACTER(len=*), INTENT(inout)             :: errstr
+       END SUBROUTINE sub
+    END INTERFACE
+    REAL(rprec8), INTENT(in)                   :: chi2_frac
+    INTEGER, INTENT(inout)                     :: niter
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)  :: cov_mat_param
+    REAL(rprec8), DIMENSION(:), INTENT(inout)  :: params
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)  :: residuals
+    REAL(rprec8), INTENT(out)                  :: chi2   
+    CHARACTER(len=*), INTENT(inout)            :: errstr
+
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: alpha
+    REAL(rprec8) :: chi2_previous, lambda
+    INTEGER :: i, ndata, nparam, nmultidata, nfit, err
+
+
+    ndata = SIZE(residuals,dim=1)
+    nmultidata = SIZE(residuals,dim=2)
+    nparam = SIZE(params)
+
+    ALLOCATE(alpha(nparam,nparam), stat=err)
+
+    chi2_previous = HUGE(chi2_previous)
+    lambda = -1.0_rprec8
+    DO i=1,niter
+       CALL LevenbergMarquardt_private
+       IF (ABS(chi2 - chi2_previous)/chi2 < chi2_frac .AND. &
+            chi2 < chi2_previous) THEN
+          EXIT
+       ELSE
+          chi2_previous = chi2
+       END IF
+    END DO
+    lambda = 0.0_rprec8
+    CALL LevenbergMarquardt_private
+
+    DEALLOCATE(alpha, stat=err)
+
+  CONTAINS
+
+
+    SUBROUTINE LevenbergMarquardt_private
+
+      REAL(rprec8), SAVE :: chi2_
+      REAL(rprec8), DIMENSION(:), ALLOCATABLE, SAVE :: params_, beta
+      REAL(rprec8), DIMENSION(:,:), ALLOCATABLE, SAVE :: param_corrections
+
+      IF (lambda < 0.0_rprec8) THEN
+         ALLOCATE(params_(nparam),beta(nparam),param_corrections(nparam,1))
+         lambda = 0.001_rprec8
+         params_ = params
+         CALL coefficients(params_, alpha, beta)
+         chi2_ = chi2
+      END IF
+      cov_mat_param = alpha
+      cov_mat_param = diagonal_multiplication(cov_mat_param,1.0_rprec8+lambda,errstr)
+      IF (LEN_TRIM(errstr) /= 0) THEN
+         errstr = " -> estimators : LevenbergMarquardt : LevenbergMarquardt_private : ." // &
+              TRIM(errstr)
+         RETURN
+      END IF
+      param_corrections(:,1) = beta
+      CALL gauss_jordan(cov_mat_param, param_corrections, errstr)
+      IF (LEN_TRIM(errstr) /= 0) THEN
+         errstr = " -> estimators : LevenbergMarquardt : LevenbergMarquardt_private : ." // &
+              TRIM(errstr)
+         RETURN         
+      END IF
+      IF (lambda == 0.0_rprec8) THEN
+         DEALLOCATE(params_, beta, param_corrections)
+         RETURN
+      END IF
+      params_ = params + param_corrections(:,1)
+      CALL coefficients(params_, cov_mat_param, param_corrections(:,1))
+      IF (chi2 < chi2_) THEN
+         lambda = 0.1_rprec8*lambda
+         chi2_ = chi2
+         alpha = cov_mat_param
+         beta = param_corrections(:,1)
+         params = params_
+      ELSE
+         lambda = 10.0_rprec8*lambda
+         chi2 = chi2_
+      END IF
+
+    END SUBROUTINE LevenbergMarquardt_private
+
+
+    SUBROUTINE coefficients(params, alpha, beta)
+
+      IMPLICIT NONE
+      REAL(rprec8), DIMENSION(:), INTENT(inout) :: params
+      REAL(rprec8), DIMENSION(:), INTENT(out) :: beta
+      REAL(rprec8), DIMENSION(:,:), INTENT(out) :: alpha
+
+      REAL(rprec8), DIMENSION(nmultidata,ndata,nparam) :: jacobians
+      REAL(rprec8), DIMENSION(nparam,nmultidata) :: tmp
+      INTEGER :: i
+
+      CALL sub(x, measur, params, residuals, jacobians, chi2, errstr)
+      IF (LEN_TRIM(errstr) /= 0) THEN
+         errstr = " -> estimators : LevenbergMarquardt : coefficients : ." // &
+              TRIM(errstr)
+         RETURN
+      END IF
+      ! Approximate Hessian by multiplying Jacobians
+      ! alpha = cov_param^(-1) = J^T Sigma_obs^(-1) J:
+      ! beta = J^T Sigma_obs^(-1) y:
+      alpha = 0.0_rprec8
+      beta = 0.0_rprec8
+      DO i=1,ndata
+         tmp = MATMUL(TRANSPOSE(jacobians(1:nmultidata,1:nparam,i)), &
+              information_matrix_measur(i,1:nmultidata,1:nmultidata))
+         alpha = alpha + MATMUL(tmp, jacobians(1:nmultidata,1:nparam,i))
+         beta = beta + MATMUL(tmp, residuals(i,1:nmultidata))
+      END DO
+
+    END SUBROUTINE coefficients
+
+  END SUBROUTINE LevenbergMarquardt_r8_blockdiag
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Minimization of the function func in N dimensions by the
+  !! downhill simplex method of Nelder and Mead. The (N + 1) × N
+  !! matrix p is input. Its N + 1 rows are N-dimensional vectors that
+  !! are the vertices of the starting simplex. Also input is the
+  !! vector y of length N + 1, whose components must be preinitialized
+  !! to the values of func evaluated at the N + 1 vertices (rows) of
+  !! p and ftol the fractional convergence tolerance to be achieved in
+  !! the function value (n.b.!). On output, p and y will have been
+  !! reset to N+1 new points all within ftol of a minimum function
+  !! value, and iter gives the number of function evaluations taken.
+  !!
+  !! Parameters: The maximum allowed number of function evaluations,
+  !! and a small number.
+  !!
+  SUBROUTINE simplex(func, param, thresh, iter, p_matrix, y_vector, verb, errstr)
+
+    IMPLICIT NONE
+    INTERFACE
+       REAL(8) FUNCTION func(x, param, errstr)
+         IMPLICIT NONE
+         REAL(8), DIMENSION(:), INTENT(in) :: x
+         REAL(8), DIMENSION(:), INTENT(in) :: param
+         CHARACTER(len=*), INTENT(inout) :: errstr
+       END FUNCTION func
+    END INTERFACE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: param
+    REAL(rprec8), INTENT(in) :: thresh
+    INTEGER, INTENT(inout) :: iter
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout) :: p_matrix
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: y_vector
+    INTEGER(iprec4), INTENT(in) :: verb
+    CHARACTER(len=*), INTENT(inout) :: errstr
+
+    CHARACTER(len=8) :: str
+    REAL(rprec8), DIMENSION(SIZE(p_matrix,dim=2)) :: psum
+    REAL(rprec8) :: ysave, ytry, ytmp
+    INTEGER(iprec4) :: i, ilo, ihi, inhi, ndim, iter_max
+    LOGICAL :: error
+
+    ndim = SIZE(p_matrix,dim=2)
+    error = .FALSE.
+    CALL toString(ndim-1, str, error)
+    IF (error) THEN
+       errstr = " -> estimators : simplex : Could not convert integer to character string." // &
+            TRIM(errstr)
+       RETURN       
+    END IF
+    IF (ndim /= SIZE(p_matrix,dim=1) - 1 .OR. ndim /= SIZE(y_vector) - 1) THEN
+       errstr = " -> estimators : simplex : Input vectors are not compatible." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+    iter_max = iter
+    iter = 0
+    psum(:) = SUM(p_matrix(:,:),dim=1) 
+    DO !Iteration loop.  
+       ! Determine which point is the highest (worst),
+       ! next-highest, and lowest (best)
+       ilo = iminloc(y_vector(:))
+       ihi = imaxloc(y_vector(:))
+       ytmp = y_vector(ihi) 
+       y_vector(ihi) = y_vector(ilo)
+       inhi = imaxloc(y_vector(:))
+       y_vector(ihi) = ytmp
+       IF (verb >= 2) THEN
+          DO i=1,SIZE(y_vector,dim=1)
+             IF (i == ilo) THEN
+                WRITE(*,"('ILO:',1X,"//TRIM(str)//"(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+             ELSE IF (i == ihi) THEN
+                WRITE(*,"('IHI:',1X,"//TRIM(str)//"(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+             ELSE
+                WRITE(*,"(5X,"//TRIM(str)//"(F20.15,1X))") p_matrix(i,:), y_vector(i) 
+             END IF
+          END DO
+          WRITE(*,"(1X)")
+       END IF
+       ! Compute the fractional range from highest to lowest and
+       ! return if satisfactory.
+       IF (y_vector(ilo) < thresh) THEN 
+          ! If returning, put best point and value in slot 1. 
+          CALL swap(y_vector(1),y_vector(ilo))
+          CALL swap(p_matrix(1,:),p_matrix(ilo,:)) 
+          RETURN 
+       END IF
+       IF (iter > iter_max) THEN
+          errstr = " -> estimators : simplex_try : Maximum number of iterations exceeded." // &
+               TRIM(errstr)
+          RETURN
+       END IF
+       ! Begin a new iteration. First extrapolate by a factor -1
+       ! through the face of the simplex across from the high
+       ! point, i.e., reflect the simplex from the high point.
+       ytry = simplex_try(func, param, -1.0_rprec8, ihi, psum, p_matrix, y_vector, errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          errstr = " -> estimators : simplex : ." // &
+               TRIM(errstr)
+          RETURN
+       END IF
+       iter = iter + 1 
+       IF (ytry <= y_vector(ilo)) THEN
+          ! Gives a result better than the best point, so try an
+          ! additional extrapolation by a factor of 2.  
+          ytry = simplex_try(func, param, 2.0_rprec8, ihi, psum, p_matrix, y_vector, errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             errstr = " -> estimators : simplex : ." // &
+                  TRIM(errstr)
+             RETURN
+          END IF
+          iter = iter + 1 
+       ELSE IF (ytry >= y_vector(inhi)) THEN 
+          ! The reflected point is worse than the second highest,
+          ! so look for an intermediate lower point, i.e., do a
+          ! one-dimensional contraction.
+          ysave = y_vector(ihi) 
+          ytry = simplex_try(func, param, 0.5_rprec8, ihi, psum, p_matrix, y_vector, errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             errstr = " -> estimators : simplex : ." // &
+                  TRIM(errstr)
+             RETURN
+          END IF
+          iter = iter + 1
+          IF (ytry >= ysave) THEN
+             ! Can't seem to get rid of that high point. Better
+             ! contract around the lowest (best) point.
+             p_matrix(:,:) = 0.5_rprec8*(p_matrix(:,:)+SPREAD(p_matrix(ilo,:),1,SIZE(p_matrix,1)))
+             DO i=1,ndim+1
+                IF (i /= ilo) THEN
+                   y_vector(i) = func(p_matrix(i,:),param,errstr)
+                   IF (LEN_TRIM(errstr) /= 0) THEN
+                      errstr = " -> estimators : simplex : ." // &
+                           TRIM(errstr)
+                      RETURN
+                   END IF
+                END IF
+             END DO
+             iter = iter + ndim ! Keep track of function evaluations.
+             psum(:) = SUM(p_matrix(:,:),dim=1)
+          END IF
+       END IF
+    END DO ! Go back for the test of doneness and the next iteration.
+
+  END SUBROUTINE simplex
+
+
+  !! *Description*:
+  !!
+  !! Extrapolates by a factor fac through the face of the
+  !! simplex across from the high point, tries it, and replaces
+  !! the high point if the new point is better.
+  !!
+  REAL(rprec8) FUNCTION simplex_try(func, param, fac, ihi, psum, p_matrix, y_vector, errstr)
+
+    IMPLICIT NONE
+    INTERFACE
+       REAL(8) FUNCTION func(x, param, errstr)
+         IMPLICIT NONE
+         REAL(8), DIMENSION(:), INTENT(in) :: x
+         REAL(8), DIMENSION(:), INTENT(in) :: param
+         CHARACTER(len=*), INTENT(inout) :: errstr
+       END FUNCTION func
+    END INTERFACE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: param
+    REAL(rprec8), INTENT(IN) :: fac
+    INTEGER, INTENT(in) :: ihi
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: psum
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout) :: p_matrix
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: y_vector
+    CHARACTER(len=*), INTENT(inout) :: errstr
+
+    REAL(rprec8), DIMENSION(SIZE(p_matrix,2)) :: ptry 
+    REAL(rprec8) :: fac1, fac2, ytry
+
+    fac1 = (1.0_rprec8-fac)/SIZE(p_matrix,dim=2)
+    fac2 = fac1 - fac 
+    ptry(:) = psum(:)*fac1-p_matrix(ihi,:)*fac2 
+    ! Evaluate the function at the trial point.
+    ytry = func(ptry,param,errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       errstr = " -> estimators : simplex_try : ." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+    IF (ytry < y_vector(ihi)) THEN 
+       ! If it's better than the highest, then replace
+       ! the highest.
+       y_vector(ihi) = ytry
+       psum(:) = psum(:) - p_matrix(ihi,:) + ptry(:)
+       p_matrix(ihi,:) = ptry(:)
+    END IF
+    simplex_try = ytry 
+
+  END FUNCTION simplex_try
+
+
+END MODULE estimators
Index: trunk/mops/oorb/modules/functions.f90
===================================================================
--- trunk/mops/oorb/modules/functions.f90	(revision 34646)
+++ trunk/mops/oorb/modules/functions.f90	(revision 34646)
@@ -0,0 +1,266 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains different mathematical functions.
+!!
+!! @author  MG
+!! @version 2008-08-12
+!!
+MODULE functions
+
+  USE parameters
+  IMPLICIT NONE
+
+  INTERFACE stumpff
+     MODULE PROCEDURE stumpff_r8_series
+     MODULE PROCEDURE stumpff_r16_series
+     MODULE PROCEDURE stumpff_r8_recursive
+     MODULE PROCEDURE stumpff_r16_recursive
+  END INTERFACE
+
+
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Determines Stumpff-function c_k(x) by using series. The number of
+  !! terms is dictated by the precision: the series is truncated when
+  !! the accuracy given by additional terms can not be presented with
+  !! the used precision. 
+  !!
+  !! Input values: x=R and k=0,1,2,...
+  !!
+  !! If k<0, the function returns 0.
+  !!
+  REAL(rprec8) FUNCTION stumpff_r8_series(x, k)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in) :: x
+    INTEGER, INTENT(in) :: k
+    REAL(rprec8) :: term, stumpff_old
+    INTEGER :: i
+
+    ! k = 0,1,2,...
+    IF (k < 0) THEN
+       stumpff_r8_series = 0.0_rprec8
+       RETURN
+    END IF
+
+    ! Compute the first term of the Stumpff-"function":
+    term = 1.0_rprec8/factorial(k)
+    stumpff_r8_series = term
+
+    ! Compute terms of the Stumpff-"function" until the 
+    ! limit of the computer accuracy is reached and 
+    ! further improvement of the accuracy is pointless:  
+    stumpff_old = HUGE(stumpff_old)
+    i = 0
+    DO
+       i = i + 1
+       term = term * x/REAL((k+i*2)*(k+i*2-1),rprec8)
+       stumpff_r8_series = stumpff_r8_series + &
+            REAL((-1)**i,rprec8) * term
+       IF (ABS(stumpff_r8_series - stumpff_old) < &
+            10.0_rprec8*EPSILON(stumpff_r8_series)) THEN
+          EXIT
+       END IF
+       stumpff_old = stumpff_r8_series
+    END DO
+
+  END FUNCTION stumpff_r8_series
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Determines Stumpff-function c_k(x) by using series. The number of
+  !! terms is dictated by the precision: the series is truncated when
+  !! the accuracy given by additional terms can not be presented with
+  !! the used precision. 
+  !!
+  !! Input values: x=R and k=0,1,2,...
+  !!
+  !! If k<0, the function returns 0.
+  !!
+  REAL(rprec16) FUNCTION stumpff_r16_series(x, k)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in) :: x
+    INTEGER, INTENT(in) :: k
+    REAL(rprec16) :: term, stumpff_old
+    INTEGER :: i
+
+    ! k = 0,1,2,...
+    IF (k < 0) THEN
+       stumpff_r16_series = 0.0_rprec16
+       RETURN
+    END IF
+
+    ! Compute the first term of the Stumpff-"function":
+    term = 1.0_rprec16/factorial(k)
+    stumpff_r16_series = term
+
+    ! Compute terms of the Stumpff-"function" until the 
+    ! limit of the computer accuracy is reached and 
+    ! further improvement of the accuracy is pointless:  
+    stumpff_old = HUGE(stumpff_old)
+    i = 0
+    DO
+       i = i + 1
+       term = term * x/REAL((k+i*2)*(k+i*2-1),rprec16)
+       stumpff_r16_series = stumpff_r16_series + &
+            REAL((-1)**i,rprec16) * term
+       IF (ABS(stumpff_r16_series - stumpff_old) < &
+            10.0_rprec16*EPSILON(stumpff_r16_series)) THEN
+          EXIT
+       END IF
+       stumpff_old = stumpff_r16_series
+    END DO
+
+  END FUNCTION stumpff_r16_series
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Determines Stumpff-function c_k(x) by using the recursion
+  !! formula.
+  !!
+  !! If 'to_higher' is abscent or .false., the function returns c_k(x)
+  !! assuming that 'stumpff' is c_(k+2)(x). If 'to_higher' is .true.,
+  !! the function returns c_(k+2)(x) assuming that 'stumpff' is
+  !! c_(k)(x).
+  !!
+  !! Input values: x=R, k=0,1,2,..., stumpff>0
+  !!
+  !! If k<0 or stumpff<=0, the function returns 0.
+  !!
+  REAL(rprec8) FUNCTION stumpff_r8_recursive(x, k, stumpff, to_higher)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in) :: x, stumpff
+    INTEGER, INTENT(in) :: k
+    LOGICAL, OPTIONAL :: to_higher
+
+    ! k = 0,1,2,... and stumpff > 0
+    IF (k < 0 .OR. stumpff <= 0) THEN
+       stumpff_r8_recursive = 0.0_rprec8
+       RETURN
+    END IF
+
+    IF (PRESENT(to_higher)) THEN
+       IF (to_higher) THEN
+          ! c_k -> c_(k+2)
+          stumpff_r8_recursive = (1.0_rprec8/factorial(k-2) - stumpff)/x
+          RETURN
+       END IF
+    END IF
+
+    ! c_(k+2) -> c_k
+    stumpff_r8_recursive = 1.0_rprec8/factorial(k) - x*stumpff
+
+  END FUNCTION stumpff_r8_recursive
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Determines Stumpff-function c_k(x) by using the recursion
+  !! formula.
+  !!
+  !! If 'to_higher' is abscent or .false., the function returns c_k(x)
+  !! assuming that 'stumpff' is c_(k+2)(x). If 'to_higher' is .true.,
+  !! the function returns c_(k+2)(x) assuming that 'stumpff' is
+  !! c_(k)(x).
+  !!
+  !! Input values: x=R, k=0,1,2,..., stumpff>0
+  !!
+  !! If k<0 or stumpff<=0, the function returns 0.
+  !!
+  REAL(rprec16) FUNCTION stumpff_r16_recursive(x, k, stumpff, to_higher)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in) :: x, stumpff
+    INTEGER, INTENT(in) :: k
+    LOGICAL, OPTIONAL :: to_higher
+
+    ! k = 0,1,2,... and stumpff > 0
+    IF (k < 0 .OR. stumpff <= 0) THEN
+       stumpff_r16_recursive = 0.0_rprec16
+       RETURN
+    END IF
+
+    IF (PRESENT(to_higher)) THEN
+       IF (to_higher) THEN
+          ! c_(k+2) <- c_k
+          stumpff_r16_recursive = (1.0_rprec16/factorial(k-2) - stumpff)/x
+          RETURN
+       END IF
+    END IF
+
+    ! c_k <- c_(k+2)
+    stumpff_r16_recursive = 1.0_rprec16/factorial(k) - x*stumpff
+
+  END FUNCTION stumpff_r16_recursive
+
+
+
+
+
+  INTEGER FUNCTION factorial(k)
+
+    INTEGER, INTENT(in) :: k
+    INTEGER             :: l
+
+    ! k = 0,1,2,...
+    IF (k < 0) THEN
+       factorial = 0
+       RETURN
+    END IF
+
+    l = k
+    factorial = 1
+    DO WHILE (l > 0)
+       factorial = factorial * l
+       l = l - 1
+    END DO
+
+  END FUNCTION factorial
+
+
+
+
+
+END MODULE functions
Index: trunk/mops/oorb/modules/integrators.f90
===================================================================
--- trunk/mops/oorb/modules/integrators.f90	(revision 34646)
+++ trunk/mops/oorb/modules/integrators.f90	(revision 34646)
@@ -0,0 +1,2499 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains integrators and force routines.
+!!
+!! @author  TL, MG, JV
+!! @version 2012-02-15
+!!
+MODULE integrators
+
+  USE planetary_data
+  USE linal
+
+  IMPLICIT NONE
+  PRIVATE
+
+  !! High precicion real type for integration variables.
+  INTEGER, PARAMETER :: prec = rprec8
+  !! Value of pi (32 digits).
+  REAL(prec), PARAMETER :: pi = 3.14159265358979323846264338327950_prec
+  !! Gaussian gravitational constant.
+  REAL(prec), PARAMETER :: ggc = 0.01720209895_prec
+  !! Constant of gravitation.
+  REAL(prec), PARAMETER :: gc = ggc**2
+  !! Speed of light (AU/day).
+  REAL(prec), PARAMETER :: c = 173.14463272_prec
+  REAL(prec), PARAMETER :: ic2 = 1.0_prec/c**2
+  !! Decimal precision. 
+  REAL(prec), PARAMETER :: rstep_tol = 10*EPSILON(pi)
+  !! Decimal precision for extrapolation (or step convergence). 
+  REAL(prec), PARAMETER :: bs_extrapol_tol = 10*EPSILON(pi)
+  !! Default step length (1 days):
+  REAL(prec), PARAMETER :: step_def = 1.0_prec
+  !! Sequence of substeps (Bulirsch and Stoer).
+  INTEGER, PARAMETER :: nseq = 27
+  INTEGER, DIMENSION(nseq), PARAMETER :: &
+       seq = (/ 2, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, &
+       256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, &
+       12288, 16384, 24576 /) ! n_i = 2 * n_(i-2)
+
+  LOGICAL :: relativity = .TRUE.
+  ! Default central body for the dynamical system
+  INTEGER, PARAMETER :: central_body_prm = 11
+  INTEGER :: central_body
+
+  ! NOTE: central_body should be an input argument in all
+  ! the public routines, since from thereon it is currently
+  ! passed on as an global module parameter.
+  PUBLIC :: bulirsch_full_jpl
+  PUBLIC :: gauss_radau_15_full_jpl
+  PUBLIC :: set_relativity
+
+  INTERFACE ratf_extrapolation
+     MODULE PROCEDURE ratf_extrapolation_vec, ratf_extrapolation_mat, &
+          ratf_extrapolation_vec_n, ratf_extrapolation_mat_n 
+  END INTERFACE ratf_extrapolation
+
+  INTERFACE polf_extrapolation
+     MODULE PROCEDURE polf_extrapolation_vec, polf_extrapolation_mat, &
+          polf_extrapolation_vec_n, polf_extrapolation_mat_n
+  END INTERFACE polf_extrapolation
+
+CONTAINS
+
+
+
+
+
+  !! Description: 
+  !!   Bulirsch-Stoer scheme.
+  !!   Rational function extrapolation w/ modified midpoint. 
+  !!
+  !! References:
+  !!   [1] Press et al. 1989, Numerical Recipes. 
+  !!   [2] Stoer & Bulirsch 1980, Introduction to Num. Anal.
+  !!
+  !! Usage:
+  !!   CALL bulirsch_full_jpl(mjd_tdt0, mjd_tdt1, &
+  !!                          celements, error, jacobian, step)
+  !!
+  !! mjd_tdt0         integration start (MJD TT)
+  !! mjd_tdt1         integration stop (MJD TT)
+  !! celements        initial coordinates for massless particles (1:6,1:nparticles)
+  !! error            returns true, if something fails 
+  !! jacobian         jacobian matrix (coordinates wrt initial coordinates)
+  !! step             step size
+  !! ncenter          number of solar-system object to use as center (default=Sun)
+  !! encounters       table containing the closest distances to, or earliest
+  !!                  time of impact with solar-system objects
+  !! masses     masses for additional perturbing bodies
+  !!
+  SUBROUTINE bulirsch_full_jpl(mjd_tdt0, mjd_tdt1, celements, &
+       perturbers, error, jacobian, step, ncenter, encounters, &
+       masses, info_verb)
+
+    REAL(prec), INTENT(in)                                :: mjd_tdt0, mjd_tdt1
+    REAL(prec), DIMENSION(:,:), INTENT(inout)             :: celements
+    LOGICAL, DIMENSION(:), INTENT(in)                     :: perturbers
+    LOGICAL, INTENT(inout)                                :: error
+    REAL(prec), DIMENSION(:,:,:), INTENT(inout), OPTIONAL :: jacobian
+    REAL(prec), INTENT(in), OPTIONAL                      :: step
+    INTEGER,  INTENT(in), OPTIONAL                        :: ncenter
+    REAL(prec), DIMENSION(:,:,:), INTENT(out), OPTIONAL   :: encounters
+    REAL(prec), DIMENSION(:), INTENT(in), OPTIONAL        :: masses
+    INTEGER, INTENT(in), OPTIONAL                         :: info_verb
+
+    REAL(prec), DIMENSION(:,:,:), ALLOCATABLE :: pws, encounters_
+    REAL(prec), DIMENSION(:,:), ALLOCATABLE :: ws
+    REAL(prec) :: mjd_tdt, tmp, istep, rstep
+    INTEGER    :: i, j, k, m, n, total, err
+
+    ! The 'masses' variable refers to masses of additional
+    ! massive objects that need to be integrated and act as pertubers
+    ! for the massless particles. The orbital elements of the
+    ! additional perturbers are concatenated to the end of
+    ! 'celements'. Note that the particles are treated asymmetrically:
+    ! massless particles are not affecting the other particles (how
+    ! could they?) and additional massive particles are only affecting
+    ! the massless particles. In particular, ephemeris for planets and
+    ! large asteroids originating in de405 are not affected by the
+    ! additional massive particles.
+
+    ALLOCATE(ws(6,SIZE(celements,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,"(A)") "bulirsch_full_jpl: Could not allocate memory (5)."
+       RETURN
+    END IF
+    ws(:,1:SIZE(celements,dim=2)) = celements
+
+    IF (PRESENT(jacobian)) THEN
+       ALLOCATE(pws(SIZE(jacobian,dim=1),SIZE(jacobian,dim=2), &
+            SIZE(jacobian,dim=3)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: Could not allocate memory (10)."
+          DEALLOCATE(ws, pws, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    ! Reset the global module parameter
+    IF (PRESENT(ncenter)) THEN
+       central_body = ncenter
+    ELSE 
+       central_body = central_body_prm
+    END IF
+
+    ! Initialize the encounter table
+    IF (PRESENT(encounters)) THEN
+       IF (SIZE(encounters,dim=1) < SIZE(ws,dim=2)) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (1)."
+          RETURN
+       END IF
+       IF (SIZE(encounters,dim=2) < 11) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (2)."
+          RETURN
+       END IF
+       IF (SIZE(encounters,dim=3) < 4) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (3)."
+          RETURN
+       END IF
+       encounters = HUGE(encounters)
+       encounters(:,:,2) = 3
+       ALLOCATE(encounters_(SIZE(encounters,dim=1),SIZE(encounters,dim=2),SIZE(encounters,dim=3)))
+    END IF
+
+    ! Set integration parameters.
+    tmp = mjd_tdt1 - mjd_tdt0
+    IF (PRESENT(step)) THEN
+       istep = SIGN(step,tmp)
+    ELSE
+       ! Use default step length:
+       istep = SIGN(step_def,tmp)
+    END IF
+    total = ABS(INT(tmp/istep))
+    !rstep = SIGN(MOD(tmp,istep),tmp)
+    rstep = tmp - total*istep
+
+    IF (ABS(rstep) > ABS(istep)) THEN
+       WRITE(0,*) "There appears to be a problem with the " // &
+            "selection of # of steps in the BS integrator. " // &
+            "Please send the lines below to MG for analysis."
+       WRITE(0,*) "mjd_tdt0:    ", mjd_tdt0
+       WRITE(0,*) "mjd_tdt1:    ", mjd_tdt1
+       WRITE(0,*) "tmp:         ", tmp
+       WRITE(0,*) "istep:       ", istep
+       WRITE(0,*) "rstep:       ", rstep
+       WRITE(0,*) "total:       ", total
+       WRITE(0,*) "total*istep: ", total*istep
+       STOP
+    END IF
+
+    ! Integration loop
+    k       = 1
+    mjd_tdt = mjd_tdt0
+    IF (info_verb >= 4) THEN
+       DO i=1,SIZE(ws,dim=2)
+          WRITE(*,"(A,I0,1X,A,1X,F15.5,6(1X,F20.15))") "Orbit #", &
+               i, "at epoch", mjd_tdt0, ws(:,i)
+       END DO
+    END IF
+    IF (PRESENT(jacobian)) THEN
+       pws = jacobian
+       DO WHILE (k <= total)
+          IF (PRESENT(encounters)) THEN
+             CALL step_bulirsch_full_jpl(mjd_tdt, istep, perturbers, ws, &
+                  ws, error, pws, pws, encounters=encounters_, masses=masses)
+             ! Log closest non-impacting encounter during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+             ! Log earliest time of impact during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+                  encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+          ELSE
+             CALL step_bulirsch_full_jpl(mjd_tdt, istep, perturbers, ws, &
+                  ws, error, pws, pws, masses=masses)
+          END IF
+          IF (error) THEN
+             DEALLOCATE(ws, pws, stat=err)
+             WRITE(0,"(A)") "bulirsch_full_jpl: TRACE BACK (5)"
+             RETURN
+          END IF
+          mjd_tdt = mjd_tdt0 + k * istep
+          k       = k + 1
+          IF (info_verb >= 4) THEN
+             DO i=1,SIZE(ws,dim=2)
+                WRITE(*,"(A,I0,1X,A,1X,F15.5,6(1X,F20.15))") "Orbit #", &
+                     i, "at epoch", mjd_tdt, ws(:,i)
+             END DO
+          END IF
+       END DO
+       IF (ABS(rstep) > rstep_tol) THEN
+          IF (PRESENT(encounters)) THEN
+             CALL step_bulirsch_full_jpl(mjd_tdt, rstep, perturbers, ws, &
+                  ws, error, pws, pws, encounters=encounters_, masses=masses)
+          ELSE
+             CALL step_bulirsch_full_jpl(mjd_tdt, rstep, perturbers, ws, &
+                  ws, error, pws, pws, masses=masses)
+          END IF
+       ELSE
+          IF (PRESENT(encounters)) THEN
+             CALL step_midpoint_full_jpl(mjd_tdt, rstep, 10, perturbers, &
+                  ws, ws, error, pws, pws, encounters=encounters_, &
+                  masses=masses)
+          ELSE
+             CALL step_midpoint_full_jpl(mjd_tdt, rstep, 10, perturbers, &
+                  ws, ws, error, pws, pws, masses=masses)             
+          END IF
+       END IF
+       IF (PRESENT(encounters)) THEN
+          ! Log closest non-impacting encounter during the integration step
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+             encounters(m,n,:) = encounters_(m,n,:)
+          END FORALL
+          ! Log earliest time of impact during the integration step
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+               encounters_(m,n,1) < encounters(m,n,1))
+             encounters(m,n,:) = encounters_(m,n,:)
+          END FORALL
+       END IF
+       celements = ws
+       jacobian  = pws
+       DEALLOCATE(pws, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: Could not deallocate memory (5)."
+          RETURN
+       END IF
+    ELSE
+       DO WHILE (k <= total)
+          IF (PRESENT(encounters)) THEN
+             CALL step_bulirsch_full_jpl(mjd_tdt, istep, perturbers, ws, &
+                  ws, error, encounters=encounters_, masses=masses)
+             ! Log closest non-impacting encounter during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+             ! Log earliest time of impact during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+                  encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+          ELSE
+             CALL step_bulirsch_full_jpl(mjd_tdt, istep, perturbers, ws, &
+                  ws, error, masses=masses)
+          END IF
+          IF (error) THEN
+             DEALLOCATE(ws, stat=err)
+             WRITE(0,"(A)") "bulirsch_full_jpl: TRACE BACK (10)"
+             RETURN
+          END IF
+          mjd_tdt = mjd_tdt0 + k * istep
+          k       = k + 1
+          IF (info_verb >= 4) THEN
+             DO i=1,SIZE(ws,dim=2)
+                WRITE(*,"(A,I0,1X,A,1X,F15.5,6(1X,F20.15))") "Orbit #", &
+                     i, "at epoch", mjd_tdt, ws(:,i)
+             END DO
+          END IF
+       END DO
+       IF (ABS(rstep) > rstep_tol) THEN
+          IF (PRESENT(encounters)) THEN
+             CALL step_bulirsch_full_jpl(mjd_tdt, rstep, perturbers, ws, &
+                  ws, error, encounters=encounters_, masses=masses)
+          ELSE
+             CALL step_bulirsch_full_jpl(mjd_tdt, rstep, perturbers, ws, &
+                  ws, error, masses=masses)
+          END IF
+       ELSE
+          IF (PRESENT(encounters)) THEN
+             CALL step_midpoint_full_jpl(mjd_tdt, rstep, 10, perturbers, &
+                  ws, ws, error, encounters=encounters_, &
+                  masses=masses)
+          ELSE
+             CALL step_midpoint_full_jpl(mjd_tdt, rstep, 10, perturbers, &
+                  ws, ws, error, masses=masses)
+          END IF
+       END IF
+       IF (PRESENT(encounters)) THEN
+          ! Log closest non-impacting encounter during the integration step
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+             encounters(m,n,:) = encounters_(m,n,:)
+          END FORALL
+          ! Log earliest time of impact during the integration step
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+               encounters_(m,n,1) < encounters(m,n,1))
+             encounters(m,n,:) = encounters_(m,n,:)
+          END FORALL
+       END IF
+       celements = ws
+    END IF
+    IF (info_verb >= 4) THEN
+       DO i=1,SIZE(ws,dim=2)
+          WRITE(*,"(A,I0,1X,A,1X,F15.5,6(1X,F20.15))") "Orbit #", &
+               i, "at epoch", mjd_tdt1, ws(:,i)
+       END DO
+    END IF
+    DEALLOCATE(ws, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,"(A)") "bulirsch_full_jpl: Could not deallocate memory (10)."
+       RETURN
+    END IF
+    IF (PRESENT(encounters)) THEN
+       DEALLOCATE(encounters_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: Could not deallocate memory (15)."
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE bulirsch_full_jpl
+
+
+
+
+
+  !! One integration step.
+  !!
+  !!  mjd_tdt  modified Julian date (for ephemerides)
+  !!  H        step size
+  !!  ws0      initial coordinates for the massless bodies
+  !!  ws1      final coordinates for the massless bodies
+  !!  error    returns true, if something fails
+  !!  pws0     initial values of the partial derivatives
+  !!  pws1     final values of the partial derivatives
+  !!  
+  SUBROUTINE step_bulirsch_full_jpl(mjd_tdt, H, perturbers, ws0, ws1, &
+       error, pws0, pws1, encounters, masses)
+
+    REAL(prec), INTENT(in)                                :: mjd_tdt, H
+    LOGICAL, DIMENSION(:), INTENT(in)                     :: perturbers
+    REAL(prec), DIMENSION(:,:), INTENT(inout)             :: ws0, ws1
+    LOGICAL, INTENT(inout)                                :: error
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(inout) :: pws0, pws1
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(out)   :: encounters
+    REAL(prec), DIMENSION(:), OPTIONAL, INTENT(in)        :: masses
+
+    REAL(prec), DIMENSION(:,:,:,:,:), ALLOCATABLE :: pddif
+    REAL(prec), DIMENSION(:,:,:,:), ALLOCATABLE :: pwa0, pwa1, ddif
+    REAL(prec), DIMENSION(:,:,:), ALLOCATABLE :: wa0, wa1, pwst, encounters_
+    REAL(prec), DIMENSION(:,:), ALLOCATABLE :: wst
+    REAL(prec), DIMENSION(:), ALLOCATABLE :: hseq
+    INTEGER, DIMENSION(:), ALLOCATABLE :: ws_index, pws_index
+    INTEGER :: ws_final, pws_final, i, k, l, m, n, NS, nseq, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: ws_converged, pws_converged
+
+    ALLOCATE(hseq(SIZE(seq)), &
+         wa0(6,SIZE(seq),SIZE(ws0,dim=2)), &
+         wa1(6,SIZE(seq),SIZE(ws0,dim=2)), &
+         ddif(6,SIZE(seq),SIZE(seq),SIZE(ws0,dim=2)), &
+         wst(6,SIZE(ws0,dim=2)), &
+         ws_converged(SIZE(ws0,dim=2)), &
+         ws_index(SIZE(ws0,dim=2)), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,"(A)") "step_bulirsch_full_jpl: Could not allocate memory (5)."
+       DEALLOCATE(hseq, wa0, wa1, pwa0, pwa1, ddif, pddif, wst, &
+            pwst, ws_converged, pws_converged, ws_index, pws_index, &
+            stat=err)
+       RETURN
+    END IF
+    ws_index = 0
+    ws_converged = .FALSE.
+
+    IF (PRESENT(encounters)) THEN
+       ALLOCATE(encounters_(SIZE(encounters,dim=1),SIZE(encounters,dim=2),SIZE(encounters,dim=3)))
+       encounters = HUGE(encounters)
+       encounters(:,:,2) = 3
+    END IF
+
+    IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+       ALLOCATE(pwa0(6,SIZE(seq),6,SIZE(ws0,dim=2)), &
+            pwa1(6,SIZE(seq),6,SIZE(ws0,dim=2)), &
+            pddif(6,SIZE(seq),SIZE(seq),6,SIZE(ws0,dim=2)), &
+            pwst(6,6,SIZE(ws0,dim=2)), &
+            pws_converged(SIZE(ws0,dim=2)), &
+            pws_index(SIZE(ws0,dim=2)), &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "step_bulirsch_full_jpl: Could not allocate memory (10)."
+          DEALLOCATE(hseq, wa0, wa1, pwa0, pwa1, ddif, pddif, wst, &
+               pwst, ws_converged, pws_converged, ws_index, &
+               pws_index, stat=err)
+          RETURN
+       END IF
+       pws_index = 0
+       pws_converged = .FALSE.
+    END IF
+
+    ws_final = 0
+    pws_final = 0
+    nseq = SIZE(seq)
+    NS = SIZE(ws0,dim=2)
+
+    DO i=1, nseq
+
+       hseq(i) = (H / seq(i)) ** 2
+
+       ! Integration with seq(i) substeps.
+       IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+          IF (PRESENT(encounters)) THEN
+             CALL step_midpoint_full_jpl(mjd_tdt, H, seq(i), perturbers, &
+                  ws0, wst, error, pws0, pwst, encounters=encounters_, &
+                  masses=masses)
+             ! Log closest non-impacting encounter during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+             ! Log earliest time of impact during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+                  encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+          ELSE
+             CALL step_midpoint_full_jpl(mjd_tdt, H, seq(i), perturbers, &
+                  ws0, wst, error, pws0, pwst, masses=masses)
+          END IF
+          DO k=1, NS
+             wa0(:,i,k) = wst(:,k)
+             DO l=1, 6
+                pwa0(:,i,l,k) = pwst(:,l,k)
+             END DO
+          END DO
+       ELSE
+          IF (PRESENT(encounters)) THEN
+             CALL step_midpoint_full_jpl(mjd_tdt, H, seq(i), perturbers, &
+                  ws0, wst, error, encounters=encounters_, masses=masses)
+             ! Log closest non-impacting encounter during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+             ! Log earliest time of impact during the integration step
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) == 1 .AND. NINT(encounters_(m,n,2)) == 1 .AND. &
+                  encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,:) = encounters_(m,n,:)
+             END FORALL
+          ELSE
+             CALL step_midpoint_full_jpl(mjd_tdt, H, seq(i), perturbers, &
+                  ws0, wst, error, masses=masses)
+          END IF
+          DO k=1, NS
+             wa0(:,i,k) = wst(:,k)
+          END DO
+       END IF
+       IF (error) THEN
+          WRITE(0,"(A)") "step_bulirsch_full_jpl: TRACE BACK (5)."
+          DEALLOCATE(hseq, wa0, wa1, pwa0, pwa1, ddif, pddif, wst, &
+               pwst, ws_converged, pws_converged, ws_index, pws_index, &
+               stat=err)
+          RETURN
+       END IF
+
+       ! Fill in the extrapolation table and check for convergence.
+       IF (ws_final == 0) THEN
+          CALL polf_extrapolation(i, hseq, wa0, wa1, ddif, ws_converged, error)
+          !          CALL ratf_extrapolation(i, hseq, wa0, wa1, ddif, ws_converged, error)
+          IF (error) THEN
+             WRITE(0,"(A)") "step_bulirsch_full_jpl: TRACE BACK (10)."
+             DEALLOCATE(hseq, wa0, wa1, pwa0, pwa1, ddif, pddif, wst, &
+                  pwst, ws_converged, pws_converged, ws_index, pws_index, &
+                  stat=err)
+             RETURN
+          END IF
+          WHERE (ws_converged .AND. ws_index == 0) 
+             ws_index = i
+          END WHERE
+          IF (ALL(ws_index > 0)) THEN
+             ws_final = i
+          END IF
+       END IF
+       IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+          IF (pws_final == 0) THEN
+             CALL polf_extrapolation(i, hseq, pwa0, pwa1, pddif, pws_converged, error)
+             !             CALL ratf_extrapolation(i, hseq, pwa0, pwa1, pddif, pws_converged, error)
+             IF (error) THEN
+                WRITE(0,"(A)") "step_bulirsch_full_jpl: TRACE BACK (15)."
+                DEALLOCATE(hseq, wa0, wa1, pwa0, pwa1, ddif, pddif, wst, &
+                     pwst, ws_converged, pws_converged, ws_index, pws_index, &
+                     stat=err)
+                RETURN
+             END IF
+             WHERE (pws_converged .AND. pws_index == 0)
+                pws_index = i
+             END WHERE
+             IF (ALL(pws_index > 0)) THEN
+                pws_final = i
+             END IF
+          END IF
+       ELSE
+          pws_final = 1
+       END IF
+       IF (ws_final /= 0 .AND. pws_final /= 0) THEN
+          EXIT
+       END IF
+
+    END DO
+
+    ! If there were problems with convergence.
+    IF (ws_final == 0) THEN
+       ws_final = nseq
+       DO k=1, NS
+          IF (ws_index(k) == 0) THEN
+             ! Error report
+             ws_index(k) = nseq
+          END IF
+       END DO
+    END IF
+    IF (pws_final == 0) THEN
+       pws_final = nseq
+       DO k=1, NS
+          IF (pws_index(k) == 0) THEN
+             ! Error report
+             pws_index(k) = nseq
+          END IF
+       END DO
+    END IF
+
+    IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+       DO k=1, NS
+          ws1(:,k) = wa1(:,ws_index(k),k)
+          DO l=1, 6
+             pws1(:,l,k) = pwa1(:,pws_index(k),l,k)
+          END DO
+       END DO
+    ELSE
+       DO k=1, NS
+          ws1(:,k) = wa1(:,ws_index(k),k)
+       END DO
+    END IF
+
+    DEALLOCATE(hseq, wa0, wa1, ddif, wst, ws_converged, ws_index, &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,"(A)") "step_bulirsch_full_jpl: Could not deallocate memory (5)."
+       RETURN
+    END IF
+    IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+       DEALLOCATE(pwa0, pwa1, pddif, pwst, pws_converged, pws_index, &
+            stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "step_bulirsch_full_jpl: Could not deallocate memory (10)."
+          RETURN
+       END IF
+    END IF
+    IF (PRESENT(encounters)) THEN
+       DEALLOCATE(encounters_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "step_bulirsch_full_jpl: Could not deallocate memory (15)."
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE step_bulirsch_full_jpl
+
+
+
+
+
+
+  !! Description: 
+  !!   Modified midpoint step (2nd order).
+  !! 
+  !! References: 
+  !!   [1] Press et al. 1989, Numerical Recipes.
+  !!
+  !! Usage:
+  !!   CALL step_midpoint_full_jpl(mjd_tdt, h, nsteps, ws0, ws1, 
+  !!                               error, pws0, pws1)
+  !!
+  !! One integration step.
+  !!
+  !!  mjd_tdt  modified Julian date (for ephemerides)
+  !!  h        (big) step size
+  !!  nsteps   number of substeps
+  !!  ws0      initial coordinates for the massless bodies
+  !!  ws1      final coordinates for the massless bodies
+  !!  error    returns true, if something fails                        
+  !!  pws0     initial values of the partial derivatives
+  !!  pws1     final values of the partial derivatives
+  !!
+  SUBROUTINE step_midpoint_full_jpl(mjd_tdt, h, nsteps, perturbers, &
+       ws0, ws1, error, pws0, pws1, encounters, masses)
+
+    REAL(prec), INTENT(in)                                :: mjd_tdt, h
+    INTEGER, INTENT(in)                                   :: nsteps
+    LOGICAL, DIMENSION(:), INTENT(in)                     :: perturbers
+    REAL(prec), DIMENSION(:,:), INTENT(inout)             :: ws0, ws1
+    LOGICAL, INTENT(inout)                                :: error
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(inout) :: pws0, pws1
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(out)   :: encounters
+    REAL(prec), DIMENSION(:), OPTIONAL, INTENT(in)        :: masses
+
+    INTEGER               :: err, i, k, m, n, NS
+    INTEGER, DIMENSION(2) :: sw
+    REAL(prec)            :: dt
+
+    REAL(prec), DIMENSION(6,SIZE(ws0,dim=2),2)   :: q
+    REAL(prec), DIMENSION(6,SIZE(ws0,dim=2))     :: qd
+    REAL(prec), DIMENSION(6,6,SIZE(ws0,dim=2),2) :: pq
+    REAL(prec), DIMENSION(6,6,SIZE(ws0,dim=2))   :: pqd
+    REAL(prec), DIMENSION(:,:,:), ALLOCATABLE    :: encounters_
+
+    REAL(prec), DIMENSION(6,6) :: pqt
+
+    NS = SIZE(ws0,dim=2)
+
+    ! Substep size.
+    dt = h / nsteps
+
+    ! Algorithm needs information from two previous points.
+    ! When calculating at k+1, sw(1) points to variables at k-1,
+    ! and sw(2) to variables at k.   
+    sw(1)         = 1
+    sw(2)         = 2
+    q(:,:,sw(1))  = ws0
+    IF (PRESENT(encounters)) THEN
+       ALLOCATE(encounters_(SIZE(encounters,dim=1), &
+            SIZE(encounters,dim=2), SIZE(encounters,dim=3)), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "step_midpoint_full_jpl: Could not allocate memory (5)."
+          RETURN
+       END IF
+       encounters = 0.0_prec
+       encounters(:,:,2) = 3
+    END IF
+
+    ! If partial derivatives are needed.
+    IF (PRESENT(pws0) .AND. PRESENT(pws1)) THEN
+       pq(:,:,:,sw(1)) = pws0
+       IF (PRESENT(encounters)) THEN
+          CALL interact_full_jpl(q(:,:,sw(1)), mjd_tdt, perturbers, &
+               qd, error, pqd, encounters=encounters_, masses=masses)
+          ! Initialize log
+          encounters = encounters_
+          encounters(:,:,4) = dt
+       ELSE
+          CALL interact_full_jpl(q(:,:,sw(1)), mjd_tdt, perturbers, &
+               qd, error, pqd, masses=masses)
+       END IF
+       IF (error) THEN
+          RETURN
+       END IF
+       q(:,:,sw(2)) = q(:,:,sw(1)) + dt * qd
+       DO i=1, NS
+          pqt = MATMUL(pqd(:,:,i),pq(:,:,i,sw(1)))
+          pq(:,:,i,sw(2)) = pq(:,:,i,sw(1)) + dt * pqt
+       END DO
+       DO k=2, nsteps     
+          IF (PRESENT(encounters)) THEN
+             CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + (k - 1) * dt, &
+                  perturbers, qd, error, pqd, &
+                  encounters=encounters_, masses=masses)
+             ! Log closest non-impacting encounter during the integration substep
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,1:3) = encounters_(m,n,1:3)
+             END FORALL
+             ! Log earliest time of impact during the integration substep
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters_(m,n,2)) == 1 .AND. encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,1:3) = encounters_(m,n,1:3)
+             END FORALL
+          ELSE
+             CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + (k - 1) * dt, &
+                  perturbers, qd, error, pqd, masses=masses)
+          END IF
+          IF (error) THEN
+             RETURN
+          END IF
+          q(:,:,sw(1)) = q(:,:,sw(1)) + 2.0_prec * dt * qd
+          DO i = 1, NS
+             pqt = MATMUL(pqd(:,:,i),pq(:,:,i,sw(2)))
+             pq(:,:,i,sw(1)) = pq(:,:,i,sw(1)) + 2.0_prec * dt * pqt
+          END DO
+          sw(1:2) = sw(2:1:-1)
+       END DO
+       IF (PRESENT(encounters)) THEN
+          CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + h, perturbers, &
+               qd, error, pqd, encounters=encounters_, masses=masses)
+          ! Log closest non-impacting encounter during the integration substep
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+             encounters(m,n,1:3) = encounters_(m,n,1:3)
+          END FORALL
+          ! Log earliest time of impact during the integration substep
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters_(m,n,2)) == 1 .AND. encounters_(m,n,1) < encounters(m,n,1))
+             encounters(m,n,1:3) = encounters_(m,n,1:3)
+          END FORALL
+       ELSE
+          CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + h, perturbers, &
+               qd, error, pqd, masses=masses)
+       END IF
+       IF (error) THEN
+          RETURN
+       END IF
+       q(:,:,sw(1)) = q(:,:,sw(1)) + dt * qd
+       DO i=1, NS
+          pqt = MATMUL(pqd(:,:,i),pq(:,:,i,sw(2)))
+          pq(:,:,i,sw(1)) = pq(:,:,i,sw(1)) + dt * pqt
+       END DO
+       ws1  = (q(:,:,sw(1)) + q(:,:,sw(2))) / 2.0_prec
+       pws1 = (pq(:,:,:,sw(1)) + pq(:,:,:,sw(2))) / 2.0_prec
+    ELSE
+       ! Plain integration.
+       IF (PRESENT(encounters)) THEN
+          CALL interact_full_jpl(q(:,:,sw(1)), mjd_tdt, perturbers, &
+               qd, error, encounters=encounters_, masses=masses)
+          ! Initialize log
+          encounters(:,:,1:3) = encounters_(:,:,1:3)
+          encounters(:,:,4) = dt
+       ELSE
+          CALL interact_full_jpl(q(:,:,sw(1)), mjd_tdt, perturbers, &
+               qd, error, masses=masses)
+       END IF
+       IF (error) THEN
+          RETURN
+       END IF
+       q(:,:,sw(2)) = q(:,:,sw(1)) + dt * qd
+       DO k=2, nsteps     
+          IF (PRESENT(encounters)) THEN
+             CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + (k - 1) * dt, &
+                  perturbers, qd, error, &
+                  encounters=encounters_, masses=masses)
+             ! Log closest non-impacting encounter during the integration substep
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+                encounters(m,n,1:3) = encounters_(m,n,1:3)
+             END FORALL
+             ! Log earliest time of impact during the integration substep
+             FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+                  NINT(encounters_(m,n,2)) == 1 .AND. encounters_(m,n,1) < encounters(m,n,1))
+                encounters(m,n,1:3) = encounters_(m,n,1:3)
+             END FORALL
+          ELSE
+             CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + (k - 1) * dt, &
+                  perturbers, qd, error, masses=masses)
+          END IF
+          IF (error) THEN
+             RETURN
+          END IF
+          q(:,:,sw(1)) = q(:,:,sw(1)) + 2.0_prec * dt * qd
+          sw(1:2)      = sw(2:1:-1)
+       END DO
+       IF (PRESENT(encounters)) THEN
+          CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + h, perturbers, &
+               qd, error, encounters=encounters_, masses=masses)
+          ! Log closest non-impacting encounter during the integration substep
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters(m,n,2)) >= 2 .AND. encounters_(m,n,3) < encounters(m,n,3))
+             encounters(m,n,1:3) = encounters_(m,n,1:3)
+          END FORALL
+          ! Log earliest time of impact during the integration substep
+          FORALL (m=1:SIZE(encounters,dim=1), n=1:SIZE(encounters,dim=2), &
+               NINT(encounters_(m,n,2)) == 1 .AND. encounters_(m,n,1) < encounters(m,n,1))
+             encounters(m,n,1:3) = encounters_(m,n,1:3)
+          END FORALL
+       ELSE
+          CALL interact_full_jpl(q(:,:,sw(2)), mjd_tdt + h, perturbers, &
+               qd, error, masses=masses)
+       END IF
+       IF (error) THEN
+          RETURN
+       END IF
+       q(:,:,sw(1)) = q(:,:,sw(1)) + dt * qd
+       ws1 = (q(:,:,sw(1)) + q(:,:,sw(2))) / 2.0_prec
+    END IF
+
+    IF (PRESENT(encounters)) THEN
+       DEALLOCATE(encounters_, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "step_midpoint_full_jpl: Could not deallocate memory (5)."
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE step_midpoint_full_jpl
+
+
+
+
+
+  !! *Description*: 
+  !!
+  !!   Rational and polynomial function extrapolation for
+  !!   (Gragg-)Bulirsch-Stoer integration.
+  !!
+  !!   These routines are applicable to single vectors or single matrices
+  !!   or to groups of vectors or matrices. 
+  !!   Extrapolation is always towards zero. 
+  !!   Extrapolation converges when all of the elements of a vector/matrix
+  !!   are converged. For groups of N vectors/matrices, convergence is checked
+  !!   individually N times.
+  !!
+  !! References:
+  !!   [1] Press et al. 1989, Numerical Recipes. 
+  !!   [2] Stoer & Bulirsch 1980, Introduction to Num. Anal.
+  !!
+  !! Usage:
+  !!   CALL ratf_extrapolation(z, h, w0, w1, ddif, converged)
+  !!   CALL polf_extrapolation(z, h, w0, w1, ddif, converged)
+  !!
+  !! Fill one diagonal in rational function extrapolation table.
+  !! Applicable to vectors.
+  !!
+  !!  z          index to process in extrapolation table  
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h 
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below) 
+  !!  converged  flag for convergence
+  !!
+  SUBROUTINE ratf_extrapolation_vec(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                         :: z
+    REAL(prec), DIMENSION(:), INTENT(in)        :: h
+    REAL(prec), DIMENSION(:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:), INTENT(inout) :: ddif
+    LOGICAL, INTENT(out)                        :: converged
+    LOGICAL, INTENT(inout)                      :: error
+
+    REAL(prec), DIMENSION(:), ALLOCATABLE :: cdif, tmp1, tmp2
+    REAL(prec) :: delta
+    INTEGER :: i, j, k, err
+
+    ! Fill in the extrapolation table: (see [1] pp. 80-86 & 563-568)
+    ! Here, tables are indexed as (i,j), where the rows i represent
+    ! integrations with seq(i) substeps and columns j extrapolations
+    ! with j extrapolation points (cf. [1]: j=m+1 in (3.2.8)).
+    ! Table ddif is filled like this:
+    !   w0(1)   ddif(1,2) ddif(1,3)     ...
+    !   w0(2)   ddif(2,2)         0     ...
+    !   w0(3)           0         0     ...
+    !     ...
+    ! Extrapolated value to stepsize=0 is w0(3)+ddif(2,2)+ddif(1,3).
+
+    converged = .FALSE.
+    w1(:,z) = w0(:,z)
+
+    IF (z == 1) THEN
+       RETURN
+    END IF
+
+    ALLOCATE(cdif(SIZE(w0,dim=1)), tmp1(SIZE(w0,dim=1)), &
+         tmp2(SIZE(w0,dim=1)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(cdif, tmp1, tmp2, stat=err)
+       RETURN
+    END IF
+
+    ddif(:,z-1,1) = w0(:,z-1)
+    cdif          = w0(:,z)
+
+    DO i=z-1, 1, -1
+       j    = z - i + 1
+       tmp1 = h(i) / h(z) * ddif(:,i,j-1)
+       tmp2 = (tmp1 - cdif)
+       DO k=1, 6
+          ! Check for division by zero.
+          IF (tmp2(k) /= 0) THEN
+             tmp2(k)     = (cdif(k) - ddif(k,i,j-1)) / tmp2(k)
+             ddif(k,i,j) = cdif(k) * tmp2(k)
+             cdif(k)     = tmp1(k) * tmp2(k)
+             ! Add difference towards final extrapolation.
+             w1(k,z)     = w1(k,z) + ddif(k,i,j)
+          ELSE
+             ddif(k,i,j) = 0.0_prec
+             cdif(k)     = 0.0_prec                
+          END IF
+       END DO
+    END DO
+
+    ! Check if extrapolation is converged.
+    delta = MAXVAL(ABS(ddif(:,1,z)))
+    IF (delta < bs_extrapol_tol) THEN
+       converged = .TRUE.
+    END IF
+
+    DEALLOCATE(cdif, tmp1, tmp2, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE ratf_extrapolation_vec
+
+
+
+
+
+  !! Fill one diagonal in polynomial function extrapolation table.
+  !! Applicable to vectors.
+  !!
+  !!  z          index to process in extrapolation table  
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h 
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences 
+  !!  converged  flag for convergence
+  !!
+  SUBROUTINE polf_extrapolation_vec(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                         :: z
+    REAL(prec), DIMENSION(:), INTENT(in)        :: h
+    REAL(prec), DIMENSION(:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:), INTENT(inout) :: ddif
+    LOGICAL, INTENT(out)                        :: converged
+    LOGICAL, INTENT(inout)                      :: error
+
+    REAL(prec)                            :: delta
+    REAL(prec), DIMENSION(:), ALLOCATABLE :: cdif, tmp
+    INTEGER                               :: i, j, err
+
+    converged = .FALSE.
+    w1(:,z) = w0(:,z)
+
+    IF (z == 1) THEN
+       RETURN
+    END IF
+
+    ALLOCATE(cdif(SIZE(w0,dim=1)), tmp(SIZE(w0,dim=1)), &
+         stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(cdif, tmp, stat=err)
+       RETURN
+    END IF
+
+    ddif(:,z-1,1) = w0(:,z-1)
+    cdif          = w0(:,z)
+
+    DO i=z-1, 1, -1
+       j           = z - i + 1
+       tmp         = (cdif - ddif(:,i,j-1)) / (h(i) - h(z))
+       ddif(:,i,j) = h(z) * tmp
+       cdif        = h(i) * tmp
+       w1(:,z)     = w1(:,z) + ddif(:,i,j)
+    END DO
+
+    ! Check if extrapolation is converged.
+    delta = MAXVAL(ABS(ddif(:,1,z)))
+    IF (delta < bs_extrapol_tol) THEN
+       converged = .TRUE.
+    END IF
+
+    DEALLOCATE(cdif, tmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE polf_extrapolation_vec
+
+
+
+
+
+  !! Fill one diagonal in rational function extrapolation table.
+  !! Applicable to matrices.
+  !!
+  !!  z          index to process in extrapolation table  
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h 
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below)
+  !!  converged  flag for convergence
+  !!
+  SUBROUTINE ratf_extrapolation_mat(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                           :: z
+    REAL(prec), DIMENSION(:), INTENT(in)          :: h
+    REAL(prec), DIMENSION(:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, INTENT(out)                          :: converged
+    LOGICAL, INTENT(inout)                        :: error
+
+    INTEGER                            :: i, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: column_ok
+
+    ! This routine calls ratf_extrapolation_vec (for vectors) for each
+    ! column of the extrapolated matrix. Therefore, the last index of 
+    ! w0, w1, and ddif is the column index of the matrix. Note this 
+    ! when accessing the corresponding actual arguments.
+
+    converged = .FALSE.
+
+    ALLOCATE(column_ok(SIZE(w0,dim=3)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(column_ok, stat=err)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(w0,dim=3)
+       CALL ratf_extrapolation_vec(z, h, w0(:,:,i), w1(:,:,i), &
+            ddif(:,:,:,i), column_ok(i), error)
+       IF (error) THEN
+          DEALLOCATE(column_ok, stat=err)
+          RETURN
+       END IF
+    END DO
+    IF (ALL(column_ok)) THEN
+       converged = .TRUE.
+    END IF
+
+    DEALLOCATE(column_ok, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE ratf_extrapolation_mat
+
+
+
+
+
+  !! Fill one diagonal in polynomial function extrapolation table.
+  !! Applicable to matrices.
+  !!
+  !!  z          index to process in extrapolation table
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences
+  !!  converged  flag for convergence
+  !! 
+  SUBROUTINE polf_extrapolation_mat(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                           :: z
+    REAL(prec), DIMENSION(:), INTENT(in)          :: h
+    REAL(prec), DIMENSION(:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, INTENT(out)                          :: converged
+    LOGICAL, INTENT(inout)                        :: error
+
+    INTEGER                            :: i, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: column_ok
+
+    converged = .FALSE.
+
+    ALLOCATE(column_ok(SIZE(w0,dim=3)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(column_ok, stat=err)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(w0,dim=3) 
+       CALL polf_extrapolation_vec(z, h, w0(:,:,i), w1(:,:,i), & 
+            ddif(:,:,:,i), column_ok(i), error)
+       IF (error) THEN
+          DEALLOCATE(column_ok, stat=err)
+          RETURN
+       END IF
+    END DO
+    IF (ALL(column_ok)) THEN 
+       converged = .TRUE. 
+    END IF
+
+    DEALLOCATE(column_ok, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE polf_extrapolation_mat
+
+
+
+
+
+  !! Fill one diagonal in rational function extrapolation table.
+  !! Applicable to N individual vectors.
+  !!
+  !!  z          index to process in extrapolation table
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below)
+  !!  converged  flags for convergence
+  !!
+  SUBROUTINE ratf_extrapolation_vec_n(z, h, w0, w1, ddif, converged, error)
+
+    INTEGER, INTENT(in)                           :: z 
+    REAL(prec), DIMENSION(:), INTENT(in)          :: h
+    REAL(prec), DIMENSION(:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, DIMENSION(:), INTENT(inout)          :: converged
+    LOGICAL, INTENT(inout)                        :: error
+
+    ! The last index of w0, w1, and ddif is now N, the number of vectors.
+    ! "converged"-flags are used to check which vectors need further
+    ! extrapolation.
+
+    INTEGER :: i
+
+    DO i=1, SIZE(w0,dim=3)
+       IF (converged(i)) CYCLE
+       CALL ratf_extrapolation_vec(z, h, w0(:,:,i), w1(:,:,i), & 
+            ddif(:,:,:,i), converged(i), error)
+       IF (error) THEN
+          RETURN
+       END IF
+    END DO
+
+  END SUBROUTINE ratf_extrapolation_vec_n
+
+
+
+
+
+  !! Fill one diagonal in polynomial function extrapolation table.
+  !! Applicable to N individual vectors.
+  !!
+  !!  z          index to process in extrapolation table
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below)
+  !!  converged  flags for convergence
+  !!
+  SUBROUTINE polf_extrapolation_vec_n(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                           :: z 
+    REAL(prec), DIMENSION(:), INTENT(in)          :: h
+    REAL(prec), DIMENSION(:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, DIMENSION(:), INTENT(inout)          :: converged
+    LOGICAL, INTENT(inout)                        :: error
+
+    INTEGER :: i
+
+    DO i=1, SIZE(w0,dim=3)
+       IF (converged(i)) CYCLE
+       CALL polf_extrapolation_vec(z, h, w0(:,:,i), w1(:,:,i), & 
+            ddif(:,:,:,i), converged(i), error)
+       IF (error) THEN
+          RETURN
+       END IF
+    END DO
+
+  END SUBROUTINE polf_extrapolation_vec_n
+
+
+
+
+
+  !! Fill one diagonal in rational function extrapolation table.
+  !! Applicable to N individual matrices.
+  !!
+  !!  z          index to process in extrapolation table
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below)
+  !!  converged  flags for convergence
+  !!
+  SUBROUTINE ratf_extrapolation_mat_n(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                             :: z 
+    REAL(prec), DIMENSION(:), INTENT(in)            :: h
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, DIMENSION(:), INTENT(inout)            :: converged
+    LOGICAL, INTENT(inout)                          :: error
+
+    ! The last index of w0, w1, and ddif is N, the number of vectors.
+    ! The index before the last one is the column index of the matrix.
+    ! Only matrices that are not already converged are extrapolated further.
+
+    INTEGER :: i, j, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: column_ok
+
+    ALLOCATE(column_ok(SIZE(w0,dim=3)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(column_ok, stat=err)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(w0,dim=4)
+       IF (converged(i)) CYCLE
+       DO j=1, SIZE(w0,dim=3)
+          CALL ratf_extrapolation_vec(z, h, w0(:,:,j,i), w1(:,:,j,i), & 
+               ddif(:,:,:,j,i), column_ok(j), error)
+          IF (error) THEN
+             DEALLOCATE(column_ok, stat=err)
+             RETURN
+          END IF
+       END DO
+       IF (ALL(column_ok)) THEN 
+          converged(i) = .TRUE. 
+       END IF
+    END DO
+
+    DEALLOCATE(column_ok, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE ratf_extrapolation_mat_n
+
+
+
+
+
+  !! Fill one diagonal in polynomial function extrapolation table.
+  !! Applicable to N individual matrices.
+  !!
+  !!  z          index to process in extrapolation table
+  !!  h          sequence of step sizes used
+  !!  w0         integrations corresponding the step sizes h
+  !!  w1         extrapolated values with z integrations
+  !!  ddif       extrapolation table with differences (see below)
+  !!  converged  flags for convergence
+  !!
+  SUBROUTINE polf_extrapolation_mat_n(z, h, w0, w1, ddif, converged, &
+       error)
+
+    INTEGER, INTENT(in)                             :: z 
+    REAL(prec), DIMENSION(:), INTENT(in)            :: h
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(in)      :: w0
+    REAL(prec), DIMENSION(:,:,:,:), INTENT(out)     :: w1
+    REAL(prec), DIMENSION(:,:,:,:,:), INTENT(inout) :: ddif
+    LOGICAL, DIMENSION(:), INTENT(inout)            :: converged
+    LOGICAL, INTENT(inout)                          :: error
+
+    INTEGER :: i, j, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: column_ok
+
+    ALLOCATE(column_ok(SIZE(w0,dim=3)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(column_ok, stat=err)
+       RETURN
+    END IF
+
+    DO i=1, SIZE(w0,dim=4)
+       IF (converged(i)) CYCLE
+       DO j=1, SIZE(w0,dim=3)
+          CALL polf_extrapolation_vec(z, h, w0(:,:,j,i), w1(:,:,j,i), & 
+               ddif(:,:,:,j,i), column_ok(j), error)
+          IF (error) THEN
+             DEALLOCATE(column_ok, stat=err)
+             RETURN
+          END IF
+       END DO
+       IF (ALL(column_ok)) THEN 
+          converged(i) = .TRUE. 
+       END IF
+    END DO
+
+    DEALLOCATE(column_ok, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE polf_extrapolation_mat_n
+
+
+
+
+
+  !! Gauss-Radau integrator by Edgar Everhart
+  !! (Physics Department, University of Denver) 
+  !!
+  !! This 15th-order version is written out for faster execution.
+  !! y'=f(y,t) is class=1, y"=f(y,t) is class= -2, and y"=f(y',y,t)
+  !! is class=2. mjd_tdt1 is t(final), and mjd_tdt0 is t(initial).
+  !! ll controls sequence size. Thus ss=10**(-ll) controls the size
+  !! of a term. A typical ll-value is in the range 6 to 12. However,
+  !! if ll<0 then step is the constant sequence size used. celements
+  !! enter as the starting position-velocity vector, at time
+  !! mjd_tdt0, and are output as the final position-velocity vector
+  !! at time mjd_tdt1. Integration is in real(8) precision, also
+  !! known as 'double precision'.
+  !!
+  !! References:
+  !! E. Everhart (1985), 'An efficient integrator that uses
+  !! Gauss-Radau spacings', A. Carusi and G. B. Valsecchi (eds.),
+  !! Dynamics of Comets: Their Origin and Evolution (proceedings),
+  !! Astrophysics and Space Science Library, vol. 115, D. Reidel
+  !! Publishing Company
+  !!
+  !! E. Everhart (1974), 'Implicit single-sequence methods for
+  !! integrating orbits', Celestial Mechanics, vol. 10, no. 1,
+  !! pp. 35-55
+  !!
+  !! 
+  !! Input/output parameters:
+  !! mjd_tdt0         integration start (MJD TT)
+  !! mjd_tdt1         integration stop (MJD TT)
+  !! celements        initial coordinates for massless particles and additional perturbers (1:6,1:nparticles)
+  !! ll
+  !! class
+  !! perturbers
+  !! error            returns true, if something fails 
+  !! jacobian         jacobian matrix (new coordinates wrt initial coordinates)
+  !! step             step size
+  !! ncenter          number of solar-system object to use as center (default=Sun)
+  !! encounters       table containing the closest distances to, or earliest
+  !!                  time of impact with solar-system objects
+  !! masses     masses for additional perturbing bodies
+  !!
+  !!
+  !! @author MG (in f95)
+  !! @version   01.03.2010
+  !!
+  !!
+  !! WARNING: jacobians do not yet work properly! 
+  !!
+  SUBROUTINE gauss_radau_15_full_jpl(mjd_tdt0, mjd_tdt1, celements, &
+       ll, CLASS, perturbers, error, jacobian, step, ncenter, &
+       encounters, masses)
+
+    IMPLICIT NONE
+    REAL(prec), INTENT(in)                                :: mjd_tdt0, mjd_tdt1
+    REAL(prec), DIMENSION(:,:), INTENT(inout)             :: celements    
+    INTEGER, INTENT(in)                                   :: ll, CLASS
+    LOGICAL, DIMENSION(:), INTENT(in)                     :: perturbers
+    LOGICAL, INTENT(inout)                                :: error
+    REAL(prec), DIMENSION(:,:,:), INTENT(inout), OPTIONAL :: jacobian
+    REAL(prec), INTENT(in), OPTIONAL                      :: step
+    INTEGER, INTENT(in), OPTIONAL                         :: ncenter
+    REAL(prec), DIMENSION(:,:,:), INTENT(out), OPTIONAL   :: encounters
+    REAL(prec), DIMENSION(:), INTENT(in), OPTIONAL        :: masses
+
+    ! Gauss-Radau spacings h, scaled to the range [0,1] for
+    ! integrating to the 15th order. The sum of these values 
+    ! should be 3.73333333...
+    REAL(prec), DIMENSION(8), PARAMETER :: h = (/ 0.0_prec, &
+         0.05626256053692215_prec, 0.18024069173689236_prec, &
+         0.35262471711316964_prec, 0.54715362633055538_prec, &
+         0.73421017721541053_prec, 0.88532094683909577_prec, &
+         0.97752061356128750_prec /)
+    INTEGER, DIMENSION(8), PARAMETER :: nw = (/ 0, 0, 1, 3, 6, 10, 15, 21 /)
+    REAL(prec), DIMENSION(:,:,:), ALLOCATABLE ::b, g, e, encounters_, bd, pwd_massless
+    REAL(prec), DIMENSION(:,:), ALLOCATABLE :: w_massless1, &
+         w_massless2, wd_massless1, wd_massless2
+    REAL(prec), DIMENSION(21) :: c, d, r
+    REAL(prec), DIMENSION(7) :: w, u
+    REAL(prec), DIMENSION(3) :: tmp, gk
+    REAL(prec) :: direction, dt, pw, t, tp, w1, ss, tm, t2, tval, s, &
+         q, hv, xl
+    INTEGER :: i, j, jd, k, l, m, n, ww, la, lb, lc, ld, le, ncount, &
+         ns, nf, ni, err, naddit, norb, iorb
+    LOGICAL :: starting_seq, last_seq
+
+    IF (PRESENT(step)) THEN
+       xl = step
+    ELSE
+       xl = step_def ! default step
+    END IF
+    norb = SIZE(celements,dim=2)
+    IF (norb == 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+    ! Reset the global module parameter
+    IF (PRESENT(ncenter)) THEN
+       central_body = ncenter
+    ELSE 
+       central_body = central_body_prm
+    END IF
+
+    IF (PRESENT(masses)) THEN
+       naddit = SIZE(masses)
+    ELSE
+       naddit = 0
+    END IF
+
+    IF (PRESENT(jacobian)) THEN
+       error = .TRUE.
+       WRITE(0,*) "gauss_radau_15_full_jpl: computation of jacobians not yet available."
+       RETURN
+       ALLOCATE(w_massless1(6,norb*7), w_massless2(6,norb*7), &
+            wd_massless1(6,norb*7), wd_massless2(6,norb*7), &
+            pwd_massless(6,6,norb), b(7*norb,7,3), g(7*norb,7,3), &
+            e(7*norb,7,3), bd(7*norb,7,3), stat=err)
+       w_massless1(1:6,1:norb) = celements(1:6,1:norb)
+       DO i=1,norb
+          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1,1:6,i)
+          w_massless1(1:6,norb+(i-1)*6+2) = jacobian(2,1:6,i)
+          w_massless1(1:6,norb+(i-1)*6+3) = jacobian(3,1:6,i)
+          w_massless1(1:6,norb+(i-1)*6+4) = jacobian(4,1:6,i)
+          w_massless1(1:6,norb+(i-1)*6+5) = jacobian(5,1:6,i)
+          w_massless1(1:6,norb+(i-1)*6+6) = jacobian(6,1:6,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,1,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,2,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,3,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,4,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,5,i)
+!!$          w_massless1(1:6,norb+(i-1)*6+1) = jacobian(1:6,6,i)
+       END DO
+       w_massless2 = 0.0_prec
+    ELSE
+       ALLOCATE(w_massless1(6,norb), w_massless2(6,norb), &
+            wd_massless1(6,norb), wd_massless2(6,norb), &
+            b(norb,7,3), g(norb,7,3), e(norb,7,3), &
+            bd(norb,7,3), stat=err)
+       w_massless1(1:6,1:norb) = celements(1:6,1:norb)
+       w_massless2 = 0.0_prec
+    END IF
+
+    ! Initialize the encounter table
+    IF (PRESENT(encounters)) THEN
+       IF (SIZE(encounters,dim=1) < norb) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (1)."
+          RETURN
+       END IF
+       IF (SIZE(encounters,dim=2) < 11) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (2)."
+          RETURN
+       END IF
+       IF (SIZE(encounters,dim=3) < 4) THEN
+          error = .TRUE.
+          WRITE(0,"(A)") "bulirsch_full_jpl: 'encounters' array too small (3)."
+          RETURN
+       END IF
+       encounters = HUGE(encounters)
+       encounters(:,:,2) = 3
+       ALLOCATE(encounters_(SIZE(encounters,dim=1),SIZE(encounters,dim=2),SIZE(encounters,dim=3)))
+    END IF
+
+    starting_seq = .TRUE.
+    last_seq = .FALSE.
+    dt = mjd_tdt1 - mjd_tdt0
+    IF (dt > 0.0_prec) THEN
+       direction = 1.0_prec
+    ELSE
+       direction = -1.0_prec
+    END IF
+    xl = direction*ABS(xl)
+    pw = 1.0_prec/9.0_prec
+    ! Evaluate the constants in the w-, u-, c-, d-, and r-vectors
+    DO n=2,8
+       ww = n + n**2
+       IF (CLASS == 1) THEN
+          ww = n
+       END IF
+       w(n-1) = 1.0_prec/ww
+       ww = n
+       u(n-1) = 1.0_prec/ww
+    END DO
+    IF (CLASS == 1) THEN
+       w_massless1(4:6,:) = 0.0_prec
+    END IF
+    bd = 0.0_prec ; b = 0.0_prec ; w1 = 0.5_prec
+    IF (CLASS == 1) THEN
+       w1 = 1.0_prec
+    END IF
+    c(1) = -h(2)
+    d(1) = h(2)
+    r(1) = 1.0_prec/(h(3)-h(2))
+    la = 1 ; lc = 1
+    DO k=3,7
+       lb = la
+       la = lc + 1
+       lc = nw(k+1)
+       c(la) = -h(k)*c(lb)
+       c(lc) = c(la-1) - h(k)
+       d(la) = h(2)*d(lb)
+       d(lc) = -c(lc)
+       r(la) = 1.0_prec/(h(k+1)-h(2))
+       r(lc) = 1.0_prec/(h(k+1)-h(k))
+       DO l=4,k
+          ld = la + l - 3
+          le = lb + l - 4
+          c(ld) = c(le) - h(k)*c(le+1)
+          d(ld) = d(le) + h(l-1)*d(le+1)
+          r(ld) = 1.0_prec/(h(k+1)-h(l-1))
+       END DO
+    END DO
+    ! For some reason, the value 10 was declared 10. instead of 10.d0 in 
+    ! the original version by Everhart (1985). This lead to a difference
+    ! in the 12-13 decimal. Here it is declared similar to 10.d0:
+    ss = 10.0_prec**(-ll)
+    ! The statements above are used only once in an integration to set up the
+    ! constants. They use less than a second of execution time. Next set in
+    ! a reasonable estimate to tp based on experience. Same sign as direction.
+    ! An initial first sequence size can be set with xl even with ll positive.
+    tp = 0.1_prec*direction
+    IF (ABS(xl) > TINY(xl) .OR. ll < 0.0_prec) THEN
+       tp = xl
+    END IF
+    IF (tp/dt > 0.5_prec) THEN
+       tp = 0.5_prec*dt
+    END IF
+    ncount = 0
+    ! The starting place of the first sequence.
+    one:DO
+       ns = 0 ; nf = 0 ; ni = 6 ; tm = 0.0_prec
+       IF (PRESENT(jacobian)) THEN
+          CALL interact_full_jpl(w_massless1(1:6,1:norb), mjd_tdt0+tm, &
+               perturbers, wd_massless1, error, pwd_massless, masses=masses)
+!!$          CALL interact_full_jpl_center(w_massless1(1:6,1:norb), mjd_tdt0+tm, &
+!!$               wd_massless1, error, pwd_massless)
+          DO i=1,norb
+             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1,1:6,i)
+             w_massless1(1:6,norb+(i-1)*6+2) = pwd_massless(2,1:6,i)
+             w_massless1(1:6,norb+(i-1)*6+3) = pwd_massless(3,1:6,i)
+             w_massless1(1:6,norb+(i-1)*6+4) = pwd_massless(4,1:6,i)
+             w_massless1(1:6,norb+(i-1)*6+5) = pwd_massless(5,1:6,i)
+             w_massless1(1:6,norb+(i-1)*6+6) = pwd_massless(6,1:6,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,1,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,2,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,3,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,4,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,5,i)
+!!$             w_massless1(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,6,i)
+          END DO
+       ELSE
+          CALL interact_full_jpl(w_massless1, mjd_tdt0+tm, &
+               perturbers, wd_massless1, error, masses=masses)
+!!$          CALL interact_full_jpl_center(w_massless1, mjd_tdt0+tm, &
+!!$               wd_massless1, error)
+       END IF
+       IF (error) THEN
+          DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+               wd_massless2, pwd_massless, b, g, e, bd, stat=err)
+          RETURN
+       END IF
+       nf = nf + 1
+       ! Second loop. First find new beta-
+       ! values from the predicted b-values, following eq. (2.7) in text.
+       DO
+          DO iorb=1,SIZE(w_massless1,dim=2)
+             g(iorb,1,:) = b(iorb,1,:) + d(1)*b(iorb,2,:) + d(2)*b(iorb,3,:) + d(4)*b(iorb,4,:) + &
+                  d( 7)*b(iorb,5,:) + d(11)*b(iorb,6,:) + d(16)*b(iorb,7,:)
+             g(iorb,2,:) = b(iorb,2,:) + d(3)*b(iorb,3,:) + d(5)*b(iorb,4,:) + d(8)*b(iorb,5,:) + &
+                  d(12)*b(iorb,6,:) + d(17)*b(iorb,7,:)
+             g(iorb,3,:) = b(iorb,3,:) + d(6)*b(iorb,4,:) + d(9)*b(iorb,5,:) + d(13)*b(iorb,6,:) + &
+                  d(18)*b(iorb,7,:)
+             g(iorb,4,:) = b(iorb,4,:) + d(10)*b(iorb,5,:) + d(14)*b(iorb,6,:) + d(19)*b(iorb,7,:)
+             g(iorb,5,:) = b(iorb,5,:) + d(15)*b(iorb,6,:) + d(20)*b(iorb,7,:)
+             g(iorb,6,:) = b(iorb,6,:) + d(21)*b(iorb,7,:)
+             g(iorb,7,:) = b(iorb,7,:)
+          END DO
+          t = tp
+          t2 = t**2.0_prec
+          IF (CLASS == 1) THEN
+             t2 = t
+          END IF
+          tval = ABS(t)
+          ! This loop is 6 iterations on first sequence and two iterations therafter.
+          DO m=1,ni
+             ! This loop is for each substep within a sequence.
+             DO j=2,8
+                jd = j - 1
+                s = h(j)
+                q = s
+                IF (CLASS == 1) THEN
+                   q = 1.0_prec
+                END IF
+                DO iorb=1,SIZE(w_massless2,dim=2)
+                   ! Use eqs. (2.9) and (2.10) of text to predict
+                   ! positions at each substep:
+                   w_massless2(1:3,iorb) = w_massless1(1:3,iorb) + &
+                        q*(t*w_massless1(4:6,iorb) + &
+                        t2*s*(wd_massless1(4:6,iorb)*w1 + &
+                        s*(w(1)*b(iorb,1,:) + s*(w(2)*b(iorb,2,:) + &
+                        s*(w(3)*b(iorb,3,:) + s*(w(4)*b(iorb,4,:) + &
+                        s*(w(5)*b(iorb,5,:) + s*(w(6)*b(iorb,6,:) + &
+                        s*w(7)*b(iorb,7,:)))))))))
+
+                   IF (CLASS == 2) THEN
+                      ! Calculate the velocity predictors needed
+                      ! for general class ii.
+                      w_massless2(4:6,iorb) = w_massless1(4:6,iorb) + &
+                           s*t*(wd_massless1(4:6,iorb) + &
+                           s*(u(1)*b(iorb,1,:) + &
+                           s*(u(2)*b(iorb,2,:) + s*(u(3)*b(iorb,3,:) + &
+                           s*(u(4)*b(iorb,4,:) + s*(u(5)*b(iorb,5,:) + &
+                           s*(u(6)*b(iorb,6,:) + s*u(7)*b(iorb,7,:))))))))
+                   END IF
+                END DO
+                ! Find forces at each substep.
+                IF (PRESENT(jacobian)) THEN
+                   CALL interact_full_jpl(w_massless2(:,1:norb), mjd_tdt0+tm+s*t, &
+                        perturbers, wd_massless2, error, pwd_massless, &
+                        masses=masses)
+!!$                   CALL interact_full_jpl_center(w_massless2(:,1:norb), mjd_tdt0+tm+s*t, &
+!!$                        wd_massless2, error, pwd_massless)
+                   DO i=1,norb
+                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1,1:6,i)
+                      w_massless2(1:6,norb+(i-1)*6+2) = pwd_massless(2,1:6,i)
+                      w_massless2(1:6,norb+(i-1)*6+3) = pwd_massless(3,1:6,i)
+                      w_massless2(1:6,norb+(i-1)*6+4) = pwd_massless(4,1:6,i)
+                      w_massless2(1:6,norb+(i-1)*6+5) = pwd_massless(5,1:6,i)
+                      w_massless2(1:6,norb+(i-1)*6+6) = pwd_massless(6,1:6,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,1,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,2,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,3,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,4,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,5,i)
+!!$                      w_massless2(1:6,norb+(i-1)*6+1) = pwd_massless(1:6,6,i)
+                   END DO
+                ELSE
+                   CALL interact_full_jpl(w_massless2, &
+                        mjd_tdt0+tm+s*t, perturbers, &
+                        wd_massless2, &
+                        error, masses=masses)
+!!$                   CALL interact_full_jpl_center(w_massless2, mjd_tdt0+tm+s*t, wd_massless2, error)
+                END IF
+                IF (error) THEN
+                   DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+                        wd_massless2, pwd_massless, b, g, e, bd, stat=err)
+                   RETURN
+                END IF
+                nf = nf + 1
+                DO iorb=1,SIZE(w_massless1,dim=2)
+                   ! Find g-value for the force wd_massless2 found at the current substep. This
+                   ! section, including the case statement, uses eq. (2.4) of text.
+                   tmp = g(iorb,jd,:)
+                   gk = (wd_massless2(4:6,iorb)-wd_massless1(4:6,iorb))/s
+                   SELECT CASE (j)
+                   CASE (2)
+                      g(iorb,1,:) = gk
+                   CASE (3)
+                      g(iorb,2,:) = (gk-g(iorb,1,:))*r(1)
+                   CASE (4)
+                      g(iorb,3,:) = ((gk-g(iorb,1,:))*r(2) - g(iorb,2,:))*r(3)
+                   CASE (5)
+                      g(iorb,4,:) = (((gk-g(iorb,1,:))*r(4) - g(iorb,2,:))*r(5) - g(iorb,3,:))*r(6)
+                   CASE (6)
+                      g(iorb,5,:) = ((((gk-g(iorb,1,:))*r(7) - g(iorb,2,:))*r(8) - g(iorb,3,:))*r(9) - &
+                           g(iorb,4,:))*r(10)
+                   CASE (7) 
+                      g(iorb,6,:) = (((((gk-g(iorb,1,:))*r(11) - g(iorb,2,:))*r(12) - &
+                           g(iorb,3,:))*r(13) - g(iorb,4,:))*r(14)-g(iorb,5,:))*r(15)
+                   CASE (8) 
+                      g(iorb,7,:) = ((((((gk-g(iorb,1,:))*r(16) - g(iorb,2,:))*r(17) - g(iorb,3,:))*r(18) - &
+                           g(iorb,4,:))*r(19) - g(iorb,5,:))*r(20) - g(iorb,6,:))*r(21)
+                   END SELECT
+                   ! Update all b-values.
+                   tmp = g(iorb,jd,:) - tmp
+                   b(iorb,jd,:) = b(iorb,jd,:) + tmp
+                   ! tmp is now the improvement on g(iorb,jd,:) over its former value.
+                   ! Now we upgrade the b-value using this difference in the one term.
+                   ! This section is based on eq. (2.5).
+                   SELECT CASE (j)
+                   CASE (3)
+                      b(iorb,1,:) = b(iorb,1,:) + c(1)*tmp
+                   CASE (4)
+                      b(iorb,1,:) = b(iorb,1,:) + c(2)*tmp
+                      b(iorb,2,:) = b(iorb,2,:) + c(3)*tmp
+                   CASE (5)
+                      b(iorb,1,:) = b(iorb,1,:) + c(4)*tmp
+                      b(iorb,2,:) = b(iorb,2,:) + c(5)*tmp
+                      b(iorb,3,:) = b(iorb,3,:) + c(6)*tmp
+                   CASE (6)
+                      b(iorb,1,:) = b(iorb,1,:) + c(7)*tmp
+                      b(iorb,2,:) = b(iorb,2,:) + c(8)*tmp
+                      b(iorb,3,:) = b(iorb,3,:) + c(9)*tmp
+                      b(iorb,4,:) = b(iorb,4,:) + c(10)*tmp
+                   CASE (7)
+                      b(iorb,1,:) = b(iorb,1,:) + c(11)*tmp
+                      b(iorb,2,:) = b(iorb,2,:) + c(12)*tmp
+                      b(iorb,3,:) = b(iorb,3,:) + c(13)*tmp
+                      b(iorb,4,:) = b(iorb,4,:) + c(14)*tmp
+                      b(iorb,5,:) = b(iorb,5,:) + c(15)*tmp
+                   CASE (8)
+                      b(iorb,1,:) = b(iorb,1,:) + c(16)*tmp
+                      b(iorb,2,:) = b(iorb,2,:) + c(17)*tmp
+                      b(iorb,3,:) = b(iorb,3,:) + c(18)*tmp
+                      b(iorb,4,:) = b(iorb,4,:) + c(19)*tmp
+                      b(iorb,5,:) = b(iorb,5,:) + c(20)*tmp
+                      b(iorb,6,:) = b(iorb,6,:) + c(21)*tmp
+                   END SELECT
+                END DO
+             END DO
+             IF (ll >= 0.0_prec .AND. m >= ni) THEN
+                ! Integration of sequence is over. Next is sequence size control.
+                hv = MAXVAL(ABS(b(1,7,:)))
+                DO iorb=2,SIZE(b,dim=1)
+                   IF (hv < MAXVAL(ABS(b(iorb,7,:)))) THEN
+                      hv = MAXVAL(ABS(b(iorb,7,:)))
+                   END IF
+                END DO
+                hv = hv*w(7)/tval**7.0_prec
+             END IF
+          END DO
+          !return
+          IF (starting_seq) THEN
+             IF (ll >= 0.0_prec) THEN
+                tp = (ss/hv)**pw*direction
+                IF (tp/t <= 1.0_prec) THEN
+                   tp = 0.8_prec*tp
+                   ncount = ncount + 1
+                   IF (ncount > 10) THEN
+                      error = .TRUE.
+                      DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+                           wd_massless2, pwd_massless, b, g, e, bd, stat=err)
+                      RETURN
+                   END IF
+                   ! restart with 0.8x sequence size if new size called for is smaller than
+                   ! originally chosen starting sequence size on first sequence.
+                   CYCLE one
+                END IF
+             ELSE
+                tp = xl
+             END IF
+             starting_seq = .FALSE.
+             ! Loop 35 finds new x and v values at end of sequence using eqs. (2.11),(2.12)
+          END IF
+          DO iorb=1,SIZE(w_massless1,dim=2)
+             w_massless1(1:3,iorb) = w_massless1(1:3,iorb) + w_massless1(4:6,iorb)*t + &
+                  t2*(wd_massless1(4:6,iorb)*w1 + b(iorb,1,:)*w(1) + &
+                  b(iorb,2,:)*w(2) + b(iorb,3,:)*w(3) + b(iorb,4,:)*w(4) + &
+                  b(iorb,5,:)*w(5) + b(iorb,6,:)*w(6)+b(iorb,7,:)*w(7))
+             IF (CLASS /= 1) THEN
+                w_massless1(4:6,iorb) = w_massless1(4:6,iorb) + t*(wd_massless1(4:6,iorb) &
+                     + b(iorb,1,:)*u(1) + b(iorb,2,:)*u(2) + b(iorb,3,:)*u(3) + &
+                     b(iorb,4,:)*u(4) + b(iorb,5,:)*u(5) + b(iorb,6,:)*u(6) + &
+                     b(iorb,7,:)*u(7))
+             END IF
+          END DO
+          tm = tm + t
+          ns = ns + 1
+          ! Return if done.
+          IF (last_seq) THEN
+             IF (PRESENT(jacobian)) THEN
+                celements(1:6,1:norb) = w_massless1(1:6,1:norb)
+                DEALLOCATE(pwd_massless, stat=err)
+                IF (err /= 0) THEN
+                   error = .TRUE.
+                   DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+                        wd_massless2, b, g, e, bd, stat=err)
+                   RETURN
+                END IF
+             ELSE
+                celements = w_massless1
+             END IF
+             DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+                  wd_massless2, b, g, e, bd, stat=err)
+             IF (err /= 0) THEN
+                error = .TRUE.
+                RETURN
+             END IF
+             RETURN
+          END IF
+          ! Control on size of next sequence and adjust last sequence to exactly
+          ! cover the integration span. last_seq=.true. Set on last sequence.
+          IF (PRESENT(jacobian)) THEN
+             CALL interact_full_jpl(w_massless1(1:6,1:norb), mjd_tdt0+tm, &
+                  perturbers, wd_massless1, error, pwd_massless, &
+                  masses=masses)
+          ELSE
+             CALL interact_full_jpl(w_massless1, mjd_tdt0+tm, &
+                  perturbers, wd_massless1, error, &
+                  masses=masses)
+          END IF
+          IF (error) THEN
+             DEALLOCATE(w_massless1, w_massless2, wd_massless1, &
+                  wd_massless2, pwd_massless, b, g, e, bd, stat=err)
+             RETURN
+          END IF
+          nf = nf + 1
+          IF (ll >= 0.0_prec) THEN
+             tp = direction*(ss/hv)**pw
+             IF (tp/t > 1.4_prec) THEN
+                tp = t*1.4_prec
+             END IF
+          END IF
+          IF (ll < 0.0_prec) THEN
+             tp = xl
+          END IF
+          IF (direction*(tm+tp) >= direction*dt - 1.e-8_prec) THEN
+             tp = dt - tm
+             last_seq = .TRUE.
+          END IF
+          ! Now predict b-values for next step. The predicted values from the preceding
+          ! sequence were saved in the e-matrix. The correction bd between the actual
+          ! b-values found and these predicted values is applied in advance to the
+          ! next sequence. The gain in accuracy is significant. Using eqs. (2.13):
+          q = tp/t
+          DO iorb=1,SIZE(w_massless1,dim=2)
+             IF (ns /= 1) THEN
+                bd(iorb,1:7,:) = b(iorb,1:7,:) - e(iorb,1:7,:)
+             END IF
+             e(iorb,1,:) = q*(b(iorb,1,:) + 2.0_prec*b(iorb,2,:) + &
+                  3.0_prec*b(iorb,3,:) + 4._prec*b(iorb,4,:) + 5._prec*b(iorb,5,:) + &
+                  6._prec*b(iorb,6,:) + 7._prec*b(iorb,7,:))
+             e(iorb,2,:) = q**2*(b(iorb,2,:) + 3.0_prec*b(iorb,3,:) + 6.0_prec*b(iorb,4,:) + &
+                  10.0_prec*b(iorb,5,:) + 15.0_prec*b(iorb,6,:)+ 21.0_prec*b(iorb,7,:))
+             e(iorb,3,:) = q**3*(b(iorb,3,:) + 4.0_prec*b(iorb,4,:) + 10.0_prec*b(iorb,5,:)+ &
+                  20.0_prec*b(iorb,6,:)+ 35.0_prec*b(iorb,7,:))
+             e(iorb,4,:) = q**4*(b(iorb,4,:) + 5.0_prec*b(iorb,5,:) + 15.0_prec*b(iorb,6,:) + &
+                  35.0_prec*b(iorb,7,:))
+             e(iorb,5,:) = q**5*(b(iorb,5,:) + 6.0_prec*b(iorb,6,:) + 21.0_prec*b(iorb,7,:))
+             e(iorb,6,:) = q**6*(b(iorb,6,:) + 7.0_prec*b(iorb,7,:))
+             e(iorb,7,:) = q**7*b(iorb,7,:)
+             b(iorb,1:7,:) = e(iorb,1:7,:) + bd(iorb,1:7,:)
+          END DO
+          ! Two iterations for every sequence after the first.
+          ni = 2
+       END DO
+       EXIT
+    END DO one
+
+  END SUBROUTINE gauss_radau_15_full_jpl
+
+
+
+
+
+  !! Description: 
+  !!   Evaluation of the full Newtonian force function for several 
+  !!   massless bodies. Positions of the massive bodies are read 
+  !!   from JPL ephemerides. A relativistic term due to the Sun is included.
+  !!   Optional argument triggers evaluation of the partial derivatives
+  !!   of the force function wrt Cartesian coordinates.
+  !!
+  !! References:
+  !!   [1] Karttunen, Taivaanmekaniikka
+  !!
+  !! Usage:
+  !!   CALL interact_full_jpl(ws, mjd_tdt, wds, error, pwds)
+  !!
+  !! Interaction.
+  !!
+  !!  ws           heliocentric, equatorial, Cartesian coordinates for bodies
+  !!                that need to be integrated (massless particles +
+  !!                additional perturbers)
+  !!  mjd_tdt      modified Julian date (for ephemerides)
+  !!  wds          evaluated force function
+  !!  perturbers   boolean mask for the basic set of perturbers available (true = use in force model)
+  !!  error        true, if reading from ephemerides fails
+  !!  pwds         evaluated partial derivatives of the force function
+  !!  encounters   encounters(i,j) where i=massless particle,
+  !!                j=perturber, encounters(i,j)=1 or 2, where 1=within
+  !!                planetary radius (~collision) and 2=outside
+  !!                planetary radius
+  !!  masses       masses for additional perturbers
+  !!
+  SUBROUTINE interact_full_jpl(ws, mjd_tdt, perturbers, wds, error, pwds, encounters, masses)
+
+    REAL(prec), DIMENSION(:,:), INTENT(in)              :: ws
+    REAL(prec), INTENT(in)                              :: mjd_tdt
+    LOGICAL, DIMENSION(:), INTENT(in)                   :: perturbers ! = basic perturbers (planets + Moon + Pluto)
+    REAL(prec), DIMENSION(:,:), INTENT(out)             :: wds
+    LOGICAL, INTENT(inout)                              :: error
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(out) :: pwds 
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(out) :: encounters
+    REAL(prec), DIMENSION(:), OPTIONAL, INTENT(in)      :: masses
+
+    ! Number of basic perturbers.
+    INTEGER :: N
+
+    ! Number of active basic perturbers.
+    INTEGER :: NP
+
+    ! Number of massless bodies.
+    INTEGER :: NS
+
+    ! Coordinates for the massive bodies.
+    REAL(prec), DIMENSION(:,:), POINTER :: wc
+
+    ! Various distances.
+    REAL(prec), DIMENSION(3,SIZE(perturbers)) :: drs 
+    REAL(prec), DIMENSION(SIZE(perturbers)) :: ir3c
+    REAL(prec), DIMENSION(SIZE(perturbers)) :: r2d, ir3d, ir5d
+    REAL(prec), DIMENSION(3,SIZE(ws,dim=2)) :: drs_ 
+    REAL(prec), DIMENSION(SIZE(ws,dim=2)) :: ir3c_
+    REAL(prec), DIMENSION(SIZE(ws,dim=2)) :: r2d_, ir3d_, ir5d_
+    REAL(prec) :: r2c, r2s, ir3s, ir5s, ir4s, v2s, us, ir6s, dist
+
+    ! Utility variables.
+    REAL(prec), DIMENSION(3,3) :: A, B, P1, P2 
+    INTEGER :: i, iaddit, j, k, l, err, naddit
+
+    naddit = 0
+    IF (PRESENT(masses)) THEN
+       DO i=1,SIZE(masses)
+          IF (masses(i) > 0.0_prec) THEN
+             naddit = naddit + 1
+          END IF
+       END DO
+       !write(*,*) 'interact_full_jpl', naddit, masses
+    END IF
+
+    ! Number of basic perturbers.
+    N = SIZE(perturbers)
+    NP = COUNT(perturbers)
+
+    ! Number of test particles (ie, bodies massless wrt basic perturbers).
+    NS = SIZE(ws,dim=2)
+
+    IF (NP > 0) THEN
+       ! Get positions of massive bodies (-10 = 9 planets + Moon).
+       !wc => JPL_ephemeris(mjd_tdt, perturbers(:), 11, error)
+       wc => JPL_ephemeris(mjd_tdt, -10, 11, error)
+       IF (error) THEN 
+          DEALLOCATE(wc, stat=err)
+          RETURN 
+       END IF
+    END IF
+
+    ! Useful quantities. 
+    ir3c = 0.0_prec
+    ir3c_ = 0.0_prec
+    ! Basic perturbers
+    IF (NP > 0) THEN
+       DO i=1,N
+          IF (perturbers(i)) THEN
+             r2c  = DOT_PRODUCT(wc(i,1:3), wc(i,1:3)) 
+             ir3c(i) = 1.0_prec / (r2c * SQRT(r2c)) 
+          END IF
+       END DO
+    END IF
+    IF (naddit > 0) THEN
+       ! Additional perturbers
+       DO i=1,NS
+          IF (masses(i) > 0.0_prec) THEN
+             r2c  = DOT_PRODUCT(ws(1:3,i), ws(1:3,i)) 
+             ir3c_(i) = 1.0_prec / (r2c * SQRT(r2c)) 
+          END IF
+       END DO
+    END IF
+
+    ! Loop over bodies to be integrated.
+    DO i=1,NS
+
+       r2s  = DOT_PRODUCT(ws(1:3,i), ws(1:3,i)) ! ws(6,NS) 
+       ir3s = 1.0_prec / (r2s * SQRT(r2s)) 
+       drs = 0.0_prec ; r2d = 0.0_prec ; ir3d = 0.0_prec
+       IF (COUNT(perturbers) > 0) THEN
+          ! Log impacts and distances to solar-system objects
+          DO j=1,N
+             IF (j <= N .AND. NP > 0) THEN
+                ! Basic perturbers. Compute drs and r2d regardless of
+                ! perturbers to be included in the force model (as long
+                ! as there is at least one perturber included in the
+                ! force model) so that the distance to planets can be
+                ! logged:
+                drs(1:3,j) = wc(j,1:3) - ws(1:3,i) 
+                r2d(j)     = DOT_PRODUCT(drs(1:3,j), drs(1:3,j)) 
+                IF (perturbers(j)) THEN
+                   ir3d(j)    = 1.0_prec / (r2d(j) * SQRT(r2d(j)))
+                END IF
+                IF (PRESENT(encounters)) THEN
+                   dist = SQRT(r2d(j))
+                   ! Basic perturbers
+                   IF (dist < planetary_radii(j)) THEN
+                      encounters(i,j,1) = mjd_tdt ! date
+                      encounters(i,j,2) = 1       ! = impact          
+                      encounters(i,j,3) = dist    ! distance
+                   ELSE
+                      encounters(i,j,1) = mjd_tdt ! date
+                      encounters(i,j,2) = 2       ! = non-impact
+                      encounters(i,j,3) = dist    ! distance
+                   END IF
+                END IF
+             END IF
+          END DO
+       END IF
+       IF (naddit > 0) THEN
+          iaddit = 0
+          DO j=1,NS
+             IF (masses(j) > 0.0_prec) THEN
+                iaddit = iaddit + 1
+                ! Additional perturbers
+                IF (j == i) THEN
+                   ! Skip references to self
+                   CYCLE
+                END IF
+                drs_(1:3,j) = ws(1:3,j) - ws(1:3,i) 
+                !write(*,*) j, i, masses(j), drs_(1:3,j), ws(1:3,j), ws(1:3,i)
+                r2d_(j)     = DOT_PRODUCT(drs_(1:3,j), drs_(1:3,j)) 
+                ir3d_(j)    = 1.0_prec / (r2d_(j) * SQRT(r2d_(j)))
+                IF (PRESENT(encounters)) THEN
+                   dist = SQRT(r2d_(j))
+                   ! Additional perturbers
+                   encounters(i,SIZE(encounters,dim=2)-naddit+iaddit,1) = mjd_tdt ! date
+                   encounters(i,SIZE(encounters,dim=2)-naddit+iaddit,2) = 2       ! always non-impact (we don't know the size)
+                   encounters(i,SIZE(encounters,dim=2)-naddit+iaddit,3) = dist    ! distance
+                END IF
+             END IF
+             IF (iaddit == naddit) THEN
+                EXIT
+             END IF
+          END DO
+       END IF
+       IF (PRESENT(encounters)) THEN
+          ! Distance to Sun
+          dist = SQRT(DOT_PRODUCT(ws(1:3,i), ws(1:3,i)))
+          IF (dist < planetary_radii(11)) THEN
+             encounters(i,11,1) = mjd_tdt 
+             encounters(i,11,2) = 1
+             encounters(i,11,3) = dist
+          ELSE
+             encounters(i,11,1) = mjd_tdt
+             encounters(i,11,2) = 2
+             encounters(i,11,3) = dist
+          END IF
+       END IF
+
+       ! Initialize force function.
+       wds(1:3,i) = ws(4:6,i)
+       wds(4:6,i) = 0.0_prec
+
+       ! Non-integrable part of the interaction.
+       ! Basic perturbers
+       DO j=1,N
+          IF (perturbers(j)) THEN
+             wds(4:6,i) = wds(4:6,i) + &
+                  planetary_masses(j)* (drs(1:3,j) * ir3d(j) - wc(j,1:3) * ir3c(j))
+          END IF
+       END DO
+       IF (naddit > 0) THEN
+          ! Additional perturbers
+          iaddit = 0
+          DO j=1,NS
+             IF (masses(j) <= 0.0_prec) THEN
+                CYCLE
+             END IF
+             iaddit = iaddit + 1
+             IF (i == j) THEN
+                CYCLE
+             END IF
+             wds(4:6,i) = wds(4:6,i) + &
+                  masses(j) * (drs_(1:3,j) * ir3d_(j) - ws(1:3,j) * ir3c_(j))
+             IF (iaddit == naddit) THEN
+                EXIT
+             END IF
+          END DO
+       END IF
+       wds(4:6,i) = gc * wds(4:6,i)
+
+       ! Integrable part of the interaction.
+       wds(4:6,i) = wds(4:6,i) - gc * ws(1:3,i) * ir3s
+
+       ! Relativistic term from the Sun (isotropic coordinates).
+       ! (Sitarski (1983) AcA 33)
+       ir4s = 1.0_prec / (r2s ** 2)
+       v2s  = DOT_PRODUCT(ws(4:6,i), ws(4:6,i))
+       us   = DOT_PRODUCT(ws(1:3,i), ws(4:6,i))
+       ! Optionally, no relativistic term (see global module parameter)
+       IF (relativity) THEN
+          wds(4:6,i) = wds(4:6,i) &
+               + gc * ((4.0_prec * gc * ir4s - v2s * ir3s) * ws(1:3,i) &
+               + 4.0_prec * us * ir3s * ws(4:6,i)) * ic2
+       END IF
+
+       ! Optional part.
+       IF (PRESENT(pwds)) THEN
+
+          ! Some useful quantities.
+          ir5s = ir3s / r2s
+          ir5d = ir3d / r2d
+          ir6s = ir4s / r2s
+          ir5d_ = ir3d_ / r2d_
+
+          ! Non-integrable part of the interaction
+          A = 0.0_prec
+          ! Basic perturbers
+          DO j=1,N
+             IF (perturbers(j)) THEN
+                DO k=1,3
+                   DO l=1,3
+                      A(k,l) = A(k,l) + 3.0_prec * planetary_masses(j) &
+                           * drs(k,j) * drs(l,j) * ir5d(j)
+                   END DO
+                   A(k,k) = A(k,k) - planetary_masses(j) * ir3d(j)
+                END DO
+             END IF
+          END DO
+          IF (naddit > 0) THEN
+             ! Additional perturbers
+             iaddit = 0
+             DO j=1,NS
+                IF (masses(j) <= 0.0_prec) THEN
+                   CYCLE
+                END IF
+                iaddit = iaddit + 1
+                IF (i == j) THEN
+                   CYCLE
+                END IF
+                DO k=1,3
+                   DO l=1,3
+                      A(k,l) = A(k,l) + 3.0_prec * masses(j) &
+                           * drs_(k,j) * drs_(l,j) * ir5d_(j)
+                   END DO
+                   A(k,k) = A(k,k) - masses(j) * ir3d_(j)
+                END DO
+                IF (iaddit == naddit) THEN
+                   EXIT
+                END IF
+             END DO
+          END IF
+          A = gc * A
+
+          ! Integrable part of the interaction
+          DO k=1,3
+             DO l=1,3 
+                B(k,l) = 3.0_prec * ws(k,i) * ws(l,i) * ir5s
+             END DO
+             B(k,k) = B(k,k) - ir3s
+          END DO
+          B = gc * B
+
+          ! Relativistic term from the Sun
+          IF (relativity) THEN
+             DO k=1,3
+                DO l=1,3 
+                   P1(k,l) = (3.0_prec * v2s * ir5s - &
+                        16.0_prec * gc * ir6s) * ws(k,i) * ws(l,i) - &
+                        12.0_prec * us * ir5s * ws(k+3,i) * ws(l,i) + &
+                        4.0_prec * ir3s * ws(k+3,i) * ws(l+3,i)
+                END DO
+                P1(k,k) = P1(k,k) + 4.0_prec *gc * ir4s - v2s * ir3s
+             END DO
+             P1 = gc * ic2 * P1
+
+             DO k=1,3
+                DO l=1,3 
+                   P2(k,l) = 2.0_prec * ws(k+3,i) * ws(l,i) - ws(k,i) * ws(l+3,i)
+                END DO
+                P2(k,k) = P2(k,k) + 2.0_prec * us
+             END DO
+             P2 = 2.0_prec * gc * ic2 * ir3s * P2
+          ELSE
+             P1 = 0.0_prec
+             P2 = 0.0_prec
+          END IF
+
+          ! Partial derivatives of the force function.
+          ! Put the parts together.
+          pwds(:,:,i) = 0.0_prec
+          DO k=1,3
+             pwds(k,k+3,i) = 1.0_prec
+          END DO
+          pwds(4:6,1:3,i) = A + B + P1
+          pwds(4:6,4:6,i) = P2
+
+       END IF
+
+    END DO
+
+    IF (ASSOCIATED(wc)) THEN
+       DEALLOCATE(wc, stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          RETURN
+       END IF
+    END IF
+
+  END SUBROUTINE interact_full_jpl
+
+
+
+
+
+
+  !! Description: 
+  !!   Evaluation of the full Newtonian force function for several 
+  !!   massless bodies. Positions of the massive bodies are read 
+  !!   from JPL ephemerides. A relativistic term due to the Sun is included.
+  !!   Optional argument triggers evaluation of the partial derivatives
+  !!   of the force function wrt Cartesian coordinates.
+  !!
+  !! References:
+  !!   [1] Karttunen, Taivaanmekaniikka
+  !!
+  !! Usage:
+  !!   CALL interact_full_jpl(ws, mjd_tdt, wds, error, pwds)
+  !!
+  !! Interaction.
+  !!
+  !!  ws       planetocentric, ecliptical (are not they equatorial??), Cartesian coordinates
+  !!                 for the massless bodies
+  !!  mjd_tdt  modified Julian date (for ephemerides)
+  !!  wds      evaluated force function
+  !!  error    true, if reading from ephemerides fails
+  !!  pwds     evaluated partial derivatives of the force function
+  !!
+  SUBROUTINE interact_full_jpl_center(ws, mjd_tdt, wds, error, pwds)
+
+    REAL(prec), DIMENSION(:,:), INTENT(in)              :: ws
+    REAL(prec), INTENT(in)                              :: mjd_tdt
+    REAL(prec), DIMENSION(:,:), INTENT(out)             :: wds
+    LOGICAL, INTENT(inout)                              :: error
+    REAL(prec), DIMENSION(:,:,:), OPTIONAL, INTENT(out) :: pwds 
+
+    ! Number of massive bodies.
+    INTEGER, PARAMETER :: N = 11
+    ! Number of massless bodies.
+    INTEGER            :: NS
+
+    ! Coordinates for the massive bodies.
+    REAL(prec), DIMENSION(:,:), POINTER :: wc_sun
+    REAL(prec), DIMENSION(:,:), ALLOCATABLE :: wc
+    !REAL(prec), DIMENSION(10,6) :: wc
+
+    ! Planetary masses.
+    REAL(prec), DIMENSION(N) :: m
+
+    ! Various distances.
+    REAL(prec)                 :: r2s, ir3s, ir5s
+    REAL(prec), DIMENSION(N)   :: r2c, ir3c
+    REAL(prec), DIMENSION(3,N) :: drs 
+    REAL(prec), DIMENSION(N)   :: r2d, ir3d, ir5d
+    REAL(prec)                 :: ir4s, v2s, us, ir6s
+
+    ! Utility variables.
+    REAL(prec), DIMENSION(3,3) :: A, B, P1, P2 
+    INTEGER :: i, j, k, l, err
+
+
+    IF (central_body /= 11 .AND. relativity) THEN
+       error = .TRUE.
+       ! Relativity term can currently only be used in heliocentric system.
+       RETURN
+    END IF
+
+    ! Get heliocentric positions of massive bodies (-10 = 9 planets + Moon).
+    wc_sun => JPL_ephemeris(mjd_tdt, -10, 11, error)
+    IF (error) THEN 
+       DEALLOCATE(wc_sun, stat=err)
+       RETURN 
+    END IF
+
+    ALLOCATE(wc(SIZE(wc_sun,dim=1)+1,SIZE(wc_sun,dim=2)),stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(wc_sun, wc, stat=err)
+       RETURN
+    END IF
+
+    ! Change of origin
+    IF (central_body /= 11) THEN
+       ! Sun
+       wc(N,1:3) = -1.0_prec * wc_sun(central_body, 1:3)
+       ! Other massive bodies
+       DO i = 1, N-1
+          wc(i,1:3) = wc_sun(i,1:3) - wc_sun(central_body, 1:3)
+       END DO
+    ELSE
+       wc(1:N-1,1:3) = wc_sun(1:N-1,1:3)
+    END IF
+
+    ! Planetary masses + Sun.
+    m(1:N) = planetary_masses(1:N)
+
+    ! Useful quantities. 
+    DO i = 1, N
+       r2c(i)  = DOT_PRODUCT(wc(i,1:3), wc(i,1:3)) 
+       ir3c(i) = 1.0_prec / (r2c(i) * SQRT(r2c(i))) 
+    END DO
+
+    ! Number of massless bodies.
+    NS = SIZE(ws,dim=2)
+
+    ! Loop over massless bodies.
+    DO i = 1, NS
+
+       r2s  = DOT_PRODUCT(ws(1:3,i), ws(1:3,i)) ! ws(6,NS) 
+       ir3s = 1.0_prec / (r2s * SQRT(r2s)) 
+       DO j = 1, N 
+          drs(1:3,j) = wc(j,1:3) - ws(1:3,i) 
+          r2d(j)     = DOT_PRODUCT(drs(1:3,j), drs(1:3,j)) 
+          ir3d(j)    = 1.0_prec / (r2d(j) * SQRT(r2d(j))) 
+       END DO
+
+       ! Initialize force function.
+       wds(1:3,i) = ws(4:6,i)
+       wds(4:6,i) = 0.0_prec
+
+       ! Non-integrable part of the interaction.
+       DO j = 1, N
+          IF (j == central_body) CYCLE
+          wds(4:6,i) = wds(4:6,i) + &
+               m(j)* (drs(1:3,j) * ir3d(j) - wc(j,1:3) * ir3c(j))
+          !if (j == 3) print*,m(j)* (drs(1:3,j) * ir3d(j) - wc(j,1:3) * ir3c(j))
+       END DO
+       wds(4:6,i) = gc * wds(4:6,i)
+
+       ! Integrable part of the interaction.
+       !wds(4:6,i) = wds(4:6,i) - gc * ws(1:3,i) * ir3s
+       wds(4:6,i) = wds(4:6,i) - planetary_mu(central_body) * ws(1:3,i) * ir3s
+
+       ! Relativistic term from the Sun (isotropic coordinates).
+       ! CHECK THIS FOR NON-HELIOCENTRIC FRAME!
+       ! (Sitarski (1983) AcA 33)
+       ir4s = 1.0_prec / (r2s ** 2)
+       v2s  = DOT_PRODUCT(ws(4:6,i), ws(4:6,i))
+       us   = DOT_PRODUCT(ws(1:3,i), ws(4:6,i))
+       ! Optionally, no relativistic term (see global module parameter)
+       IF (relativity) THEN
+          wds(4:6,i) = wds(4:6,i) &
+               + gc * ((4.0_prec * gc * ir4s - v2s * ir3s) * ws(1:3,i) &
+               + 4.0_prec * us * ir3s * ws(4:6,i)) * ic2
+       END IF
+
+       ! Optional part.
+       IF (PRESENT(pwds)) THEN
+
+          ! Some useful quantities.
+          ir5s = ir3s / r2s
+          ir5d = ir3d / r2d
+          ir6s = ir4s / r2s
+
+          ! Non-integrable part of the interaction
+          A = 0.0_prec
+          DO j = 1, N
+             IF (j == central_body) CYCLE
+             DO k = 1, 3
+                DO l = 1, 3
+                   A(k,l) = A(k,l) + 3.0_prec * m(j) &
+                        * drs(k,j) * drs(l,j) * ir5d(j)
+                END DO
+                A(k,k) = A(k,k) - m(j) * ir3d(j)
+             END DO
+          END DO
+          A = gc * A
+
+          ! Integrable part of the interaction
+          DO k = 1, 3
+             DO l = 1, 3 
+                B(k,l) = 3.0_prec * ws(k,i) * ws(l,i) * ir5s
+             END DO
+             B(k,k) = B(k,k) - ir3s
+          END DO
+          B = gc * B
+
+          ! Relativistic term from the Sun
+          IF (relativity) THEN
+             DO k = 1, 3
+                DO l = 1, 3 
+                   P1(k,l) = (3.0_prec * v2s * ir5s - &
+                        16.0_prec * gc * ir6s) * ws(k,i) * ws(l,i) - &
+                        12.0_prec * us * ir5s * ws(k+3,i) * ws(l,i) + &
+                        4.0_prec * ir3s * ws(k+3,i) * ws(l+3,i)
+                END DO
+                P1(k,k) = P1(k,k) + 4.0_prec *gc * ir4s - v2s * ir3s
+             END DO
+             P1 = gc * ic2 * P1
+
+             DO k = 1, 3
+                DO l = 1, 3 
+                   P2(k,l) = 2.0_prec * ws(k+3,i) * ws(l,i) - ws(k,i) * ws(l+3,i)
+                END DO
+                P2(k,k) = P2(k,k) + 2.0_prec * us
+             END DO
+             P2 = 2.0_prec * gc * ic2 * ir3s * P2
+          ELSE
+             P1 = 0.0_prec
+             P2 = 0.0_prec
+          END IF
+
+          ! Partial derivatives of the force function.
+          ! Put the parts together.
+          pwds(:,:,i) = 0.0_prec
+          DO k = 1, 3
+             pwds(k,k+3,i) = 1.0_prec
+          END DO
+          pwds(4:6,1:3,i) = A + B + P1
+          pwds(4:6,4:6,i) = P2
+
+       END IF
+
+    END DO
+
+    DEALLOCATE(wc, wc_sun, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       RETURN
+    END IF
+
+  END SUBROUTINE interact_full_jpl_center
+
+
+
+  SUBROUTINE set_relativity(rel)
+
+    IMPLICIT NONE
+    LOGICAL, INTENT(in) :: rel
+
+    relativity = rel
+
+  END SUBROUTINE set_relativity
+
+
+
+END MODULE integrators
+
+
+
+
Index: trunk/mops/oorb/modules/linal.f90
===================================================================
--- trunk/mops/oorb/modules/linal.f90	(revision 34646)
+++ trunk/mops/oorb/modules/linal.f90	(revision 34646)
@@ -0,0 +1,1863 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!                                                                         
+!! This is a linear algebra module written in Fortran 90. For additional   
+!! information see the README.txt-file and the linal_doc.ps-file, which are
+!! distributed together with this sourcefile (linal.f90).                  
+!!                                                                         
+!! Following routines are included:                                        
+!!                                                                         
+!! eigen_decomposition_jacobi - Solves the eigenproblem.                   
+!!                                                                         
+!! sq_matrix_check        - Checks wheter the given matrix is a square     
+!!                          matrix, if the ranges are ok etc.              
+!!                                                                         
+!! tri_matrix_check       - Checks wheter the given matrix is a compressed 
+!!                          tridiagonal matrix, if the ranges are ok etc.  
+!!                                                                         
+!! vector_check           - Checks wheter the vector ranges are ok.        
+!!                                                                         
+!! LU_factor              - Finds the LU factorization of a given square   
+!!                          matrix.                                        
+!!                                                                         
+!! LU_solve               - Solves a linear system by using the LU factori-
+!!                          zation.                                        
+!!                                                                         
+!! LU_separation          - Separates an LU factorization matrix to a lower
+!!                          and an upper triangular matrix.                
+!!                                                                         
+!! matinv                 - Finds the inverse matrix of a given square     
+!!                          matrix by means of the LU factorization.       
+!!                                                                         
+!! Gauss_elimination      - Solves a linear system by means of the Gauss   
+!!                          elimination procedure.                         
+!!                                                                         
+!! tridiagonal_solve      - Solves a tridiagonal linear system.            
+!!                                                                         
+!! Jacobi_iteration       - Solves a linear system by means of the Jacobi  
+!!                          iteration procedure.                           
+!!                                                                         
+!! Gauss_Seidel_iteration - Solves a linear system by means of the Gauss-  
+!!                          Seidel iteration procedure.                    
+!!                                                                         
+!! determinant            - Finds the determinant of a given matrix.       
+!!                                                                         
+!! cond_number            - Finds the condition number of a given matrix.  
+!!                                                                         
+!! matrix_norm            - Finds the matrix norm of a given matrix.       
+!!                                                                         
+!! matrix_print          - Writes the given matrix to the given i/o-unit  
+!!                          using a nice layout.                           
+!!                                                                         
+!! vector_print          - Writes the given vector to the given i/o-unit  
+!!                          using a nice layout.                           
+!!                                                                         
+!! outer_product          - Computes the outer product of two given vectors.
+!!                                                                         
+!! cross_product          - Computes the cross product of two given vectors.
+!!                                                                         
+!! identity_matrix        - Returns the identity matrix of a given         
+!!                          dimension.                                     
+!!                                                                         
+!!                                                                         
+!!                                                                         
+!!                                                                         
+!!   THE tri_matrix_check ROUTINE SHOULD ALWAYS BE CALLED BEFORE CALLING   
+!!                                                                         
+!!   tridiagonal_solve                                                     
+!!                                                                         
+!!   THE sq_matrix_check ROUTINE SHOULD ALWAYS BE CALLED BEFORE CALLING    
+!!                                                                         
+!!   LU_factor                                                             
+!!   LU_solve                                                              
+!!   LU_separation                                                         
+!!   Gauss_elimination                                                     
+!!   Jacobi_iteration                                                      
+!!   Gauss_Seidel_iteration                                                
+!!   matinv                                                                
+!!   determinant                                                           
+!!   cond_number                                                           
+!!                                                                         
+!!   YOU DON'T NEED TO CALL THE CHECKING ROUTINES, BUT NOT CALLING THEM IS 
+!!   ADVISABLE ONLY IN CASE YOU KNOW EXACTLY WHAT YOU ARE DOING.           
+!!
+!!
+!! @author  MG
+!! @version 2011-10-13
+!!
+MODULE linal
+
+  USE parameters
+  USE utilities
+
+  IMPLICIT NONE
+
+  !! Parameters:
+  !!
+  !!  max_iter         - Maximum number of iteration loops.
+  !!
+  !!  layout           - Layout of one number.
+  !!
+
+  INTEGER, PARAMETER           :: max_iter = 1000000
+  CHARACTER(len=30), PARAMETER :: frmt_default = '(E22.14,1X)'
+
+  PRIVATE :: matrix_print_r8
+  PRIVATE :: matrix_print_r16
+  PRIVATE :: outer_product_r4
+  PRIVATE :: outer_product_r8
+  PRIVATE :: outer_product_r16
+
+  INTERFACE diagonal_multiplication
+     MODULE PROCEDURE diagonal_multiplication_vec_r8
+     MODULE PROCEDURE diagonal_multiplication_sca_r8
+  END INTERFACE diagonal_multiplication
+
+  INTERFACE identity_matrix
+     MODULE PROCEDURE identity_matrix_r8
+  END INTERFACE identity_matrix
+
+  INTERFACE LU_factor
+     MODULE PROCEDURE LU_factor_r8
+     MODULE PROCEDURE LU_factor_r16
+  END INTERFACE LU_factor
+
+  INTERFACE LU_solve
+     MODULE PROCEDURE LU_solve_r8
+     MODULE PROCEDURE LU_solve_r16
+  END INTERFACE LU_solve
+
+  INTERFACE matrix_print
+     MODULE PROCEDURE matrix_print_r8
+     MODULE PROCEDURE matrix_print_r16
+  END INTERFACE matrix_print
+
+  INTERFACE matinv
+     MODULE PROCEDURE matinv_r8
+     MODULE PROCEDURE matinv_r16
+  END INTERFACE matinv
+
+  INTERFACE outer_product
+     MODULE PROCEDURE outer_product_r4
+     MODULE PROCEDURE outer_product_r8
+     MODULE PROCEDURE outer_product_r16
+  END INTERFACE outer_product
+
+  INTERFACE triple_product
+     MODULE PROCEDURE triple_product_r8
+  END INTERFACE triple_product
+
+  INTERFACE cross_product
+     MODULE PROCEDURE cross_product_r8
+  END INTERFACE cross_product
+
+CONTAINS
+
+
+
+  !! *Description*:
+  !!
+  !! Cholesky decomposition.
+  !!
+  !! Given an N x N positive-definite symmetric matrix 'a', this routine
+  !! constructs its Cholesky decomposition, A = L · Transpose(L) . On
+  !! input, only the upper triangle of 'a' needs to be given; it is not
+  !! modified. The Cholesky factor L is returned in the lower triangle
+  !! of 'a', except for its diagonal elements, which are returned in 'p',
+  !! a vector of length N.
+  !!
+  SUBROUTINE cholesky_decomposition(a, p, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout) :: a
+    REAL(rprec8), DIMENSION(:), INTENT(out) :: p
+    CHARACTER(len=*), INTENT(inout) :: error
+
+    REAL(rprec8) :: summ
+    INTEGER(iprec4) :: i, n
+
+    n = SIZE(a,dim=1)
+    IF (n /= SIZE(a,dim=2) .OR. n /= SIZE(p)) THEN
+       error = " -> linal : cholesky_decomposition : Matrix and vector sizes are not compatible." // &
+            TRIM(error)
+       RETURN
+    END IF
+    DO i=1,n
+       summ = a(i,i) - DOT_PRODUCT(a(i,1:i-1),a(i,1:i-1))
+       IF (summ <= 0.0_rprec8) THEN 
+          ! a, WITH rounding errors, is not positive definite
+          error = " -> linal : cholesky_decomposition : Matrix is not positive definite." // &
+               TRIM(error)
+          RETURN
+       END IF
+       p(i) = SQRT(summ)
+       a(i+1:n,i) = (a(i,i+1:n) - MATMUL(a(i+1:n,1:i-1),a(i,1:i-1)))/p(i)
+    END DO
+
+  END SUBROUTINE cholesky_decomposition
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Solves the set of N linear equations A · x = b, where a is a
+  !! positive-definite symmetric matrix. a (N × N) and p (of length N)
+  !! are input as the output of the routine choldc.  Only the lower
+  !! subdiagonal portion of a is accessed. b is the input right-hand-
+  !! side vector, of length N. The solution vector, also of length N,
+  !! is returned in x. a and p are not modified and can be left in
+  !! place for successive calls with different right-hand sides b. b
+  !! is not modified unless you identify b and x in the calling
+  !! sequence, which is allowed.
+  !!
+  SUBROUTINE cholesky_solve(a, p, b, x, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: a
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: p, b
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: x
+    CHARACTER(len=*), INTENT(inout) :: error
+
+    INTEGER(iprec4) :: i, n
+
+    n = SIZE(a,dim=1)
+    IF (n /= SIZE(a,dim=2) .OR. n /= SIZE(p) .OR. &
+         n /= SIZE(b) .OR. n /= SIZE(x)) THEN
+       error = " -> linal : cholesky_solve : Matrix and/or vector sizes are not compatible." // &
+            TRIM(error)
+       RETURN
+    END IF
+    DO i=1,n ! Solve L · y = b, storing y in x.
+       x(i) = (b(i) - DOT_PRODUCT(a(i,1:i-1),x(1:i-1))) / p(i)
+    END DO
+    DO i=n,1,-1 ! Solve LT · x = y.
+       x(i) = (x(i) - DOT_PRODUCT(a(i+1:n,i),x(i+1:n))) / p(i)
+    END DO
+
+  END SUBROUTINE cholesky_solve
+
+
+
+
+
+  FUNCTION diagonal_multiplication_vec_r8(matrix, diagonal, error, mask)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: matrix
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: diagonal
+    REAL(rprec8), DIMENSION(SIZE(matrix,dim=1),SIZE(matrix,dim=2)) :: diagonal_multiplication_vec_r8
+    CHARACTER(len=*), INTENT(inout) :: error
+    LOGICAL, DIMENSION(:), OPTIONAL, INTENT(in) :: mask 
+    INTEGER :: i, n
+
+    n = MIN(SIZE(matrix,dim=1),SIZE(matrix,dim=2))
+    IF (SIZE(diagonal) < n) THEN
+       error = " -> linal : diagonal_multiplication : Matrix and diagonal vector are not compatible." // &
+            TRIM(error)
+       RETURN
+    END IF
+    IF (PRESENT(mask)) THEN
+       IF (SIZE(mask) < n) THEN
+          error = " -> linal : diagonal_multiplication : Matrix and mask vector are not compatible." // &
+               TRIM(error)
+          RETURN
+       END IF
+    END IF
+    diagonal_multiplication_vec_r8 = matrix
+    DO i=1,n
+       IF (PRESENT(mask)) THEN
+          IF (.NOT.mask(i)) THEN
+             CYCLE
+          END IF
+       END IF
+       diagonal_multiplication_vec_r8(i,i) = matrix(i,i) * diagonal(i)
+    END DO
+
+  END FUNCTION diagonal_multiplication_vec_r8
+
+
+
+
+
+  FUNCTION diagonal_multiplication_sca_r8(matrix, diagonal, error, mask)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: matrix
+    REAL(rprec8), INTENT(in) :: diagonal
+    REAL(rprec8), DIMENSION(SIZE(matrix,dim=1),SIZE(matrix,dim=2)) :: diagonal_multiplication_sca_r8
+    CHARACTER(len=*), INTENT(inout) :: error
+    LOGICAL, DIMENSION(:), OPTIONAL, INTENT(in) :: mask 
+    INTEGER :: i, n
+
+    n = MIN(SIZE(matrix,dim=1),SIZE(matrix,dim=2))
+    IF (PRESENT(mask)) THEN
+       IF (SIZE(mask) < n) THEN
+          error = " -> linal : diagonal_multiplication : Matrix and mask vector are not compatible." // &
+               TRIM(error)
+          RETURN
+       END IF
+    END IF
+    diagonal_multiplication_sca_r8 = matrix
+    DO i=1,n
+       IF (PRESENT(mask)) THEN
+          IF (.NOT.mask(i)) THEN
+             CYCLE
+          END IF
+       END IF
+       diagonal_multiplication_sca_r8(i,i) = matrix(i,i) * diagonal
+    END DO
+
+  END FUNCTION diagonal_multiplication_sca_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes all eigenvalues and eigenvectors of a real symmetric
+  !! N x N matrix 'a'. 'd' is a vector of length N that returns the
+  !! eigenvalues of 'a'. 'v' is an N x N matrix whose columns contain,
+  !! on output, the normalized eigenvectors of 'a'. 'nrot' returns the
+  !! number of Jacobi rotations that were required.
+  !! 
+  !! Reference:
+  !! Press, Teukolsky, Vetterling, and Flannery: Numerical Recipes in
+  !! Fortran 90 -- The Art of Parallel Scientific Computing, 2nd Ed.,
+  !! 1999, Cambridge University Press, pp. 1225--1227.
+  !!
+  SUBROUTINE eigen_decomposition_jacobi(a, d, v, nrot, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)  :: a
+    REAL(rprec8), DIMENSION(:), INTENT(out)   :: d
+    REAL(rprec8), DIMENSION(:,:), INTENT(out) :: v
+    INTEGER, INTENT(out)                      :: nrot
+    CHARACTER(len=*), INTENT(inout)           :: error
+
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: aa
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: b, z
+    REAL(rprec8) :: c, g, h, s, sm, t, tau, theta, tresh
+    INTEGER :: i, j, ip, iq, n, err
+    LOGICAL, DIMENSION(:,:), ALLOCATABLE :: upper_triangle
+
+    n = SIZE(a,dim=1)
+    IF (n /= SIZE(a,dim=2) .OR. n /= SIZE(d) .OR. &
+         n /= SIZE(v,dim=1) .OR. n /= SIZE(v,dim=2)) THEN
+       error = " -> linal : eigen_decomposition_jacobi : Matrix and/or vector sizes are not compatible." // &
+            TRIM(error)
+       RETURN
+    END IF
+    ALLOCATE(aa(n,n), b(n), z(n), upper_triangle(n,n), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : eigen_decomposition_jacobi : Could not allocate memory." // &
+            TRIM(error)
+       DEALLOCATE(aa, stat=err)
+       DEALLOCATE(b, stat=err)
+       DEALLOCATE(z, stat=err)
+       DEALLOCATE(upper_triangle, stat=err)
+       RETURN
+    END IF
+    aa = a
+    upper_triangle = .FALSE.
+    DO i=1,n-1
+       upper_triangle(i,i+1:n) = .TRUE.
+       b(i) = aa(i,i)
+    END DO
+    v = identity_matrix(n)
+    d(:) = b(:)
+    z(:) = 0.0_rprec8
+    nrot = 0
+    DO i=1, 100
+       sm = SUM(ABS(aa), mask=upper_triangle)
+       IF (sm == 0.0_rprec8) THEN
+          DEALLOCATE(aa, b, z, upper_triangle, stat=err)
+          IF (err /= 0) THEN
+             error = " -> linal : eigen_decomposition_jacobi : Could not deallocate memory (1)." // &
+                  TRIM(error)
+             DEALLOCATE(aa, stat=err)
+             DEALLOCATE(b, stat=err)
+             DEALLOCATE(z, stat=err)
+             DEALLOCATE(upper_triangle, stat=err)
+          END IF
+          ! Make sure that the eigenvalues are non-negative:
+          d = ABS(d)
+          RETURN
+       END IF
+       tresh = MERGE((0.2_rprec8*sm)/(n**2), 0.0_rprec8, i < 4)
+       DO ip=1,n-1
+          DO iq=ip+1,n
+             g = 100.0_rprec8*ABS(aa(ip,iq))
+             IF((i > 4) .AND. (ABS(d(ip))+g == ABS(d(ip))) &
+                  .AND. (ABS(d(iq))+g == ABS(d(iq)))) THEN
+                aa(ip,iq) = 0.0_rprec8
+             ELSE IF (ABS(aa(ip,iq)) > tresh) THEN
+                h = d(iq) - d(ip)
+                IF(ABS(h)+g == ABS(h)) THEN
+                   t = aa(ip,iq)/h
+                ELSE
+                   theta = 0.5_rprec8*h/aa(ip,iq)
+                   t = 1.0_rprec8/(ABS(theta)+SQRT(1.0_rprec8+theta**2.0_rprec8))
+                   IF(theta < 0.0) THEN
+                      t = -t
+                   END IF
+                END IF
+                c = 1.0_rprec8 / SQRT(1.0_rprec8+t**2.0_rprec8)
+                s = t*c
+                tau = s/(1.0_rprec8 + c)
+                h = t*aa(ip,iq)
+                z(ip) = z(ip) - h
+                z(iq) = z(iq) + h
+                d(ip) = d(ip) - h
+                d(iq) = d(iq) + h
+                aa(ip,iq) = 0.0_rprec8
+                CALL jrotate(aa(1:ip-1, ip), aa(1:ip-1, iq), error)
+                IF (LEN_TRIM(error) /= 0) THEN
+                   error = " -> linal : eigen_decomposition_jacobi : (1)" // TRIM(error) 
+                   RETURN
+                END IF
+                CALL jrotate(aa(ip, ip+1:iq-1), aa(ip+1:iq-1, iq), error)
+                IF (LEN_TRIM(error) /= 0) THEN
+                   error = " -> linal : eigen_decomposition_jacobi : (2)" // TRIM(error) 
+                   RETURN
+                END IF
+                CALL jrotate(aa(ip, iq+1:n), aa(iq, iq+1:n), error)
+                IF (LEN_TRIM(error) /= 0) THEN
+                   error = " -> linal : eigen_decomposition_jacobi : (3)" // TRIM(error) 
+                   RETURN
+                END IF
+                CALL jrotate(v(:,ip), v(:,iq), error)
+                IF (LEN_TRIM(error) /= 0) THEN
+                   error = " -> linal : eigen_decomposition_jacobi : (4)" // TRIM(error) 
+                   RETURN
+                END IF
+                IF (LEN_TRIM(error) /= 0) THEN
+                   DEALLOCATE(aa, stat=err)
+                   DEALLOCATE(b, stat=err)
+                   DEALLOCATE(z, stat=err)
+                   DEALLOCATE(upper_triangle, stat=err)
+                   RETURN
+                END IF
+                nrot = nrot + 1
+             END IF
+          END DO
+       END DO
+       b(:) = b(:) + z(:)
+       d(:) = b(:)
+       z(:) = 0.0_rprec8
+    END DO
+    error = " -> linal : eigen_decomposition_jacobi : Too many iterations." // &
+         TRIM(error)
+    DEALLOCATE(aa, b, z, upper_triangle, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : eigen_decomposition_jacobi : Could not deallocate memory (2)." // &
+            TRIM(error)
+       DEALLOCATE(aa, stat=err)
+       DEALLOCATE(b, stat=err)
+       DEALLOCATE(z, stat=err)
+       DEALLOCATE(upper_triangle, stat=err)
+       RETURN
+    END IF
+
+  CONTAINS
+
+    SUBROUTINE jrotate(a1, a2, error)
+
+      IMPLICIT NONE
+      REAL(rprec8), DIMENSION(:), INTENT(inout) :: a1, a2
+      CHARACTER(len=*), INTENT(inout)           :: error
+
+      REAL(rprec8), DIMENSION(:), ALLOCATABLE :: wk1
+      INTEGER :: err = 0
+
+      ALLOCATE(wk1(SIZE(a1)), stat=err)
+      IF (err /= 0) THEN
+         error = " -> linal : jrotate : Could not allocate memory." // &
+              TRIM(error)
+         RETURN
+      END IF
+
+      wk1(:) = a1(:)
+      a1(:) = a1(:) - s*(a2(:) + a1(:) * tau)
+      a2(:) = a2(:) + s*(wk1(:) - a2(:) * tau)
+
+      DEALLOCATE(wk1, stat=err)
+      IF (err /= 0) THEN
+         error = " -> linal : jrotate : Could not deallocate memory." // &
+              TRIM(error)
+         RETURN
+      END IF
+
+    END SUBROUTINE jrotate
+
+  END SUBROUTINE eigen_decomposition_jacobi
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns an identity matrix of a given dimension. 
+  !!
+  FUNCTION identity_matrix_r8(n)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: n
+    REAL(rprec8), DIMENSION(n,n) :: identity_matrix_r8
+    INTEGER :: i
+
+    identity_matrix_r8 = 0.0_rprec8
+    DO i=1,n
+       identity_matrix_r8(i,i) = 1.0_rprec8
+    END DO
+
+  END FUNCTION identity_matrix_r8
+
+
+
+
+
+  SUBROUTINE sq_matrix_check(A, n, error)
+
+    !! Finds out the following things about the given matrix:
+    !!    - is it a square matrix (n,n)? (yes=ok)
+    !!
+    !! Input:  - Matrix                                      A(:,:)
+    !! Output: - Number of columns/rows (if square, else 0)  n
+    !!         - Error (.false., if ok)                      error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: A
+    INTEGER, INTENT(out) :: n
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER, DIMENSION(2) :: up_bound
+
+    n = 0
+    up_bound = UBOUND(A) 
+
+    ! Is A a square matrix?
+    IF (up_bound(1) /= up_bound(2)) THEN
+       error = " -> linal : sq_matrix_check : A is not a square matrix." // &
+            TRIM(error)
+       RETURN
+       ! Is it bigger than 1x1?
+    ELSE IF (up_bound(1) < 2) THEN
+       error = " -> linal : sq_matrix_check : A is a 1x1 matrix." // &
+            TRIM(error)
+       RETURN
+       ! If everything is ok, give n the right value:
+    ELSE
+       n = up_bound(1)
+    END IF
+
+  END SUBROUTINE sq_matrix_check
+
+
+
+
+
+  SUBROUTINE tri_matrix_check(A, n, error)
+
+    !! Finds out if the given matrix is a compressed tridiagonal
+    !! matrix (n,3)? (yes=ok)
+    !!
+    !! Input:  - Matrix                                      A(:,:)
+    !! Output: - Number of columns/rows (if square, else 0)  n
+    !!         - Error (.false., if ok)                      error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: A
+    INTEGER, INTENT(out) :: n
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER, DIMENSION(2) :: up_bound
+
+    n = 0
+    up_bound = UBOUND(A) 
+
+    ! Is A a tridiagonal matrix?
+    IF (up_bound(2) /= 3) THEN
+       error = " -> linal : tri_matrix_check : A is not a compressed tridiagonal matrix." // &
+            TRIM(error)
+       RETURN
+       ! If everything is ok, give n the right value:
+    ELSE
+       n = up_bound(1)
+    END IF
+
+  END SUBROUTINE tri_matrix_check
+
+
+
+
+
+  SUBROUTINE vector_size(b, n)
+
+    !! Finds out the number of elements of the given vector.
+    !!
+    !! Input:  - Vector                     b(:)
+    !! Output: - Size of vector             n
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: b
+    INTEGER, INTENT(out)                   :: n
+
+    INTEGER, DIMENSION(1) :: up_bound
+
+    up_bound = UBOUND(b) 
+    n = up_bound(1)
+
+  END SUBROUTINE vector_size
+
+
+
+
+
+  SUBROUTINE LU_factor_r8(A2LU, indx, error)
+
+    !! Finds the LU factorization of a given square matrix.
+    !!
+    !! Input:  - Square matrix              A2LU(n,n)
+    !! Output: - LU factorization           A2LU(n,n)
+    !!         - Index vector               indx(n)
+    !!         - Error (.false., if ok)     error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout)       :: A2LU
+    INTEGER, DIMENSION(SIZE(A2LU,dim=1)), INTENT(out) :: indx
+    CHARACTER(len=*), INTENT(inout)                            :: error
+
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: vv, helpvec
+    INTEGER :: n, i, imax, err
+
+    n = SIZE(A2LU,dim=1)
+    ALLOCATE(vv(SIZE(indx)), helpvec(SIZE(indx)), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : LU_factor : Could not allocate memory." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    END IF
+
+    ! Find scaling factor for each row so that the maximum 
+    ! element of the row is equal to one:
+    vv = MAXVAL(ABS(A2LU),dim=2)
+    IF (MINVAL(vv) < 1.0e-32_rprec8*EPSILON(vv)) THEN
+       error = " -> linal : LU_factor : Maximum element of a row too small." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    ELSE
+       vv = 1.0_rprec8 / vv
+    END IF
+
+    DO i=1,n
+       imax = (i-1) + imaxloc(vv(i:n)*ABS(A2LU(i:n,i)))
+       IF (i /= imax) THEN
+          helpvec = A2LU(imax,1:n)
+          A2LU(imax,1:n) = A2LU(i,1:n)
+          A2LU(i,1:n) = helpvec
+          vv(imax) = vv(i)
+       END IF
+       indx(i) = imax
+       ! Avoid division with zero:
+       IF (ABS(A2LU(i,i)) < 1.0e-32_rprec8*EPSILON(A2LU(i,i))) THEN
+          error = " -> linal : LU_factor : Division by almost zero." // &
+               TRIM(error)
+          DEALLOCATE(vv, stat=err)
+          DEALLOCATE(helpvec, stat=err)
+          RETURN
+       END IF
+       A2LU(i+1:n,i) = A2LU(i+1:n,i) / A2LU(i,i)
+       A2LU(i+1:n,i+1:n) = A2LU(i+1:n,i+1:n) - &
+            outer_product(A2LU(i+1:n,i),A2LU(i,i+1:n))
+    END DO
+
+    DEALLOCATE(vv, helpvec, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : LU_factor : Could not deallocate memory." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE LU_factor_r8
+
+
+
+
+
+  SUBROUTINE LU_factor_r16(A2LU, indx, error)
+
+    !! Finds the LU factorization of a given square matrix.
+    !!
+    !! Input:  - Square matrix              A2LU(n,n)
+    !! Output: - LU factorization           A2LU(n,n)
+    !!         - Index vector               indx(n)
+    !!         - Error (.false., if ok)     error
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:,:), INTENT(inout)    :: A2LU
+    INTEGER, DIMENSION(SIZE(A2LU,dim=1)), INTENT(out) :: indx
+    CHARACTER(len=*), INTENT(inout)                            :: error
+
+    REAL(rprec16), DIMENSION(:), ALLOCATABLE :: vv, helpvec
+    INTEGER :: n, i, imax, err
+
+    n = SIZE(A2LU,dim=1)
+    ALLOCATE(vv(SIZE(indx)), helpvec(SIZE(indx)), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : LU_factor : Could not allocate memory." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    END IF
+
+    ! Find scaling factor for each row so that the maximum 
+    ! element of the row is equal to one:
+    vv = MAXVAL(ABS(A2LU),dim=2)
+    IF (MINVAL(vv) < 1.0e-32_rprec16*EPSILON(vv)) THEN
+       error = " -> linal : LU_factor : Maximum element of a row too small." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    ELSE
+       vv = 1.0_rprec16 / vv
+    END IF
+
+    DO i=1,n
+       imax = (i-1) + imaxloc(vv(i:n)*ABS(A2LU(i:n,i)))
+       IF (i /= imax) THEN
+          helpvec = A2LU(imax,1:n)
+          A2LU(imax,1:n) = A2LU(i,1:n)
+          A2LU(i,1:n) = helpvec
+          vv(imax) = vv(i)
+       END IF
+       indx(i) = imax
+       ! Avoid division with zero:
+       IF (ABS(A2LU(i,i)) < 1.0e-32_rprec16*EPSILON(A2LU(i,i))) THEN
+          error = " -> linal : LU_factor : Division by almost zero." // &
+               TRIM(error)
+          DEALLOCATE(vv, stat=err)
+          DEALLOCATE(helpvec, stat=err)
+          RETURN
+       END IF
+       A2LU(i+1:n,i) = A2LU(i+1:n,i) / A2LU(i,i)
+       A2LU(i+1:n,i+1:n) = A2LU(i+1:n,i+1:n) - &
+            outer_product(A2LU(i+1:n,i),A2LU(i,i+1:n))
+    END DO
+
+    DEALLOCATE(vv, helpvec, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : LU_factor : Could not deallocate memory." // &
+            TRIM(error)
+       DEALLOCATE(vv, stat=err)
+       DEALLOCATE(helpvec, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE LU_factor_r16
+
+
+
+
+
+  SUBROUTINE LU_solve_r8(LU, indx, b)
+
+    !! Solves a linear system by means of the LU factorization.
+    !! 
+    !! Input:  - LU factorization square matrix  LU(n,n)
+    !!         - Row permutation index vector    indx(n)
+    !!         - LUx=b                           b(n)
+    !! Output: - LUx=b => solve x => b=x         b(n)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)  :: LU
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: b
+    INTEGER, DIMENSION(:), INTENT(in)         :: indx
+
+    REAL(rprec8) :: summ
+    INTEGER :: n, i, ii, ll
+
+    n = SIZE(LU,dim=1)
+    ii = 0
+
+    ! Solve 'a' (=Ux) from La=b, by means of forward
+    ! substitution:
+    DO i=1,n
+       ll = indx(i)
+       summ = b(ll)
+       b(ll) = b(i)
+       IF (ii /= 0) THEN
+          summ = summ - DOT_PRODUCT(LU(i,ii:i-1), b(ii:i-1))
+       ELSE IF (ABS(summ) > 0.0_rprec8) THEN
+          ii = i
+       END IF
+       b(i) = summ
+    END DO
+
+    ! Solve 'x' from Ux=a, by means of backward
+    ! substitution:
+    DO i=n,1,-1
+       b(i) = (b(i) - DOT_PRODUCT(LU(i,i+1:n), b(i+1:n)))/LU(i,i)
+    END DO
+
+  END SUBROUTINE LU_solve_r8
+
+
+
+
+
+  SUBROUTINE LU_solve_r16(LU, indx, b)
+
+    !! Solves a linear system by means of the LU factorization.
+    !! 
+    !! Input:  - LU factorization square matrix  LU(n,n)
+    !!         - Row permutation index vector    indx(n)
+    !!         - LUx=b                           b(n)
+    !! Output: - LUx=b => solve x => b=x         b(n)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:,:), INTENT(in)  :: LU
+    REAL(rprec16), DIMENSION(:), INTENT(inout) :: b
+    INTEGER, DIMENSION(:), INTENT(in)          :: indx
+
+    REAL(rprec16) :: summ
+    INTEGER :: n, i, ii, ll
+
+    n = SIZE(LU,dim=1)
+    ii = 0
+
+    ! Solve 'a' (=Ux) from La=b, by means of forward
+    ! substitution:
+    DO i=1,n
+       ll = indx(i)
+       summ = b(ll)
+       b(ll) = b(i)
+       IF (ii /= 0) THEN
+          summ = summ - DOT_PRODUCT(LU(i,ii:i-1), b(ii:i-1))
+       ELSE IF (ABS(summ) > 0.0_rprec16) THEN
+          ii = i
+       END IF
+       b(i) = summ
+    END DO
+
+    ! Solve 'x' from Ux=a, by means of backward
+    ! substitution:
+    DO i=n,1,-1
+       b(i) = (b(i) - DOT_PRODUCT(LU(i,i+1:n), b(i+1:n)))/LU(i,i)
+    END DO
+
+  END SUBROUTINE LU_solve_r16
+
+
+
+
+
+  SUBROUTINE LU_separation(LU2L, U)
+
+    !! Separates an LU factorization square matrix to a lower 
+    !! and an upper triangular square matrix.
+    !!
+    !! Input:  - LU factorization square matrix  LU2L(n,n)
+    !!         - Number of columns/rows          n
+    !! Output: - Lower triangular square matrix  LU2L(n,n)
+    !!         - Upper triangular square matrix  U(n,n)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout) :: LU2L
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)   :: U
+
+    INTEGER :: n, i, j
+
+    n = SIZE(LU2L,dim=1)
+
+    U = 0.0_rprec8
+    ! Copy the upper triangular matrix from LU2L to U:
+    FORALL(i=1:n, j=1:n, i<=j) 
+       U(i,j) = LU2L(i,j)
+    END FORALL
+    ! Transform the LU2L matrix to a lower triangular matrix:
+    FORALL(i=1:n)
+       LU2L(i,i) = 1.0_rprec8
+    END FORALL
+    FORALL(i=1:n, j=1:n, i<j)
+       LU2L(i,j) = 0.0_rprec8
+    END FORALL
+
+  END SUBROUTINE LU_separation
+
+
+
+
+
+  FUNCTION matinv_r8(A, error, method)
+
+    !! Returns the inverse of square matrix A using either the LU
+    !! factorization algorithm or the Cholesky decomposition algorithm
+    !! 
+    !! Input:   - Square matrix              A(n,n)
+    !!          - Inverse square matrix      inv_A(n,n)
+    !! Output:  - Error (.false., if ok)     error 
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)             :: A
+    REAL(rprec8), DIMENSION(SIZE(A,dim=2),SIZE(A,dim=1)) :: matinv_r8
+    CHARACTER(len=*), INTENT(inout)                      :: error
+    CHARACTER(len=*), INTENT(in), OPTIONAL               :: method
+
+    CHARACTER(len=16) :: method_
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: LU, L
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: p
+    INTEGER, DIMENSION(:), ALLOCATABLE :: indx
+    INTEGER :: i, n, err
+
+    n = SIZE(A,dim=1)
+    IF (n /= SIZE(A,dim=2)) THEN
+       error = " -> linal : matinv : Input not a square matrix." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+    method_ = " "
+    IF (PRESENT(method)) THEN
+       method_ = method
+    ELSE
+       method_ = "LU"
+    END IF
+
+    IF (method_ == "LU") THEN
+
+       ALLOCATE(LU(n,n), indx(n), stat=err)
+       IF (err /= 0) THEN
+          error = " -> linal : matinv : Could not allocate memory." // &
+               TRIM(error)
+          DEALLOCATE(LU, stat=err)
+          DEALLOCATE(indx, stat=err)
+          RETURN
+       END IF
+
+       ! A => LU :
+       LU(:,:) = A(:,:)
+       CALL LU_factor(LU(:,:), indx, error)
+       IF (LEN_TRIM(error) /= 0) THEN
+          error = " -> linal : matinv : LU factorization unsuccessful." // &
+               TRIM(error)
+          DEALLOCATE(LU, stat=err)
+          DEALLOCATE(indx, stat=err)
+          RETURN
+       END IF
+
+       ! Initialize the identity matrix:
+       matinv_r8(:,:) = 0.0_rprec8
+       FORALL(i=1:n)
+          matinv_r8(i,i) = 1.0_rprec8
+       END FORALL
+
+       ! Solve b from LUb = e_i and put A(:,i) = b:
+       DO i=1,n
+          CALL LU_solve(LU, indx, matinv_r8(1:n,i))
+       END DO
+
+       DEALLOCATE(LU, indx, stat=err)
+       IF (err /= 0) THEN
+          error = " -> linal : matinv : Could not deallocate memory." // &
+               TRIM(error)
+          DEALLOCATE(LU, stat=err)
+          DEALLOCATE(indx, stat=err)
+          RETURN
+       END IF
+
+    ELSE IF (method_ == "Cholesky") THEN
+
+       ALLOCATE(L(n,n), p(n), stat=err)
+       IF (err /= 0) THEN
+          error = " -> linal : matinv : Could not allocate memory." // &
+               TRIM(error)
+          DEALLOCATE(L, stat=err)
+          DEALLOCATE(p, stat=err)
+          RETURN
+       END IF
+
+       L(:,:) = A(:,:)
+       CALL cholesky_decomposition(L, p, error)
+       IF (LEN_TRIM(error) /= 0) THEN
+          error = " -> linal : matinv : ." // &
+               TRIM(error)
+          DEALLOCATE(L, stat=err)
+          DEALLOCATE(p, stat=err)
+          RETURN
+       END IF
+
+       ! Initialize the identity matrix:
+       matinv_r8(:,:) = 0.0_rprec8
+       FORALL(i=1:n)
+          matinv_r8(i,i) = 1.0_rprec8
+       END FORALL
+
+       ! Solve b from L * Transpose(L) * b = e_i and put A(:,i) = b:
+       DO i=1,n
+          CALL cholesky_solve(L, p, matinv_r8(1:n,i), matinv_r8(1:n,i), error)
+          IF (LEN_TRIM(error) /= 0) THEN
+             error = " -> linal : matinv : ." // &
+                  TRIM(error)
+             DEALLOCATE(L, stat=err)
+             DEALLOCATE(p, stat=err)
+             RETURN
+          END IF
+       END DO
+
+       DEALLOCATE(L, p, stat=err)
+       IF (err /= 0) THEN
+          error = " -> linal : matinv : Could not deallocate memory." // &
+               TRIM(error)
+          DEALLOCATE(L, stat=err)
+          DEALLOCATE(p, stat=err)
+          RETURN
+       END IF
+
+    ELSE
+
+       ! No such option...
+       error = " -> linal : matinv : No such option." // &
+            TRIM(error)
+
+    END IF
+
+  END FUNCTION matinv_r8
+
+
+
+
+
+  FUNCTION matinv_r16(A, error)
+
+    !! Returns the inverse matrix of square matrix. 
+    !! 
+    !! Input:   - Square matrix              A(n,n)
+    !!          - Inverse square matrix      inv_A(n,n)
+    !! Output:  - Error (.false., if ok)     error 
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:,:), INTENT(in)             :: A
+    REAL(rprec16), DIMENSION(SIZE(A,dim=2),SIZE(A,dim=1)) :: matinv_r16
+    CHARACTER(len=*), INTENT(inout)                                :: error
+
+    REAL(rprec16), DIMENSION(:,:), ALLOCATABLE :: LU
+    INTEGER, DIMENSION(:), ALLOCATABLE :: indx
+    INTEGER :: i, n, err
+
+    n = SIZE(A,dim=1)
+    IF (n /= SIZE(A,dim=2)) THEN
+       error = " -> linal : matinv : Input not a square matrix." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+    ALLOCATE(LU(n,n), indx(n), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matinv : Could not allocate memory." // &
+            TRIM(error)
+       DEALLOCATE(LU, stat=err)
+       DEALLOCATE(indx, stat=err)
+       RETURN
+    END IF
+
+    ! A => LU :
+    LU(:,:) = A(:,:)
+    CALL LU_factor(LU(:,:), indx, error)
+    IF (LEN_TRIM(error) /= 0) THEN
+       error = " -> linal : matinv : LU factorization unsuccessful." // &
+            TRIM(error)
+       DEALLOCATE(LU, stat=err)
+       DEALLOCATE(indx, stat=err)
+       RETURN
+    END IF
+
+    ! Initialize the identity matrix:
+    matinv_r16(:,:) = 0.0_rprec16
+    FORALL(i=1:n)
+       matinv_r16(i,i) = 1.0_rprec16
+    END FORALL
+
+    ! Solve b from LUb = e_i and put A(:,i) = b:
+    DO i=1,n
+       CALL LU_solve(LU, indx, matinv_r16(1:n,i))
+    END DO
+
+    DEALLOCATE(LU, indx, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matinv : Could not deallocate memory." // &
+            TRIM(error)
+       DEALLOCATE(LU, stat=err)
+       DEALLOCATE(indx, stat=err)
+       RETURN
+    END IF
+
+  END FUNCTION matinv_r16
+
+
+
+
+
+  SUBROUTINE Gauss_elimination(A, b, error)
+
+    !! Solves a linear system by means of the Gauss elimination 
+    !! procedure.
+    !!
+    !! Input:  - Square matrix              A(n,n)
+    !!         - Ax=b                       b(n)
+    !!         - Number of columns/rows     n
+    !! Output: - Ax=b => solve x => b=x     b(n)
+    !!         - Error (.false., if ok)     error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)             :: A
+    REAL(rprec8), DIMENSION(:), INTENT(inout)            :: b
+    CHARACTER(len=*), INTENT(inout)                                  :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1),SIZE(A,dim=2)) :: AA
+    REAL(rprec8), DIMENSION(SIZE(b))                     :: help_b
+    INTEGER, DIMENSION(SIZE(b))                             :: ind
+    REAL(rprec8)                                         :: smax, s, c 
+    INTEGER                                                 :: i, ii, j, k, kk, l, m, n
+
+    n = SIZE(A,dim=1)
+
+    AA = A
+    ! Initialize the row permutation vector ind:
+    FORALL(i=1:n)
+       ind(i) = i
+    END FORALL
+
+    DO i=1, n
+       m = i
+       ! Find maximum element among the remaining
+       ! elements of this column.
+       smax = AA(ind(i),i)
+       DO k=i+1, n
+          s = ABS(AA(ind(k),i))
+          IF (s > smax) THEN
+             smax = s
+             m = k
+          END IF
+       END DO
+       l = ind(i)
+       ind(i) = ind(m)
+       ind(m) = l
+       ii = ind(i)
+       IF (ABS(AA(ii,i)) < EPSILON(AA(ii,i))) THEN
+          error = " -> linal : Gauss_elimination : Attempted division by zero." // &
+               TRIM(error)
+          RETURN
+       END IF
+       ! Calculate the upper triangular matrix by
+       ! means of the Gauss procedure:
+       DO k=i+1, n
+          kk = ind(k)
+          c = AA(kk,i) / AA(ii,i)
+          DO j=i, n
+             AA(kk,j) = AA(kk,j) - c * AA(ii,j)
+          END DO
+          b(kk) = b(kk) - c * b(ii)
+       END DO
+    END DO
+
+    ! Solve the upper triangular matrix by means
+    ! of backsubstitution:
+    DO i=n, 1, -1
+       ii = ind(i)
+       b(ii) = b(ii) / AA(ii,i)
+       DO k=i-1, 1, -1
+          kk = ind(k)
+          b(kk) = b(kk) - AA(kk,i) * b(ii)
+       END DO
+    END DO
+
+    ! "Unpermutate" the solution in order to get
+    ! a solution, which corresponds to the original,
+    ! given matrix:  
+    help_b = b
+    FORALL(i=1:n)
+       b(i) = help_b(ind(i))
+    END FORALL
+
+  END SUBROUTINE Gauss_elimination
+
+
+
+
+
+  SUBROUTINE gauss_jordan(a, b, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(inout) :: a,b
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER, DIMENSION(SIZE(a,1)) :: ipiv,indxr,indxc
+    LOGICAL, DIMENSION(SIZE(a,1)) :: lpiv
+    REAL(rprec8) :: pivinv
+    REAL(rprec8), DIMENSION(SIZE(a,1)) :: dumc
+    INTEGER, DIMENSION(2), TARGET :: irc
+    INTEGER :: i,l,n
+    INTEGER, POINTER :: irow,icol
+
+    n = SIZE(a,dim=1)
+    irow => irc(1)
+    icol => irc(2)
+    ipiv = 0
+    DO i=1,n
+       lpiv = (ipiv == 0)
+       irc = MAXLOC(ABS(a),outerand(lpiv,lpiv))
+       ipiv(icol) = ipiv(icol) + 1
+       IF (ipiv(icol) > 1) THEN
+          error = " -> linal : gauss_jordan : Singular matrix (1)." // &
+               TRIM(error)
+          RETURN
+       END IF
+       IF (irow /= icol) THEN
+          CALL swap(a(irow,:),a(icol,:))
+          CALL swap(b(irow,:),b(icol,:))
+       END IF
+       indxr(i) = irow
+       indxc(i) = icol
+       IF (a(icol,icol) == 0.0) THEN
+          error = " -> linal : gauss_jordan : Singular matrix (2)." // &
+               TRIM(error)
+          RETURN
+       END IF
+       pivinv = 1.0_rprec8/a(icol,icol)
+       a(icol,icol) = 1.0_rprec8
+       a(icol,:) = a(icol,:)*pivinv
+       b(icol,:) = b(icol,:)*pivinv
+       dumc = a(:,icol)
+       a(:,icol) = 0.0
+       a(icol,icol) = pivinv
+       a(1:icol-1,:) = a(1:icol-1,:) - outer_product(dumc(1:icol-1),a(icol,:))
+       b(1:icol-1,:) = b(1:icol-1,:) - outer_product(dumc(1:icol-1),b(icol,:))
+       a(icol+1:,:) = a(icol+1:,:) - outer_product(dumc(icol+1:),a(icol,:))
+       b(icol+1:,:) = b(icol+1:,:) - outer_product(dumc(icol+1:),b(icol,:))
+    END DO
+    DO l=n,1,-1
+       CALL swap(a(:,indxr(l)),a(:,indxc(l)))
+    END DO
+
+  END SUBROUTINE gauss_jordan
+
+
+
+
+
+  SUBROUTINE tridiagonal_solve(A, b, error)
+
+    !! Solves a tridiagonal linear system. 
+    !!
+    !! Input:  - Tridigonal matrix (the non-null diagonals)  A(n,3)
+    !!         - Ax=b                                        b(n)
+    !! Output: - Ax=b => x=bA^(-1) => b=x                    b(n)
+    !!         - Error (.false., if ok)                      error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)  :: A
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: b
+    CHARACTER(len=*), INTENT(inout)                       :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1),3)  :: AA
+    INTEGER                                      :: i, n
+
+    n = SIZE(A,dim=1)
+    AA = A
+
+    DO i=2, n
+       IF (ABS(AA(i-1,2)) < EPSILON(AA(i-1,2))) THEN
+          error = " -> linal : tridiagonal_solve : Attempted division by almost zero." // &
+               TRIM(error)
+          RETURN
+       END IF
+       AA(i,2) = AA(i,2) - (AA(i,1) * AA(i-1,3)) / AA(i-1,2)
+       b(i) = b(i) - (AA(i,1) * b(i-1)) / AA(i-1,2)
+    END DO
+
+    b(n) = b(n) / AA(n,2) 
+    DO i=n-1, 1, -1
+       b(i) = (b(i) - AA(i,3) * b(i+1)) / AA(i,2)
+    END DO
+
+  END SUBROUTINE tridiagonal_solve
+
+
+
+
+
+  SUBROUTINE Jacobi_iteration(A, b, error)
+
+    !! Solves a linear system by means of the Jacobi iteration
+    !! procedure.
+    !!
+    !! Input:  - Square matrix                            A(n,n)
+    !!         - Ax=b                                     b(n)
+    !! Output: - Ax=b => solve x => b=x                   b(n)
+    !!         - Error (.false., if ok)                   error
+    !!
+    !! Other:  - Old solution vector                      x(n)
+    !!         - New solution vector                      y(n)
+    !!         - Difference between solution vectors      diff
+    !!         - Old difference between solution vectors  old_diff
+
+    IMPLICIT NONE
+    REAL(rprec8), PARAMETER                              :: iteration_factor = 1.0_rprec8
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)             :: A
+    REAL(rprec8), DIMENSION(:), INTENT(inout)            :: b
+    CHARACTER(len=*), INTENT(inout)                                  :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1),SIZE(A,dim=2)) :: LU
+    REAL(rprec8), DIMENSION(SIZE(b))                     :: D, x, y
+    REAL(rprec8)                                         :: diff, old_diff
+    INTEGER                                                 :: iter, i, n
+
+    n = SIZE(A,dim=1)
+
+    ! A = L + U + D = (L + U) + D :
+    LU = A
+    FORALL(i=1:n)
+       D(i) = LU(i,i)
+       LU(i,i) = 0.0_rprec8
+    END FORALL
+    x = 0.0_rprec8
+    diff = HUGE(diff)
+    iter = 1
+
+    DO WHILE (diff > iteration_factor*EPSILON(diff))
+       DO i=1, n
+          IF (ABS(D(i)) < EPSILON(D(i))) THEN
+             error = " -> linal : Jacobi_iteration : Attempted division by almost zero." // &
+                  TRIM(error)
+             RETURN
+          END IF
+          y(i) = (b(i) - DOT_PRODUCT(LU(i,:), x)) / D(i)
+       END DO
+       old_diff = diff
+       diff = SQRT(DOT_PRODUCT(x-y, x-y))
+       IF (diff > old_diff) THEN
+          error = " -> linal : Jacobi_iteration : Iteration divergent." // &
+               TRIM(error)
+          RETURN
+       END IF
+       x = y
+       iter = iter + 1
+       IF (iter > max_iter) THEN
+          error = " -> linal : Jacobi_iteration : Reached maximum number of iterations." // &
+               TRIM(error)
+          RETURN
+       END IF
+    END DO
+
+    b = x
+
+  END SUBROUTINE Jacobi_iteration
+
+
+
+
+  SUBROUTINE Gauss_Seidel_iteration(A, b, error)
+
+    !! Solves a linear system by means of the Gauss-Seidel iteration
+    !! procedure.
+    !!
+    !! Input:  - Square matrix                            A(n,n)
+    !!         - Ax=b                                     b(n)
+    !! Output: - Ax=b => solve x => b=x                   b(n)
+    !!         - Error (.false., if ok)                   error
+    !!
+    !! Other:  - Old solution vector                      x(n)
+    !!         - New solution vector                      y(n)
+    !!         - Difference between solution vectors      diff
+    !!         - Old difference between solution vectors  old_diff
+
+    IMPLICIT NONE
+    REAL(rprec8), PARAMETER                               :: iteration_factor = 1.0_rprec8
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)              :: A
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1)), INTENT(inout) :: b
+    CHARACTER(len=*), INTENT(inout)                                   :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1),SIZE(A,dim=2))  :: LU
+    REAL(rprec8), DIMENSION(SIZE(b))                      :: D, x, y
+    REAL(rprec8)                                          :: diff, old_diff
+    INTEGER                                                  :: n, iter, i
+    INTRINSIC sqrt
+
+    n = SIZE(A,dim=1)
+
+    ! A = L + U + D = (L + U) + D :
+    LU = A
+    FORALL(i=1:n)
+       D(i) = LU(i,i)
+       LU(i,i) = 0.0_rprec8
+    END FORALL
+
+    x = 0.0_rprec8
+    y = 0.0_rprec8
+    diff = HUGE(diff)
+    iter = 1
+
+    DO WHILE (diff > iteration_factor*EPSILON(diff))
+       DO i=1, n
+          IF (ABS(D(i)) < EPSILON(D(i))) THEN
+             error = " -> linal : Gauss_Seidel_iteration : Attempted division by almost zero." // &
+                  TRIM(error)
+             RETURN
+          END IF
+          y(i) = (b(i) - DOT_PRODUCT(LU(i,1:i-1), y(1:i-1)) - &
+               DOT_PRODUCT(LU(i,i+1:n), x(i+1:n))) / D(i)
+       END DO
+       old_diff = diff
+       diff = SQRT(DOT_PRODUCT(x - y, x - y))
+       IF (diff > old_diff) THEN
+          error = " -> linal : Gauss_Seidel_iteration : Iteration divergent." // &
+               TRIM(error)
+          RETURN
+       END IF
+       x = y
+       iter = iter + 1
+       IF (iter > max_iter) THEN
+          error = " -> linal : Gauss_Seidel_iteration : Reached maximum number of iterations." // &
+               TRIM(error)
+          RETURN
+       END IF
+    END DO
+
+    b = x
+
+  END SUBROUTINE Gauss_Seidel_iteration
+
+
+
+
+
+  REAL(rprec8) FUNCTION determinant(A, error)
+
+    !! Returns the determinant of a square matrix.
+    !!
+    !! Input:  - Square matrix                   A(n,n)
+    !! Output: - Error message (.false., if ok)  error
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)             :: A
+    CHARACTER(len=*), INTENT(inout)                                  :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1),SIZE(A,dim=2)) :: B
+    INTEGER, DIMENSION(SIZE(A,dim=1))                       :: indx
+    INTEGER                                                 :: i
+
+    B = A
+
+    ! A => LU :
+    CALL LU_factor(B, indx, error)
+    IF (LEN_TRIM(error) /= 0) THEN
+       error = " -> linal : determinant : ." // TRIM(error)
+       determinant = 0.0_rprec8
+       RETURN
+    END IF
+    ! det = U(1,1)*U(2,2)*U(3,3)*...*U(n,n)
+    determinant = 1.0_rprec8
+    DO i=1, SIZE(B,dim=1)
+       determinant = determinant * B(i,i)
+    END DO
+
+  END FUNCTION determinant
+
+
+
+
+
+  REAL(rprec8) FUNCTION cond_nr(A, error)
+
+    !! Finds the condition number of a given matrix. A failure in the
+    !! matrix inversion results in a huge condition number.
+    !!
+    !! Input:  - Square matrix              A(n,n)
+    !! Output: - Error (.false., if ok)     error
+    !!
+    !! Other:  - Matrix norm of A           A_norm
+    !!         - Matrix norm of A^(-1)      inv_A_norm
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)             :: A
+    CHARACTER(len=*), INTENT(inout)                               :: error
+    REAL(rprec8), DIMENSION(SIZE(A,dim=2),SIZE(A,dim=1)) :: inv_A
+    REAL(rprec8)                                         :: A_norm, inv_A_norm
+
+    A_norm = matnorm(A)
+    inv_A = matinv(A, error)
+    IF (LEN_TRIM(error) /= 0) THEN
+       error = " -> linal : cond_nr : ." // TRIM(error)
+       cond_nr = HUGE(cond_nr)
+       RETURN
+    END IF
+    inv_A_norm = matnorm(inv_A)
+    cond_nr = A_norm * inv_A_norm
+
+  END FUNCTION cond_nr
+
+
+
+
+
+  REAL(rprec8) FUNCTION matnorm(A)
+
+    !! Finds the matrix norm of a given matrix.
+    !!
+    !! Input:  - Matrix       A(:,:)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: A
+    REAL(rprec8), DIMENSION(SIZE(A,dim=1))   :: s
+    INTEGER                                     :: i
+
+    ! Find the sum of each row:
+    FORALL(i=1:SIZE(A,dim=1))
+       s(i) = SUM(ABS(A(i,1:SIZE(A,dim=2))))
+    END FORALL
+    ! Matrix norm is equal to the greatest sum:
+    matnorm = MAXVAL(s)
+
+  END FUNCTION matnorm
+
+
+
+
+  SUBROUTINE matrix_print_r8(A, lu, error, frmt, row_indx, column_indx)
+
+    !! Writes the given matrix to the given i/o-unit using a nice
+    !! layout.
+    !!
+    !! Input:  - Square matrix           A(n,n)
+    !!         - I/O-unit                iounit
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)    :: A
+    INTEGER, INTENT(in)                         :: lu
+    CHARACTER(len=*), INTENT(inout)             :: error
+    CHARACTER(len=*), INTENT(in), OPTIONAL      :: frmt
+    INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: row_indx
+    INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: column_indx
+    CHARACTER(len=32)                           :: form
+    INTEGER, DIMENSION(:), ALLOCATABLE          :: indx1, indx2
+    INTEGER                                     :: i, j, siz1, siz2, err
+
+    siz1 = SIZE(A, dim=1)
+    siz2 = SIZE(A, dim=2)
+    ALLOCATE(indx1(siz1), indx2(siz2), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matrix_print : Could not allocate memory." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+    IF (PRESENT(frmt)) THEN
+       form = TRIM(frmt)
+    ELSE
+       form = TRIM(frmt_default)
+    END IF
+    IF (PRESENT(row_indx)) THEN
+       indx1 = row_indx
+    ELSE
+       DO i=1,siz1
+          indx1(i) = i
+       END DO
+    END IF
+    IF (PRESENT(column_indx)) THEN
+       indx2 = column_indx
+    ELSE
+       DO i=1,siz2
+          indx2(i) = i
+       END DO
+    END IF
+
+    ! Write the matrix row-wise:
+    DO i=1,siz1
+       DO j=1,siz2
+          WRITE(lu,TRIM(form),advance='no') A(indx1(i),indx2(j))
+       END DO
+       WRITE(lu,*)
+    END DO
+
+    DEALLOCATE(indx1, indx2, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matrix_print : Could not deallocate memory." // &
+            TRIM(error)
+       DEALLOCATE(indx1, stat=err)
+       DEALLOCATE(indx2, stat=err)
+       RETURN       
+    END IF
+
+  END SUBROUTINE matrix_print_r8
+
+
+
+
+
+  SUBROUTINE matrix_print_r16(A, lu, error, frmt)
+
+    !! Writes the given matrix to the given i/o-unit using a nice
+    !! layout.
+    !!
+    !! Input:  - Square matrix           A(n,n)
+    !!         - I/O-unit                lu
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:,:), INTENT(in)  :: A
+    INTEGER, INTENT(in)                          :: lu
+    CHARACTER(len=*), INTENT(inout)       :: error
+    CHARACTER(len=*), INTENT(in), OPTIONAL       :: frmt
+    REAL(rprec16), DIMENSION(:,:), ALLOCATABLE :: AA
+    CHARACTER(len=30)                            :: form, c
+    REAL                                         :: x, y
+    INTEGER, DIMENSION(2)                        :: lo_bound, up_bound
+    INTEGER                                      :: i, n, p, err
+
+    INTRINSIC lbound, ubound, fraction, nint, char, trim 
+
+    lo_bound = LBOUND(A)
+    up_bound = UBOUND(A)
+    ALLOCATE(AA(lo_bound(1):up_bound(1),lo_bound(2):up_bound(2)), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matrix_print : Could not allocate memory." // &
+            TRIM(error)
+       RETURN       
+    END IF
+    AA = A
+
+    ! Change integer n to character c (= n):
+    n = up_bound(2) - lo_bound(2) + 1
+    c = ''
+    DO WHILE (n > 0)
+       x = n / 10.0
+       y = FRACTION(x)
+       n = NINT(x - y)
+       p = NINT(10 * y)
+       c = CHAR(48 + p) // TRIM(c)
+    END DO
+
+    IF (PRESENT(frmt)) THEN
+       form = '(' // TRIM(c) // TRIM(frmt) // ')'
+    ELSE
+       form = '(' // TRIM(c) // TRIM(frmt_default) // ')'
+    END IF
+
+    ! Write the matrix row-wise:
+    DO i=lo_bound(1), up_bound(1)
+       WRITE(lu,TRIM(form)) AA(i,:)
+    END DO
+
+    DEALLOCATE(AA, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : matrix_print : Could not deallocate memory." // &
+            TRIM(error)
+       RETURN       
+    END IF
+
+  END SUBROUTINE matrix_print_r16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Ref. Numerical Recipes for Fortran 90, Sect. 23.5 
+  !!
+  FUNCTION outer_product_r4(a, b)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), INTENT(in) :: a, b
+    REAL(rprec4), DIMENSION(SIZE(a),SIZE(b)) :: outer_product_r4
+
+    outer_product_r4 = SPREAD(a,dim=2,ncopies=SIZE(b)) * &
+         SPREAD(b,dim=1,ncopies=SIZE(a))
+
+  END FUNCTION outer_product_r4
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Ref. Numerical Recipes for Fortran 90, Sect. 23.5 
+  !!
+  FUNCTION outer_product_r8(a, b)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: a, b
+    REAL(rprec8), DIMENSION(SIZE(a),SIZE(b)) :: outer_product_r8
+
+    outer_product_r8 = SPREAD(a,dim=2,ncopies=SIZE(b)) * &
+         SPREAD(b,dim=1,ncopies=SIZE(a))
+
+  END FUNCTION outer_product_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Ref. Numerical Recipes for Fortran 90, Sect. 23.5 
+  !!
+  FUNCTION outer_product_r16(a, b)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(in) :: a, b
+    REAL(rprec16), DIMENSION(SIZE(a),SIZE(b)) :: outer_product_r16
+
+    outer_product_r16 = SPREAD(a,dim=2,ncopies=SIZE(b)) * &
+         SPREAD(b,dim=1,ncopies=SIZE(a))
+
+  END FUNCTION outer_product_r16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the triple product (x dot (y cross z)) of three vectors
+  !! with three elements.
+  !!
+  REAL(rprec8) FUNCTION triple_product_r8(x,y,z)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(3), INTENT(in) :: x, y, z
+
+    triple_product_r8 = DOT_PRODUCT(x,cross_product(y,z))
+
+  END FUNCTION triple_product_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns cross product of two 3-vectors.
+  !!
+  FUNCTION cross_product_r8(x,y) RESULT(cross_prod)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(3), INTENT(in) :: x, y 
+    REAL(rprec8), DIMENSION(3)             :: cross_prod
+
+    cross_prod(1) = x(2)*y(3) - x(3)*y(2)
+    cross_prod(2) = x(3)*y(1) - x(1)*y(3)
+    cross_prod(3) = x(1)*y(2) - x(2)*y(1)
+
+  END FUNCTION cross_product_r8
+
+
+
+
+
+  SUBROUTINE vector_print(b, lu, column, error, frmt)
+
+    !! Writes the given vector to the given i/o-unit using a nice
+    !! layout.
+    !!
+    !! Input:  - Vector                          b(n)
+    !!         - Column = .true., row = .false.  column
+    !!         - I/O-unit                        lu
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)  :: b
+    INTEGER, INTENT(in)                        :: lu
+    LOGICAL, INTENT(in)                        :: column
+    CHARACTER(len=*), INTENT(inout)     :: error
+    CHARACTER(len=*), INTENT(in), OPTIONAL     :: frmt
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: bb
+    CHARACTER(len=30)                          :: form, c
+    REAL                                       :: x, y
+    INTEGER, DIMENSION(1)                      :: lo_bound, up_bound
+    INTEGER                                    :: i, n, p, indx, err
+
+    INTRINSIC lbound, ubound, fraction, nint, char, trim 
+
+    lo_bound = LBOUND(b)
+    up_bound = UBOUND(b)
+    ALLOCATE(bb(lo_bound(1):up_bound(1)), stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : vector_print : Could not allocate memory." // &
+            TRIM(error)
+       RETURN
+    END IF
+    bb = b
+
+    WHERE (ABS(bb) < EPSILON(bb)) bb = 0
+
+    IF (column) THEN
+       ! Writes a column vector:
+       IF (PRESENT(frmt)) THEN
+          ! Remove empty spaces:
+          indx = INDEX(frmt,',',back=.TRUE.)
+          form = '(' // frmt(1:indx-1) // '))'
+       ELSE
+          indx = INDEX(frmt_default,',',back=.TRUE.)
+          form = '(' // frmt_default(1:indx-1) // '))'
+       END IF
+       DO i=lo_bound(1), up_bound(1)
+          WRITE(lu,TRIM(form)) bb(i)
+       END DO
+    ELSE
+       ! Writes a row vector:
+       ! Change integer n to character c (= n):
+       n = up_bound(1) - lo_bound(1) + 1
+       c = ''
+       DO WHILE (n > 0)
+          x = n / 10.0
+          y = FRACTION(x)
+          n = NINT(x - y)
+          p = NINT(10 * y)
+          c = CHAR(48 + p) // TRIM(c)
+       END DO
+       IF (PRESENT(frmt)) THEN
+          form = '(' // TRIM(c) // TRIM(frmt) // ')'
+       ELSE
+          form = '(' // TRIM(c) // TRIM(frmt_default) // ')'
+       END IF
+       WRITE(lu,TRIM(form)) bb
+    END IF
+
+    DEALLOCATE(bb, stat=err)
+    IF (err /= 0) THEN
+       error = " -> linal : vector_print : Could not deallocate memory." // &
+            TRIM(error)
+       RETURN
+    END IF
+
+  END SUBROUTINE vector_print
+
+
+
+END MODULE linal
Index: trunk/mops/oorb/modules/parameters.f90
===================================================================
--- trunk/mops/oorb/modules/parameters.f90	(revision 34646)
+++ trunk/mops/oorb/modules/parameters.f90	(revision 34646)
@@ -0,0 +1,41 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Parameters for modules.
+!!
+!! @author  MG
+!! @version 2009-04-17
+!!
+MODULE parameters
+
+  IMPLICIT NONE
+  INTEGER, PARAMETER :: iprec1 = SELECTED_INT_KIND(2)
+  INTEGER, PARAMETER :: iprec4 = SELECTED_INT_KIND(7)
+  INTEGER, PARAMETER :: iprec8 = SELECTED_INT_KIND(12)
+  INTEGER, PARAMETER :: rprec4 = SELECTED_REAL_KIND(p=6)
+  INTEGER, PARAMETER :: rprec8 = SELECTED_REAL_KIND(p=12)
+  INTEGER, PARAMETER :: rprec16 = SELECTED_REAL_KIND(p=18)
+
+END MODULE parameters
Index: trunk/mops/oorb/modules/planetary_data.f90
===================================================================
--- trunk/mops/oorb/modules/planetary_data.f90	(revision 34646)
+++ trunk/mops/oorb/modules/planetary_data.f90	(revision 34646)
@@ -0,0 +1,1419 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011,2012   !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Defines parameters relating to planets and minor planets in the 
+!! solar system, and contains the routines for using planetary
+!! ephemeris provided by the Jet Propulsion Laboratory.
+!!
+!! This software is partly based on <i>jplsub.f</i> (by JPL) and a
+!! Fortran 90 compilation of the same software by Hannu Karttunen 
+!! (Tuorla Observatory, Turku, Finland).
+!!
+!! *Example*:
+!!
+!!<pre>
+!!program myprog
+!!
+!! use planetary_data
+!! implicit none
+!! real(8), dimension(6) :: crtcrd
+!! real(8) :: t
+!! logical :: error
+!!
+!! crtcrd = JPL_ephemeris(t, 3, 11, error)
+!! if (error) stop 'Error 2'
+!!
+!!end program myprog
+!!</pre>
+!!
+!! @author  MG, TL
+!! @version 2012-01-09
+!!
+MODULE planetary_data
+
+  USE parameters
+  USE linal
+  IMPLICIT NONE
+  PRIVATE
+  CHARACTER(len=256), PARAMETER :: EPH_FNAME = 'de405.dat' 
+  INTEGER, PARAMETER            :: RECORD_LENGTH = 4
+  INTEGER, PARAMETER            :: RECORD_SIZE_405 =  2036
+  INTEGER, PARAMETER            :: RECORD_SIZE_406 =  1456
+  INTEGER, PARAMETER            :: NCOEFF_405 = 1018
+  INTEGER, PARAMETER            :: NCOEFF_406 = 728
+  INTEGER, PARAMETER            :: NRECORD_MAX = 35000 ! Fits all of de405 and de406
+  REAL(rprec8), PARAMETER       :: ggc = 0.01720209895_rprec8
+  REAL(rprec8), PARAMETER       :: kgm3_smau3 = (1.4959787066e8_rprec8)**3/1.989100e30
+
+
+  CHARACTER(len=23), DIMENSION(13), PARAMETER, PUBLIC :: planetary_locations = (/ &
+       "Mercury                ", &
+       "Venus                  ", &
+       "Earth                  ", &
+       "Mars                   ", &
+       "Jupiter                ", &
+       "Saturn                 ", &
+       "Uranus                 ", &
+       "Neptune                ", &
+       "Pluto                  ", &
+       "Moon                   ", &
+       "Sun                    ", &
+       "solar-system_barycenter", &
+       "Earth-Moon_barycenter  " /)
+
+  ! Unit: AU
+  REAL(rprec8), DIMENSION(17), PARAMETER, PUBLIC :: planetary_radii = (/ &
+       1.63037e-5_rprec8, &   !!  (1) Mercury,
+       4.04551e-5_rprec8, &   !!  (2) Venus,
+       4.25641e-5_rprec8, &   !!  (3) Earth, 
+       2.26491e-5_rprec8, &   !!  (4) Mars,
+       4.62908e-4_rprec8, &   !!  (5) Jupiter,
+       3.81021e-4_rprec8, &   !!  (6) Saturn,
+       1.72128e-4_rprec8, &   !!  (7) Uranus,
+       1.60096e-4_rprec8, &   !!  (8) Neptune,
+       8.17191e-6_rprec8, &   !!  (9) Pluto,
+       1.16178e-5_rprec8, &   !! (10) Moon,
+       4.65424e-3_rprec8, &   !! (11) Sun,
+       0.e0_rprec8,       &   !! (12) solar system barycenter,
+       0.e0_rprec8,       &   !! (13) Earth-Moon barycenter,
+       0.e0_rprec8,       &   !! (14) Asteroid,
+       3.05151e-6_rprec8, &   !! (15) Ceres,
+       1.74802e-6_rprec8, &   !! (16) Pallas,
+       1.67449e-6_rprec8  /)  !! (17) Vesta
+
+  ! Data from http://ssd.jpl.nasa.gov/ 
+  ! Unit: M_sol
+  REAL(rprec8), DIMENSION(17), PARAMETER, PUBLIC :: planetary_masses = (/ &
+       1.0_rprec8/6023600.0_rprec8, &                                      !!  (1) Mercury,
+       1.0_rprec8/408523.71_rprec8, &                                      !!  (2) Venus,
+       1.0_rprec8/(328900.56_rprec8*(1.0_rprec8+0.012300033739_rprec8)), & !!  (3) Earth, 
+       1.0_rprec8/3098708.0_rprec8, &                                      !!  (4) Mars,
+       1.0_rprec8/1047.3486_rprec8, &                                      !!  (5) Jupiter,
+       1.0_rprec8/3497.898_rprec8, &                                       !!  (6) Saturn,
+       1.0_rprec8/22902.98_rprec8, &                                       !!  (7) Uranus,
+       1.0_rprec8/19412.24_rprec8, &                                       !!  (8) Neptune,
+       1.0_rprec8/1.35e8_rprec8, &                                         !!  (9) Pluto,
+       1.0_rprec8/(328900.56_rprec8*(1.0_rprec8+81.30059_rprec8)), &       !! (10) Moon,
+       1.0_rprec8, &                                                       !! (11) Sun,
+       0.0_rprec8, &                                                       !! (12) solar system barycenter,
+       1.0_rprec8/328900.56_rprec8, &                                      !! (13) Earth-Moon barycenter,
+       0.0_rprec8, &                                                       !! (14) Asteroid,
+       1.0_rprec8/2099880378.8_rprec8, &                                   !! (15) Ceres,   GM=63.2
+       1.0_rprec8/9280590205.59_rprec8, &                                  !! (16) Pallas,  GM=14.3
+       1.0_rprec8/7455755052.81_rprec8  /)                                 !! (17) Vesta    GM=17.8
+
+  ! Data from http://nssdc.gsfc.nasa.gov/planetary/planetfact.html
+  ! Unit: M_sol AU^(-3)
+  REAL(rprec8), DIMENSION(17), PARAMETER, PUBLIC :: planetary_densities = (/ &
+       5427.0_rprec8*kgm3_smau3, &               !!  (1) Mercury,
+       5243.0_rprec8*kgm3_smau3, &               !!  (2) Venus,
+       5515.0_rprec8*kgm3_smau3, &               !!  (3) Earth, 
+       3933.0_rprec8*kgm3_smau3, &               !!  (4) Mars,
+       1326.0_rprec8*kgm3_smau3, &               !!  (5) Jupiter,
+       687.0_rprec8*kgm3_smau3, &                !!  (6) Saturn,
+       1270.0_rprec8*kgm3_smau3, &               !!  (7) Uranus,
+       1632.0_rprec8*kgm3_smau3, &               !!  (8) Neptune,
+       1750.0_rprec8*kgm3_smau3, &               !!  (9) Pluto,
+       3340.0_rprec8*kgm3_smau3, &               !! (10) Moon,
+       1408.0_rprec8*kgm3_smau3, &               !! (11) Sun,
+       -1.0_rprec8, &                            !! (12) solar system barycenter,
+       -1.0_rprec8, &                            !! (13) Earth-Moon barycenter,
+       2500.0_rprec8*kgm3_smau3, &               !! (14) Asteroid,
+       0.0_rprec8, &                             !! (15) Ceres,
+       0.0_rprec8, &                             !! (16) Pallas,
+       0.0_rprec8  /)                            !! (17) Vesta
+
+  ! Constants of gravitation (G*M)
+  ! Unit: AU^3 day^(-2)
+  REAL(rprec8), DIMENSION(14), PARAMETER, PUBLIC :: planetary_mu  = (/ &
+       ggc**2*planetary_masses(1), &             !!  (1) Mercury,
+       ggc**2*planetary_masses(2), &             !!  (2) Venus,
+                                !8.887692691e-10_rprec8, &                 !!  (3) Earth, in SI: 398600.4415e9_bp (IAU'94)
+       ggc**2*planetary_masses(3), &             !!  (3) Earth,
+       ggc**2*planetary_masses(4), &             !!  (4) Mars,
+       ggc**2*planetary_masses(5), &             !!  (5) Jupiter,
+       ggc**2*planetary_masses(6), &             !!  (6) Saturn,
+       ggc**2*planetary_masses(7), &             !!  (7) Uranus,
+       ggc**2*planetary_masses(8), &             !!  (8) Neptune,
+       ggc**2*planetary_masses(9), &             !!  (9) Pluto,
+       ggc**2*planetary_masses(10), &            !! (10) Moon,
+       ggc**2*planetary_masses(11), &            !! (11) Sun; ggc**2 * 1
+       ggc**2*planetary_masses(12), &            !! (12) solar system barycenter,
+       ggc**2*planetary_masses(13), &            !! (13) Earth-Moon barycenter,
+       0.0_rprec8 /)                             !! (14) Asteroid
+
+  CHARACTER(len=6), DIMENSION(14,3)         :: ttl
+  CHARACTER(len=6), DIMENSION(400)          :: cnam
+  REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: buf
+  REAL(rprec8), DIMENSION(400)              :: cval
+  REAL(rprec8), DIMENSION(3)                :: ss
+  REAL(rprec8)                              :: au, emrat
+  INTEGER, DIMENSION(3,13)                  :: ipt
+  INTEGER                                   :: numde, ncon, rec_size, eph_size
+  LOGICAL                                   :: first = .TRUE.
+  LOGICAL                                   :: kilometres = .FALSE.
+  LOGICAL                                   :: barycenter = .TRUE.
+
+  PUBLIC :: JPL_ephemeris_init
+  PUBLIC :: JPL_ephemeris
+  PUBLIC :: JPL_ephemeris_nullify
+  PUBLIC :: Hill_radius
+
+  INTERFACE JPL_ephemeris
+     MODULE PROCEDURE JPL_ephemeris_r8
+     MODULE PROCEDURE JPL_ephemeris_perturbers_r8
+     MODULE PROCEDURE JPL_ephemeris_r16
+     MODULE PROCEDURE JPL_ephemeris_perturbers_r16
+  END INTERFACE JPL_ephemeris
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Returns the radius of the Hill sphere 
+  !!
+  !!    r_H ~ a_1(1-e_1) * (mass_1/3mass_2)^(1/3))
+  !!
+  !! where M_1 and M_2 are the masses of the object whose Hill-sphere
+  !! radius is sought (e.g., the Earth) and the object around which
+  !! the previous revolves (e.g., the Sun), respectively. The
+  !! semimajor axis a_1 and eccentricity e_1 refer to the previous
+  !! object. The default values for a_1 (= 1.0 AU) and e_1 (= 0) will
+  !! be used if they are not explicitly given.
+  !!
+  REAL(rprec8) FUNCTION Hill_radius(mass_1, mass_2, a_1, e_1)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in) :: mass_1, mass_2
+    REAL(rprec8), OPTIONAL, INTENT(in) :: a_1, e_1
+
+    REAL(rprec8) :: a_, e_
+
+    IF (PRESENT(a_1)) THEN
+       a_ = a_1
+    ELSE
+       a_ = 1.0_rprec8
+    END IF
+    IF (PRESENT(e_1)) THEN
+       e_ = e_1
+    ELSE
+       e_ = 0.0_rprec8
+    END IF
+
+    Hill_radius =  a_*(1.0_rprec8-e_) * (mass_1/(3*mass_2))**(1.0_rprec8/3)
+
+  END FUNCTION Hill_radius
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! If used for the first time during execution, this routine reads
+  !! the JPL Planetary Ephemerides from a given file (known as
+  !! de405.dat at JPL) and stores the data in an array.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE JPL_ephemeris_init(error, filename)
+
+    IMPLICIT NONE
+    LOGICAL, INTENT(inout)                 :: error
+    CHARACTER(len=*), OPTIONAL, INTENT(in) :: filename
+    INTEGER, PARAMETER                     :: min_lu = 10
+    INTEGER, PARAMETER                     :: max_lu = 99
+    CHARACTER(len=256)                     :: fname, OORB_DATA_DIR    
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: tmp
+    INTEGER                                :: err, i, lu, count
+    LOGICAL                                :: done, used
+
+    ! Make sure this is the first call to this routine
+    IF (.NOT.first) THEN
+       RETURN
+    END IF
+
+    IF (PRESENT(filename) .AND. LEN_TRIM(filename) <= 256) THEN
+       fname = TRIM(filename)
+    ELSE
+       ! only use with gfortran
+       !CALL get_environment_variable("OORB_DATA", OORB_DATA_DIR)
+       ! only use with g95
+       CALL getenv("OORB_DATA", OORB_DATA_DIR)
+       IF (LEN_TRIM(OORB_DATA_DIR) == 0) THEN
+          OORB_DATA_DIR = "."
+       END IF
+       fname = TRIM(OORB_DATA_DIR) // "/" // TRIM(EPH_FNAME)
+    END IF
+
+    ! Find a free logical unit:
+    done = .FALSE.
+    count = min_lu
+    lu = min_lu
+    DO WHILE (.NOT. done)
+       ! Figure out whether this unit is taken or not:
+       INQUIRE(unit=lu, opened=used, iostat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_init(): Error when inquiring for status of logical unit."
+          RETURN
+       END IF
+       IF (used) THEN
+          count = count + 1
+          ! If more than max_lu units have been tried,
+          ! every available unit has been tried at least once.
+          ! A free unit could not be found: 
+          IF (count > max_lu) THEN
+             error = .TRUE.
+             WRITE(0,*) "JPL_ephemeris_init(): Could not find a free logical unit."
+             RETURN
+          END IF
+          lu = lu + 1
+          ! Back to beginning if top is reached:
+          IF (lu > max_lu) lu = min_lu
+       ELSE
+          done = .TRUE.
+       END IF
+    END DO
+
+    ! Read deXXX.dat (or whatever you call the JPL Planetary Ephemeris file):
+    !WRITE(0,"(A,1X,A)") "Using ephemeris file ", TRIM(fname)
+    IF (INDEX(fname,"405") /= 0) THEN
+       OPEN(unit=lu, file=TRIM(fname), status='OLD', access='DIRECT', &
+            recl=RECORD_LENGTH*RECORD_SIZE_405, action='READ', iostat=err)
+    ELSE IF (INDEX(fname,"406") /= 0) THEN
+       OPEN(unit=lu, file=TRIM(fname), status='OLD', access='DIRECT', &
+            recl=RECORD_LENGTH*RECORD_SIZE_406, action='READ', iostat=err)
+    END IF
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not open file '" // TRIM(fname) // "'."
+       RETURN
+    END IF
+
+    READ(lu, rec=1, iostat=err) ttl, cnam, ss, ncon, &
+         au, emrat, ipt(1:3,1:12), numde, ipt(1:3,13)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not read record #1."
+       RETURN
+    END IF
+
+    READ(lu, rec=2, iostat=err) cval
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not read record #2."
+       RETURN
+    END IF
+
+    IF (INDEX(fname,"405") /= 0) THEN
+       ALLOCATE(tmp(NCOEFF_405,NRECORD_MAX), stat=err)
+    ELSE IF (INDEX(fname,"406") /= 0) THEN
+       ALLOCATE(tmp(NCOEFF_406,NRECORD_MAX), stat=err)
+    END IF
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not allocate memory (5)."
+       DEALLOCATE(tmp, stat=err)
+       RETURN
+    END IF
+    i = 1
+    DO
+       READ(lu, rec=i+2, iostat=err) tmp(:,i)
+       IF (err /= 0) THEN
+          i = i - 1
+          EXIT
+       ELSE
+          i = i + 1
+          IF (i+2 > NRECORD_MAX) THEN
+             error = .TRUE.
+             WRITE(0,*) "JPL_ephemeris_init(): NRECORD_MAX too small."
+             DEALLOCATE(tmp, stat=err)
+             RETURN
+          END IF
+       END IF
+    END DO
+    ALLOCATE(buf(SIZE(tmp,dim=1),i), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not allocate memory (10)."
+       DEALLOCATE(tmp, stat=err)
+       RETURN
+    END IF
+    buf(1:SIZE(tmp,dim=1),1:i) = tmp(1:SIZE(tmp,dim=1),1:i)
+    DEALLOCATE(tmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_init(): Could not deallocate memory."
+       RETURN
+    END IF
+    CLOSE(lu)
+    first = .FALSE.
+
+  END SUBROUTINE JPL_ephemeris_init
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Deallocates memory used by the planetary ephemerides. Should be
+  !! used at the very end of an executable.
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE JPL_ephemeris_nullify()
+
+    IMPLICIT NONE
+    INTEGER :: err
+
+    DEALLOCATE(buf, stat=err)
+
+  END SUBROUTINE JPL_ephemeris_nullify
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads the JPL Planetary Ephemeris and gives the position and 
+  !! velocity of the point 'ntarget' with respect to 'ncenter'.
+  !!
+  !! ntarget = integer number of target point.
+  !!
+  !! ncentet = integer number of center point.
+  !!
+  !! The numbering convention for 'ntarget' and 'ncenter' is:
+  !!
+  !!<pre>
+  !!         1 = Mercury            8 = Neptune
+  !!         2 = Venus              9 = Pluto
+  !!         3 = Earth             10 = Moon
+  !!         4 = Mars              11 = Sun
+  !!         5 = Jupiter          (12 = solar-system barycenter)
+  !!         6 = Saturn           (13 = earth-moon barycenter)
+  !!         7 = Uranus           (14 = nutations (longitude and obliq))
+  !!                              (15 = librations, if on eph file)
+  !!<pre>
+  !!  Additional: -10 = 9 planets + Moon
+  !!
+  !! If nutations are wanted, set ntarget = 14, and for librations,
+  !! set ntarget = 15. Set ncenter = 0.
+  !!
+  !! Output is a 6-vector containing position and velocity of point
+  !! 'ntarget' relative to 'ncenter' in an equatorial reference
+  !! frame. The units are AU and AU/day.  For librations the units are
+  !! radians and radians per day.
+  !!
+  !! Returns error.
+  !! 
+  !! ntarget=-10 and ncenter=11 tested to produce correct results.
+  !! ntarget=-10 and ncenter=12 tested to produce correct results.
+  !!
+  ! In the case 
+  ! of nutations the first four words of rrd will be set to nutations and 
+  ! rates, having units of radians and radians/day.
+  !!
+  !! Known errors: 
+  !! 
+  !!  ntarget  ncenter
+  !!    13       11        (note that 11 13 works?!?)
+  !!    -9       11
+  !!    -9       12
+  !!
+  FUNCTION JPL_ephemeris_r8(mjd_tt, ntarget, ncenter, error, km)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)              :: mjd_tt
+    INTEGER, INTENT(in)                   :: ntarget, ncenter
+    LOGICAL, INTENT(inout)                :: error
+    LOGICAL, OPTIONAL, INTENT(in)         :: km
+    REAL(rprec8), DIMENSION(:,:), POINTER :: JPL_ephemeris_r8
+
+    REAL(rprec8), DIMENSION(13,6) :: celements
+    REAL(rprec8), DIMENSION(6)    :: celements_
+    REAL(rprec8), DIMENSION(2)    :: tt2
+    INTEGER, DIMENSION(12)        :: list
+    INTEGER                       :: i, k, err
+    LOGICAL                       :: tmp_barycenter
+
+    celements = 0.0_rprec8
+
+    IF (first) THEN
+       CALL JPL_ephemeris_init(error)
+       IF (error) THEN
+          WRITE(0,*) "JPL_ephemeris_r8(): Error when calling JPL_ephemeris_init()."
+          RETURN
+       END IF
+    END IF
+
+    IF (ntarget == ncenter) THEN
+       ALLOCATE(JPL_ephemeris_r8(1,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_r8(): Could not allocate memory for output (1)."
+          RETURN
+       END IF
+       JPL_ephemeris_r8(1,1:6) = 0.0_rprec8
+       RETURN
+    END IF
+
+    IF (PRESENT(km)) THEN
+       kilometres = km
+    END IF
+
+    tt2(1) = mjd_tt + 2400000.5_rprec8 ! convert to Julian date
+    tt2 = split(tt2(1))
+    IF (tt2(2) < 0.5_rprec8) THEN
+       tt2(1) = tt2(1) - 0.5_rprec8
+       tt2(2) = tt2(2) + 0.5_rprec8
+    ELSE
+       tt2(1) = tt2(1) + 0.5_rprec8
+       tt2(2) = tt2(2) - 0.5_rprec8
+    END IF
+    list = 0
+
+    !  check for librations
+    IF (ntarget == 15) THEN 
+       IF (ipt(2,13) > 0) THEN
+          list(12) = 2
+          celements(1:12,1:6) = states(tt2, list, error)
+          IF (error) THEN
+             WRITE(0,*) 'JPL_ephemeris_r8(): Target object and center object are the same.'
+             RETURN
+          ELSE
+             !state = celements(11,:)
+             RETURN
+          END IF
+       ELSE
+          error = .TRUE.
+          WRITE(0,*) 'JPL_ephemeris_r8(): No librations available on the ephemeris file.'
+          RETURN
+       END IF
+    END IF
+
+    ! Force barycentric output from states()
+    tmp_barycenter = barycenter
+    barycenter = .TRUE.
+
+    !  set up proper entries in 'list' array for state call
+    IF (ntarget > 0) THEN
+       DO i=1, 2
+          IF (i == 1) THEN
+             k = ntarget
+          ELSE IF (i == 2) THEN
+             k = ncenter
+          END IF
+          IF (k <= 10) THEN
+             list(k)  = 2 ! If k:th planet wanted, k:th is needed 
+          END IF
+          IF (k == 3) THEN
+             list(10) = 2 ! If Earth wanted, Moon is needed
+          END IF
+          IF (k == 10) THEN
+             list(3)  = 2 ! If Moon wanted, Earth is needed
+          END IF
+          IF (k == 13) THEN
+             list(3)  = 2 ! If barycentric Earth-Moon wanted, Earth is needed
+          END IF
+       END DO
+    ELSE IF (ntarget == -9 .OR. ntarget == -10) THEN
+       list(1:10) = 2
+    END IF
+
+    !  make call to state
+    celements(1:12,1:6) = states(tt2, list, error)
+    IF (error) THEN
+       WRITE(0,*) 'JPL_ephemeris_r8(): Error when calling states() (1).'
+       RETURN
+    END IF
+
+    ! If the target or the center is the Sun, 
+    ! change it to the Solar System barycenter:
+    IF (ntarget == 11 .OR. ncenter == 11 .OR. ntarget < 0) THEN
+       celements(11,:) = celements(12,1:6)
+    END IF
+
+    ! If the target or the center is the Solar System barycenter, 
+    ! set its coordinates to zero:
+    IF (ntarget == 12 .OR. ncenter == 12) THEN
+       celements(12,:) = 0.0_rprec8
+    END IF
+
+    ! If the target or the center is the Earth-Moon barycenter, 
+    ! set it initially equal to the coordinates of the Earth:
+    IF (ntarget == 13 .OR. ncenter == 13 .OR. ntarget == -9) THEN
+       celements(13,:) = celements(3,:)
+    END IF
+
+    ! If Earth to Moon (or vice versa) coordinates are needed, use
+    ! geocentric coordinates for the Moon:
+    IF (ntarget * ncenter == 30 .AND. ntarget + ncenter == 13) THEN 
+       celements(3,:) = 0.0_rprec8
+       celements(ntarget,:) = celements(ntarget,:) - celements(ncenter,:)
+       ALLOCATE(JPL_ephemeris_r8(1,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_r8(): Could not allocate memory for output (2)."
+          RETURN
+       END IF
+       JPL_ephemeris_r8(1,1:6) = celements(ntarget,1:6)
+       barycenter = tmp_barycenter
+       RETURN
+    END IF
+
+    ! If the target or the center is the Moon or the Earth-Moon barycenter, 
+    ! compute Earth coordinates using coordinates for the barycentric Earth-Moon 
+    ! system and geocentric coordinates for the Moon:
+    IF (list(3) == 2) THEN
+       celements(3,:) = celements(3,:) - celements(10,:)/(1.0_rprec8 + emrat)
+    END IF
+
+    ! If the target or the center is the Moon, compute Moon's
+    ! coordinates using coordinates for the Earth and geocentric
+    ! coordinates for the Moon:
+    IF (list(10) == 2) THEN
+       celements(10,:) = celements(3,:) + celements(10,:)
+    END IF
+
+    celements_ = celements(ncenter,1:6)
+    barycenter = tmp_barycenter
+    DO i=1,12
+       celements(i,1:6) = celements(i,1:6) - celements_
+    END DO
+    IF (ntarget == -9) THEN ! use Earth-Moon barycenter
+       ALLOCATE(JPL_ephemeris_r8(9,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_r8(): Could not allocate memory for output (3)."
+          RETURN
+       END IF
+       DO i=1,9
+          JPL_ephemeris_r8(i,1:6) = celements(i,1:6)
+       END DO
+       !JPL_ephemeris_r8(3,1:6) = celements(13,1:6)
+    ELSE IF (ntarget == -10) THEN ! separate Earth and Moon
+       ALLOCATE(JPL_ephemeris_r8(10,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_r8(): Could not allocate memory for output (4)."
+          RETURN
+       END IF
+       DO i=1,10
+          JPL_ephemeris_r8(i,1:6) = celements(i,1:6)
+       END DO
+    ELSE IF (ntarget >= 1 .AND. ntarget <= 13) THEN
+       ALLOCATE(JPL_ephemeris_r8(1,6), stat=err)
+       IF (err /= 0) THEN
+          error = .TRUE.
+          WRITE(0,*) "JPL_ephemeris_r8(): Could not allocate memory for output (5)."
+          RETURN
+       END IF
+       JPL_ephemeris_r8(1,1:6) = celements(ntarget,1:6)
+    ELSE
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_r8(): Could not decide what kind of output caller requested."
+       RETURN
+    END IF
+
+  END FUNCTION JPL_ephemeris_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Same as JPL_ephemeris_r8, but with digits allowing greater
+  !! numerical accuracy, i.e., the accuracy of values is the same 
+  !! as for JPL_ephemeris_r8.
+  !!
+  FUNCTION JPL_ephemeris_r16(mjd_tt, ntarget, ncenter, error, km)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in)              :: mjd_tt
+    INTEGER, INTENT(in)               :: ntarget, ncenter
+    LOGICAL, INTENT(inout)            :: error
+    LOGICAL, OPTIONAL, INTENT(in)     :: km
+    REAL(rprec16), DIMENSION(:,:), POINTER :: JPL_ephemeris_r16
+    REAL(rprec8), DIMENSION(:,:), POINTER  :: tmp
+    INTEGER :: err
+
+    IF (PRESENT(km)) THEN
+       tmp => JPL_ephemeris(REAL(mjd_tt,rprec8), ntarget, ncenter, error, km)
+    ELSE
+       tmp => JPL_ephemeris(REAL(mjd_tt,rprec8), ntarget, ncenter, error)
+    END IF
+    IF (error) THEN
+       WRITE(0,*) "JPL_ephemeris_r16(): Error when calling JPL_ephemeris_r8()."
+       RETURN
+    END IF
+    ALLOCATE(JPL_ephemeris_r16(SIZE(tmp,dim=1),SIZE(tmp,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_r16(): Could not allocate memory."
+       DEALLOCATE(tmp, stat=err)
+       RETURN
+    END IF
+    JPL_ephemeris_r16 = REAL(tmp,rprec16)
+    DEALLOCATE(tmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_r16(): Could not deallocate memory."
+       RETURN
+    END IF
+
+  END FUNCTION JPL_ephemeris_r16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads the JPL Planetary Ephemeris and gives the position and 
+  !! velocity of the point 'ntarget' with respect to 'ncenter'.
+  !!
+  !! ntarget = integer number of target point.
+  !!
+  !! ncentet = integer number of center point.
+  !!
+  !! The numbering convention for 'ntarget' and 'ncenter' is:
+  !!
+  !!<pre>
+  !!         1 = Mercury            8 = Neptune
+  !!         2 = Venus              9 = Pluto
+  !!         3 = Earth             10 = Moon
+  !!         4 = Mars              11 = Sun
+  !!         5 = Jupiter          (12 = solar-system barycenter)
+  !!         6 = Saturn           (13 = earth-moon barycenter)
+  !!         7 = Uranus           (14 = nutations (longitude and obliq))
+  !!                              (15 = librations, if on eph file)
+  !!<pre>
+  !!  Additional: -10 = 9 planets + Moon
+  !!
+  !! If nutations are wanted, set ntarget = 14, and for librations,
+  !! set ntarget = 15. Set ncenter = 0.
+  !!
+  !! Output is a CartesianCoordinates object (crtcrd) containing position and velocity
+  !! of point 'ntarget' relative to 'ncenter'. the units are AU and AU/day.
+  !! For librations the units are radians and radians per day.
+  !!
+  !! Returns error.
+  !! 
+  !! ntarget=-10 and ncenter=11 tested to produce correct results.
+  !! ntarget=-10 and ncenter=12 tested to produce correct results.
+  !!
+  ! In the case 
+  ! of nutations the first four words of rrd will be set to nutations and 
+  ! rates, having units of radians and radians/day.
+  !!
+  !! Known errors: 
+  !! 
+  !!  ntarget  ncenter
+  !!    13       11
+  !!    -9       11
+  !!    -9       12
+  !!
+  FUNCTION JPL_ephemeris_perturbers_r8(mjd_tt, ntargets, ncenter, error, km)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)              :: mjd_tt
+    LOGICAL, DIMENSION(:), INTENT(in)     :: ntargets    
+    INTEGER, INTENT(in)                   :: ncenter
+    LOGICAL, INTENT(inout)                :: error
+    LOGICAL, OPTIONAL, INTENT(in)         :: km
+    REAL(rprec8), DIMENSION(:,:), POINTER :: JPL_ephemeris_perturbers_r8
+
+    REAL(rprec8), DIMENSION(13,6) :: celements
+    REAL(rprec8), DIMENSION(6)    :: celements_
+    REAL(rprec8), DIMENSION(2)    :: tt2
+    INTEGER, DIMENSION(12)        :: list
+    INTEGER                       :: i, j, err
+    LOGICAL                       :: tmp_barycenter
+
+    IF (first) THEN
+       CALL JPL_ephemeris_init(error)
+       IF (error) THEN
+          WRITE(0,*) "JPL_ephemeris_perturbers_r8(): Could not initialize ephemerides."
+          RETURN
+       END IF
+    END IF
+
+    IF (PRESENT(km)) THEN
+       kilometres = km
+    END IF
+
+    tt2(1) = mjd_tt + 2400000.5_rprec8 ! convert to Julian date
+    tt2 = split(tt2(1))
+    IF (tt2(2) < 0.5_rprec8) THEN
+       tt2(1) = tt2(1) - 0.5_rprec8
+       tt2(2) = tt2(2) + 0.5_rprec8
+    ELSE
+       tt2(1) = tt2(1) + 0.5_rprec8
+       tt2(2) = tt2(2) - 0.5_rprec8
+    END IF
+    list = 0
+
+    ! Force barycentric output from states()
+    tmp_barycenter = barycenter
+    barycenter = .TRUE.
+
+    !  set up proper entries in 'list' array for state call
+    list(1:10) = 2
+
+    !  make call to state
+    celements(1:12,1:6) = states(tt2, list, error)
+    IF (error) THEN
+       WRITE(0,*) "JPL_ephemeris_perturbers_r8(): Error when calling states() (1)."
+       RETURN
+    END IF
+
+    ! If the target or the center is the Sun, 
+    ! change it to the Solar System barycenter:
+    celements(11,:) = celements(12,1:6)
+
+    ! If the target or the center is the Earth-Moon barycenter, 
+    ! set it initially equal to the coordinates of the Earth:
+    IF (ntargets(3) .AND. .NOT.ntargets(10)) THEN
+       celements(13,:) = celements(3,:)
+    END IF
+
+    ! If the target or the center is the Moon or the Earth-Moon barycenter, 
+    ! compute Earth coordinates using coordinates for the barycentric Earth-Moon 
+    ! system and geocentric coordinates for the Moon:
+    celements(3,:) = celements(3,:) - celements(10,:)/(1.0_rprec8 + emrat)
+
+    ! If the target or the center is the Moon, compute Moon's
+    ! coordinates using coordinates for the Earth and geocentric
+    ! coordinates for the Moon:
+    celements(10,:) = celements(3,:) + celements(10,:)
+
+    celements_ = celements(ncenter,1:6)
+    barycenter = tmp_barycenter
+    DO i=1,12
+       celements(i,1:6) = celements(i,1:6) - celements_
+    END DO
+    ALLOCATE(JPL_ephemeris_perturbers_r8(COUNT(ntargets),6), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_perturbers_r8(): Could not allocate memory."
+       RETURN
+    END IF
+    j = 0
+    DO i=1,10
+       IF (ntargets(i)) THEN
+          j = j + 1
+          JPL_ephemeris_perturbers_r8(j,1:6) = celements(i,1:6)
+       END IF
+    END DO
+
+  END FUNCTION JPL_ephemeris_perturbers_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Same as JPL_ephemeris_r8, but with digits allowing greater
+  !! numerical accuracy, i.e., the accuracy of values is the same 
+  !! as for JPL_ephemeris_r8.
+  !!
+  FUNCTION JPL_ephemeris_perturbers_r16(mjd_tt, ntargets, ncenter, error, km)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in)              :: mjd_tt
+    LOGICAL, DIMENSION(:), INTENT(in)      :: ntargets
+    INTEGER, INTENT(in)                    :: ncenter
+    LOGICAL, INTENT(inout)                 :: error
+    LOGICAL, OPTIONAL, INTENT(in)          :: km
+    REAL(rprec16), DIMENSION(:,:), POINTER :: JPL_ephemeris_perturbers_r16
+    REAL(rprec8), DIMENSION(:,:), POINTER  :: tmp
+    INTEGER :: err
+
+    IF (PRESENT(km)) THEN
+       tmp => JPL_ephemeris(REAL(mjd_tt,rprec8), ntargets, ncenter, error, km)
+    ELSE
+       tmp => JPL_ephemeris(REAL(mjd_tt,rprec8), ntargets, ncenter, error)
+    END IF
+    IF (error) THEN
+       WRITE(0,*) "JPL_ephemeris_perturbers_r16(): Error when calling JPL_ephemeris_perturbers_r8()."
+       RETURN
+    END IF
+    ALLOCATE(JPL_ephemeris_perturbers_r16(SIZE(tmp,dim=1),SIZE(tmp,dim=2)), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_perturbers_r16(): Could not allocate memory."
+       DEALLOCATE(tmp, stat=err)
+       RETURN
+    END IF
+    JPL_ephemeris_perturbers_r16 = REAL(tmp,rprec16)
+    DEALLOCATE(tmp, stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       WRITE(0,*) "JPL_ephemeris_perturbers_r16(): Could not deallocate memory."
+       RETURN
+    END IF
+
+  END FUNCTION JPL_ephemeris_perturbers_r16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Reads the jpl planetary ephemeris and gives the position and 
+  !! velocity of the point 'ntarget' with respect to 'ncenter'.
+  !!
+  !! ntarget = integer number of target point.
+  !!
+  !! ncentet = integer number of center point.
+  !!
+  !! The numbering convention for 'ntarget' and 'ncenter' is:
+  !!
+  !!<pre>
+  !!         1 = mercury           8 = neptune
+  !!         2 = venus             9 = pluto
+  !!         3 = earth            10 = moon
+  !!         4 = mars             11 = sun
+  !!         5 = jupiter          (12 = solar-system barycenter)
+  !!         6 = saturn           (13 = earth-moon barycenter)
+  !!         7 = uranus           (14 = nutations (longitude and obliq))
+  !!                              (15 = librations, if on eph file)
+  !!<pre>
+  !!
+  !! If nutations are wanted, set ntarget = 14, and for librations,
+  !! set ntarget = 15. Set ncenter = 0.
+  !!
+  !! Output is a CartesianCoordinates object (crtcrd) containing position and velocity
+  !! of point 'ntarget' relative to 'ncenter'. the units are AU and AU/day.
+  !! For librations the units are radians and radians per day. 
+  !!
+  !! Returns error.
+  !!
+  ! In the case 
+  ! of nutations the first four words of rrd will be set to nutations and 
+  ! rates, having units of radians and radians/day.
+  !!
+  FUNCTION nutations(t, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)   :: t
+    LOGICAL, INTENT(inout) :: error
+    REAL(rprec8), DIMENSION(4) :: nutations
+    REAL(rprec8), DIMENSION(6) :: tmp
+    REAL(rprec8), DIMENSION(4) :: pjd
+    REAL(rprec8), DIMENSION(2) :: tt2, tt
+    REAL(rprec8)               :: s
+    INTEGER, DIMENSION(12) :: list
+    INTEGER                :: record_nr
+
+    IF (first) THEN
+       CALL JPL_ephemeris_init(error)
+       IF (error) THEN
+          WRITE(0,*) "nutations(): Could not initialize ephemerides."
+          RETURN
+       END IF
+    END IF
+
+    tt2(1) = t
+    tt2 = split(tt2(1))
+    IF (tt2(2) < 0.5_rprec8) THEN
+       tt2(1) = tt2(1) - 0.5_rprec8
+       tt2(2) = tt2(2) + 0.5_rprec8
+    ELSE
+       tt2(1) = tt2(1) + 0.5_rprec8
+       tt2(2) = tt2(2) - 0.5_rprec8
+    END IF
+    list = 0
+
+    IF (ipt(2,12) > 0) THEN
+       list(11) = 2
+
+       IF (tt2(1) == 0.0_rprec8) THEN
+          error = .TRUE.
+          WRITE(0,*) 'nutations(): Input Julian date is zero.'
+          RETURN
+       END IF
+
+       s = tt2(1) - 0.5_rprec8
+       pjd(1:2) = split(s)
+       pjd(3:4) = split(tt2(2))
+       pjd(1) = pjd(1) + pjd(3) + 0.5_rprec8
+       pjd(2) = pjd(2) + pjd(4)
+       pjd(3:4) = split(pjd(2))
+       pjd(1) = pjd(1) + pjd(3)
+
+       IF (pjd(1) + pjd(4) < ss(1) .OR. &
+            pjd(1) + pjd(4) > ss(2)) THEN
+          error = .TRUE.
+          WRITE(0,*) 'nutations(): Requested Julian ET not within limits.'
+          RETURN
+       END IF
+
+       ! Calculate record number and relative time in interval:
+       record_nr = INT((pjd(1) - ss(1))/ss(3)) + 1
+       IF (pjd(1) == ss(2)) record_nr = record_nr - 1
+       tt(1) = ((pjd(1) - (REAL(record_nr-1, rprec8) * ss(3) + ss(1))) + &
+            pjd(4)) / ss(3)
+
+       ! Read correct record if not in core:
+       !IF (record_nr < 1 .OR. record_nr > SIZE(buf,dim=1)) THEN
+       IF (record_nr < 1 .OR. record_nr > SIZE(buf,dim=2)) THEN
+          error = .TRUE.
+          WRITE(0,*) 'Requested Julian ET not within limits.'
+          RETURN
+       END IF
+
+       ! Do nutations if requested (and if on file)
+       IF (list(11) > 0 .AND. ipt(2,12) > 0) THEN
+          !CALL interpolate(buf(record_nr,:), ipt(1,12), tt, &
+          !     ipt(2,12), 2, ipt(3,12), tmp, error)
+          CALL interpolate(buf(:,record_nr), ipt(1,12), tt, &
+               ipt(2,12), 2, ipt(3,12), tmp, error)
+          IF (error) THEN
+             RETURN
+          END IF
+          nutations = tmp(1:4)
+       ELSE
+          nutations = 0.0_rprec8
+       END IF
+       IF (error) THEN
+          WRITE(0,*) 'nutations(): No nutations on the ephemeris file.'
+          RETURN
+       END IF
+    END IF
+
+  END FUNCTION nutations
+
+
+
+
+
+  !!
+  !! Returns error.
+  !!
+  FUNCTION states(tt2, list, error)
+
+    ! this subroutine reads and interpolates the jpl planetary ephemeris file
+    ! 
+    ! calling sequence parameters:
+    ! 
+    ! input:
+    ! 
+    ! tt2   rprec8 2-word julian ephemeris epoch at which interpolation
+    ! is wanted.  any combination of tt2(1)+tt2(2) which falls
+    ! within the time span on the file is a permissible epoch.
+    ! 
+    ! a. for ease in programming, the user may put the
+    ! entire epoch in tt2(1) and set tt2(2)=0.
+    ! 
+    ! b. for maximum interpolation accuracy, set tt2(1) =
+    ! the most recent midnight at or before interpolation
+    ! epoch and set tt2(2) = fractional part of a day
+    ! elapsed between tt2(1) and epoch.
+    ! 
+    ! c. as an alternative, it may prove convenient to set
+    ! tt2(1) = some fixed epoch, such as start of integration,
+    ! and tt2(2) = elapsed interval between then and epoch.
+    ! 
+    ! list   12-word integer array specifying what interpolation
+    ! is wanted for each of the bodies on the file.
+    ! 
+    ! list(i)=0, no interpolation for body i
+    ! =1, position only
+    ! =2, position and velocity
+    ! 
+    ! the designation of the astronomical bodies by i is:
+    ! 
+    ! i =  1: mercury
+    !   =  2: venus
+    !   =  3: earth-moon barycenter
+    !   =  4: mars
+    !   =  5: jupiter
+    !   =  6: saturn
+    !   =  7: uranus
+    !   =  8: neptune
+    !   =  9: pluto
+    !   = 10: geocentric moon
+    !   = 11: nutations in longitude and obliquity
+    !   = 12: lunar librations (if on file)
+    ! 
+    ! 
+    ! output:
+    ! 
+    ! s_array   rprec8 6 x 11 array that will contain requested interpolated
+    ! quantities.  the body specified by list(i) will have its
+    ! state in the array starting at s_array(1,i).  (on any given
+    ! call, only those words in 's_array' which are affected by the
+    ! first 10 'list' entries (and by list(12) if librations are
+    ! on the file) are set.  the rest of the 's_array' array
+    ! is untouched.)  the order of components starting in
+    ! s_array(1,i) is: x,y,z,dx,dy,dz.
+    ! 
+    ! all output vectors are referenced to the earth mean
+    ! equator and equinox of j2000 if the de number is 200 or
+    ! greater; of b1950 if the de number is less than 200. 
+    ! 
+    ! the moon state is always geocentric; the other nine states 
+    ! are either heliocentric or solar-system barycentric, 
+    ! depending on the setting of common flags (see below).
+    ! 
+    ! lunar librations, if on file, are put into s_array(k,11) if
+    ! list(12) is 1 or 2.
+    ! 
+    ! nut   rprec8 4-word array that will contain nutations and rates,
+    ! depending on the setting of list(11).  the order of
+    ! quantities in nut is:
+    ! 
+    ! d psi  (nutation in longitude)
+    ! d epsilon (nutation in obliquity)
+    ! d psi dot
+    ! d epsilon dot
+    ! 
+    ! *   statement # for error return, in case of epoch out of
+    ! range or i/o errors.
+    ! 
+    ! 
+    ! common area stcomx:
+    ! 
+    ! kilometres   logical flag defining physical units of the output
+    ! states. kilometres = .true., km and km/sec
+    ! = .false., au and au/day
+    ! default value = .false.  (kilometres determines time unit
+    ! for nutations and librations.  angle unit is always radians.)
+    ! 
+    ! bary   logical flag defining output center.
+    ! only the 9 planets are affected.
+    ! bary = .true. =\ center is solar-system barycenter
+    ! = .false. =\ center is sun
+    ! default value = .false.
+    ! 
+    ! celements(1:6,12) rprec8 6-word array containing the barycentric position and
+    ! velocity of the sun.
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(2), INTENT(in) :: tt2
+    INTEGER, DIMENSION(12), INTENT(in)     :: list
+    LOGICAL, INTENT(inout)                 :: error
+    REAL(rprec8), DIMENSION(12,6)          :: states
+    REAL(rprec8), DIMENSION(2)             :: t
+    REAL(rprec8), DIMENSION(4)             :: pjd
+    REAL(rprec8)                           :: s, aufac
+    INTEGER                                :: record_nr, i
+
+    states = 0.0_rprec8
+
+    IF (ABS(tt2(1)) < EPSILON(tt2(1))) THEN
+       error = .TRUE.
+       WRITE(0,*) 'states(): Input Julian date is zero.'
+       RETURN
+    END IF
+
+    s = tt2(1) - 0.5_rprec8
+    pjd(1:2) = split(s)
+    pjd(3:4) = split(tt2(2))
+    pjd(1) = pjd(1) + pjd(3) + 0.5_rprec8
+    pjd(2) = pjd(2) + pjd(4)
+    pjd(3:4) = split(pjd(2))
+    pjd(1) = pjd(1) + pjd(3)
+
+    IF (pjd(1) + pjd(4) < ss(1) .OR. &
+         pjd(1) + pjd(4) > ss(2)) THEN
+       error = .TRUE.
+       WRITE(0,*) 'states(): Requested Julian ET not within limits:'
+       WRITE(0,*) tt2, ss
+       RETURN
+    END IF
+
+    ! Calculate record number and relative time in interval:
+    record_nr = INT((pjd(1) - ss(1))/ss(3)) + 1
+    IF (pjd(1) == ss(2)) THEN
+       record_nr = record_nr - 1
+    END IF
+    t(1) = ((pjd(1) - (REAL(record_nr-1, rprec8) * ss(3) + ss(1))) + &
+         pjd(4)) / ss(3)
+
+    ! Read correct record if not in core:
+    IF (record_nr < 1 .OR. record_nr > SIZE(buf,dim=2)) THEN
+       error = .TRUE.
+       WRITE(0,*) 'states(): Requested Julian ephemeris date not within limits.'
+       RETURN
+    END IF
+
+    IF (kilometres) THEN
+       t(2) = ss(3)*86400.0_rprec8
+       aufac = 1.0_rprec8
+    ELSE
+       t(2) = ss(3)
+       aufac = 1.0_rprec8/au
+    ENDIF
+
+    ! Interpolate ssbary sun: 
+    CALL interpolate(buf(:,record_nr), ipt(1,11), t, ipt(2,11), &
+         3, ipt(3,11), states(12,1:6), error)
+    IF (error) THEN
+       WRITE(0,*) "states(): Error when calling interpolate() (1)."
+       RETURN
+    END IF
+    states(12,1:6) = states(12,1:6)*aufac
+    ! Check and interpolate whichever bodies are requested:
+    DO i=1, 10
+       IF (list(i) == 0) CYCLE
+       CALL interpolate(buf(:,record_nr), ipt(1,i), t, ipt(2,i), &
+            3, ipt(3,i), states(i,:), error)
+       IF (error) THEN
+          WRITE(0,*) "states(): Error when calling interpolate() (2)."
+          RETURN
+       END IF
+       IF (i <= 9 .AND. .NOT.barycenter) THEN
+          states(i,:) = states(i,:) * aufac - states(12,:)
+       ELSE
+          states(i,:) = states(i,:) * aufac
+       END IF
+    END DO
+    ! Get librations if requested (and if on file)
+    IF (list(12) > 0 .AND. ipt(2,13) > 0) THEN
+       CALL interpolate(buf(:,record_nr), ipt(1,13), t, ipt(2,13), &
+            3, ipt(3,13), states(11,:), error)
+       IF (error) THEN
+          WRITE(0,*) "states(): Error when calling interpolate() (3)."
+          RETURN
+       END IF
+    ELSE
+       states(11,1) = 0.0_rprec8
+    END IF
+
+  END FUNCTION states
+
+
+
+
+
+  !!
+  !! Returns error.
+  !!
+  SUBROUTINE interpolate(inbuf, ind, time, ncf, ncm, na, svector, error)
+
+    ! this subroutine differentiates and interpolates a
+    ! set of chebyshev coefficients to give position and velocity
+    ! 
+    ! calling sequence parameters:
+    ! 
+    ! input:
+    ! 
+    ! buf   1st location of array of d.p. chebyshev coefficients of position
+    ! 
+    ! t   t(1) is rprec8 fractional time in interval covered by
+    ! coefficients at which interpolation is wanted
+    ! (0 <= t(1) <= 1).  t(2) is rprec8 length of whole
+    ! interval in input time units.
+    ! 
+    ! ncf   # of coefficients per component
+    ! 
+    ! ncm   # of components per set of coefficients
+    ! 
+    ! na   # of sets of coefficients in full array
+    ! (i.e., # of sub-intervals in full interval)
+    ! 
+    ! flag  integer flag: =1 for positions only
+    ! =2 for pos and vel
+    ! 
+    ! 
+    ! output:
+    ! 
+    ! svector   interpolated quantities requested.  dimension
+    ! expected is svector(ncm,flag), rprec8.
+    !
+    IMPLICIT NONE
+    INTEGER, INTENT(in)                 :: ncf, ncm, na, ind
+    SAVE
+    REAL(rprec8), DIMENSION(:), INTENT(in)  :: inbuf
+    REAL(rprec8), DIMENSION(2), INTENT(in)  :: time
+    REAL(rprec8), DIMENSION(6), INTENT(out) :: svector
+    LOGICAL, INTENT(inout)              :: error
+    REAL(rprec8), DIMENSION(ncf,ncm,na)     :: buf
+    REAL(rprec8), DIMENSION(18)             :: pc, vc
+    REAL(rprec8), DIMENSION(6)              :: pos, vel
+    REAL(rprec8)                            :: twot, tmp, tc, vfac, dna
+    INTEGER                             :: npos, nvel, dt1, i, j, k, l
+
+    npos = 2
+    nvel = 3
+    twot = 0.0_rprec8
+    pc(1:2) = (/ 1.0_rprec8, 0.0_rprec8 /)
+    vc(2) = 1.0_rprec8
+
+    l = ind
+    buf = 0.0
+    DO k=1,na 
+       DO j=1,ncm
+          DO i=1,ncf
+             buf(i,j,k) = inbuf(l)
+             l = l + 1
+          END DO
+       END DO
+    END DO
+
+    ! Get correct sub-interval number for this set of coefficients and
+    ! then get normalized Chebyshev time within that subinterval.
+    dna = REAL(na,rprec8)
+    dt1 = INT(time(1))
+    tmp = dna * time(1)
+    l = INT(tmp - dt1) + 1
+
+    ! tc is the normalized chebyshev time (-1 <= tc <= 1)
+    tc = 2.0_rprec8 * (MOD(tmp,1.0_rprec8) + dt1) - 1.0_rprec8
+
+    ! check to see whether chebyshev time has changed,
+    ! and compute new polynomial values if it has.
+    ! (the element pc(2) is the value of t1(tc) and hence
+    ! contains the value of tc on the previous call.)
+    IF(tc /= pc(2)) THEN
+       npos = 2
+       nvel = 3
+       pc(2) = tc
+       twot = tc + tc
+    END IF
+
+    ! be sure that at least 'ncf' polynomials have been evaluated
+    ! and are stored in the array 'pc'.
+    IF(npos < ncf) THEN
+       DO i=npos+1,ncf
+          pc(i) = twot * pc(i-1) - pc(i-2)
+       END DO
+       npos = ncf
+    END IF
+
+    ! interpolate to get position for each component
+    DO i=1,ncm
+       pos(i) = 0.0_rprec8
+       DO j=ncf,1,-1
+          pos(i) = pos(i) + pc(j) * buf(j,i,l)
+       END DO
+    END DO
+
+    ! if velocity interpolation is wanted, be sure enough
+    ! derivative polynomials have been generated and stored.
+    IF (ABS(time(2)) < EPSILON(time(2))) THEN
+       error = .TRUE.
+       WRITE(0,*) 'interpolate(): Attempted division by zero.'
+       RETURN
+    END IF
+    vfac = (dna + dna)/time(2)
+    vc(3) = twot + twot
+    IF (nvel < ncf) THEN
+       DO i=nvel+1, ncf
+          vc(i) = twot * vc(i-1) + pc(i-1) + pc(i-1) - vc(i-2)
+       END DO
+       nvel = ncf
+    ENDIF
+
+    ! interpolate to get velocity for each component
+    DO i=1, ncm
+       vel(i) = 0.0_rprec8
+       DO j=ncf,2,-1
+          vel(i) = vel(i) + vc(j) * buf(j,i,l)
+       END DO
+       vel(i) = vel(i) * vfac
+    END DO
+
+    svector = (/ pos(1:3), vel(1:3) /)
+
+  END SUBROUTINE interpolate
+
+
+
+
+
+  !!
+  !!
+  FUNCTION split(in)
+
+    ! this subroutine breaks a rprec8 number into a rprec8 integer
+    ! and a rprec8 fractional part.
+    !
+    ! calling sequence parameters:
+    !
+    !   in = input number
+    !
+    !   out = output array.
+    !        split(1) contains integer part
+    !        split(2) contains fractional part
+    !
+    !        for negative input numbers, split(1) contains the next
+    !        more negative integer; split(2) contains a positive fraction.
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)   :: in
+    REAL(rprec8), DIMENSION(2) :: split
+
+    !  main entry -- get integer and fractional parts
+    split(1) = 1.0_rprec8*AINT(in)
+    split(2) = 1.0_rprec8*in - 1.0_rprec8*split(1)
+
+    IF (in < 0.0_rprec8 .AND. split(2) /= 0.0_rprec8) THEN
+       !  make adjustments for negative input number
+       split(1) = 1.0_rprec8*split(1) - 1.0_rprec8
+       split(2) = 1.0_rprec8*split(2) + 1.0_rprec8
+    END IF
+
+  END FUNCTION split
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The Roche limit 'd' for a fluid satellite where 
+  !!
+  !!    d ~ 2.44 * r_planet * (rho_planet/rho_satellite)^(1/3))
+  !!
+  !! and r_planet and rho_planet are the radius and bulk density of
+  !! the planet, and rho_satellite is the bulk density of the
+  !! satellite.
+  !!
+  REAL(rprec8) FUNCTION Roche_limit(radius_1, density_1, density_2)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in) :: radius_1, density_1, density_2
+
+    Roche_limit =  2.44_rprec8 * radius_1 * (density_1/density_2)**(1.0_rprec8/3)
+
+  END FUNCTION Roche_limit
+
+
+
+
+END MODULE planetary_data
Index: trunk/mops/oorb/modules/random.f90
===================================================================
--- trunk/mops/oorb/modules/random.f90	(revision 34646)
+++ trunk/mops/oorb/modules/random.f90	(revision 34646)
@@ -0,0 +1,593 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002-2011,2012                                           !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*: 
+!!  
+!! Random number generators. 
+!!
+!! @see SphericalCoordinates_class 
+!!  
+!! @author  MG
+!! @version 2012-02-15
+!!
+MODULE random
+
+  USE parameters
+  IMPLICIT NONE
+  PRIVATE
+  INTEGER, PARAMETER :: IA=16807, IM=2147483647, IQ=127773, IR=2836
+  INTEGER, DIMENSION(:), ALLOCATABLE :: seed 
+  INTEGER :: idum_prm = -1
+  INTEGER :: idum
+  LOGICAL :: first_ran = .TRUE.
+
+  PUBLIC :: initializeRandomNumberGenerator
+  PUBLIC :: randomNumber
+  PUBLIC :: randomGaussian
+
+  INTERFACE ran_pmm
+     MODULE PROCEDURE ran_pmm_r4
+     MODULE PROCEDURE ran_pmm_r8
+     MODULE PROCEDURE ran_pmm_r16
+  END INTERFACE ran_pmm
+
+  INTERFACE randomNumber
+     MODULE PROCEDURE randomNumber_single_r4
+     MODULE PROCEDURE randomNumber_single_r8
+     MODULE PROCEDURE randomNumber_single_r16
+     MODULE PROCEDURE randomNumber_array_r4
+     MODULE PROCEDURE randomNumber_2array_r4
+     MODULE PROCEDURE randomNumber_array_r8
+     MODULE PROCEDURE randomNumber_2array_r8
+     MODULE PROCEDURE randomNumber_array_r16
+  END INTERFACE randomNumber
+
+  INTERFACE randomGaussian
+     MODULE PROCEDURE randomGaussian_single_r4
+     MODULE PROCEDURE randomGaussian_single_r8
+     MODULE PROCEDURE randomGaussian_single_r16
+     MODULE PROCEDURE randomGaussian_array_r4
+     MODULE PROCEDURE randomGaussian_array_r8
+     MODULE PROCEDURE randomGaussian_array_r16
+  END INTERFACE randomGaussian
+
+
+CONTAINS
+
+
+
+  SUBROUTINE initializeRandomNumberGenerator(idum)
+
+    IMPLICIT NONE
+    INTEGER, INTENT(in) :: idum
+
+    idum_prm = idum
+
+  END SUBROUTINE initializeRandomNumberGenerator
+
+
+
+
+
+!!$  subroutine devroyeRandomMultinormalValues(covariance, ran)
+!!$
+!!$    implicit none
+!!$    real(prec8), dimension(:,:), intent(in) 
+!!$
+!!$    ! From Devroye: "Non-Uniform Random Variate Generation", 1986,
+!!$    ! chapter 11
+!!$
+!!$    A = 0.0_bp
+!!$    DO i=1,6
+!!$       DO j=1,i
+!!$          IF (j == 1) THEN
+!!$             A(i,1) = cov(i,1)/SQRT(cov(1,1))
+!!$          ELSE IF (i == j) THEN
+!!$             IF (cov(i,i) - SUM(A(i,1:i-1)**2) < -1E-7_bp) THEN
+!!$                CALL toString(i, str1, error)
+!!$                CALL toString(cov(i,i) - SUM(A(i,1:i-1)**2), str2, error, frmt=efrmt)
+!!$                error = .TRUE.
+!!$                CALL errorMessage("StochasticOrbit / covarianceSampling", &
+!!$                     "Square of element (" // TRIM(str1) // "," // TRIM(str1) // &
+!!$                     ") of Devroye's matrix A is negative (" // TRIM(str2) // ").", 1)
+!!$                RETURN
+!!$             END IF
+!!$             A(i,i) = SQRT(ABS(cov(i,i) - SUM(A(i,1:i-1)**2)))
+!!$          ELSE IF (j < i) THEN
+!!$             A(i,j) = (cov(i,j) - SUM(A(i,1:j-1)*A(j,1:j-1)))/A(j,j)
+!!$          END IF
+!!$       END DO
+!!$    END DO
+
+
+
+
+
+  !! Minimal random number generator of Park and Miller combined with a
+  !! Marsaglia shift sequence. Returns a uniform random deviate between
+  !! 0.0 and 1.0 (exclusive of the endpoint values). This fully portable,
+  !! scalar generator has the traditional (not Fortran 90)
+  !! calling sequence with a random deviate as the returned function value:
+  !! call with idum a negative integer to initialize; thereafter, do not
+  !! alter idum except to reinitialize. The period of this generator is
+  !! about 3.1 × 10^18.
+  !!
+  SUBROUTINE ran_pmm_r4(idum, ran)
+
+    IMPLICIT NONE 
+    INTEGER, INTENT(inout) :: idum 
+    REAL(rprec4), INTENT(out) :: ran
+    REAL(rprec4), SAVE :: am
+    INTEGER, SAVE :: ix=-1, iy=-1, k
+
+    IF (idum <= 0 .OR. iy < 0) THEN 
+       ! Initialize.
+       am=NEAREST(1.0_rprec4,-1.0_rprec4)/IM
+       iy=IOR(IEOR(888889999,ABS(idum)),1)
+       ix=IEOR(777755555,ABS(idum))
+       ! Set idum positive.
+       idum=ABS(idum)+1
+    END IF
+
+    ! Marsaglia shift sequence with period 2^32 - 1.
+    ix=IEOR(ix,ISHFT(ix,13))
+    ix=IEOR(ix,ISHFT(ix,-17))
+    ix=IEOR(ix,ISHFT(ix,5))
+
+    ! Park-Miller sequence by Schrage's method, period 2^31 - 2
+    k=iy/IQ
+    iy=IA*(iy-k*IQ)-IR*k
+    IF (iy < 0) THEN
+       iy=iy+IM
+    END IF
+
+    !Combine the two generators with masking to ensure nonzero value
+    ran = am*IOR(IAND(IM,IEOR(ix,iy)),1)
+
+  END SUBROUTINE ran_pmm_r4
+
+
+
+
+
+  !! Minimal random number generator of Park and Miller combined with a
+  !! Marsaglia shift sequence. Returns a uniform random deviate between
+  !! 0.0 and 1.0 (exclusive of the endpoint values). This fully portable,
+  !! scalar generator has the traditional (not Fortran 90)
+  !! calling sequence with a random deviate as the returned function value:
+  !! call with idum a negative integer to initialize; thereafter, do not
+  !! alter idum except to reinitialize. The period of this generator is
+  !! about 3.1 × 10^18.
+  !!
+  SUBROUTINE ran_pmm_r8(idum, ran)
+
+    IMPLICIT NONE 
+    INTEGER, INTENT(inout) :: idum 
+    REAL(rprec8), INTENT(out) :: ran
+    REAL(rprec8), SAVE :: am
+    INTEGER, SAVE :: ix=-1, iy=-1, k
+
+    IF (idum <= 0 .OR. iy < 0) THEN 
+       ! Initialize.
+       am=NEAREST(1.0_rprec8,-1.0_rprec8)/IM
+       iy=IOR(IEOR(888889999,ABS(idum)),1)
+       ix=IEOR(777755555,ABS(idum))
+       ! Set idum positive.
+       idum=ABS(idum)+1
+    END IF
+
+    ! Marsaglia shift sequence with period 2^32 - 1.
+    ix=IEOR(ix,ISHFT(ix,13))
+    ix=IEOR(ix,ISHFT(ix,-17))
+    ix=IEOR(ix,ISHFT(ix,5))
+
+    ! Park-Miller sequence by Schrage's method, period 2^31 - 2
+    k=iy/IQ
+    iy=IA*(iy-k*IQ)-IR*k
+    IF (iy < 0) THEN
+       iy=iy+IM
+    END IF
+
+    !Combine the two generators with masking to ensure nonzero value
+    ran = am*IOR(IAND(IM,IEOR(ix,iy)),1)
+
+  END SUBROUTINE ran_pmm_r8
+
+
+
+
+  !! Minimal random number generator of Park and Miller combined with a
+  !! Marsaglia shift sequence. Returns a uniform random deviate between
+  !! 0.0 and 1.0 (exclusive of the endpoint values). This fully portable,
+  !! scalar generator has the traditional (not Fortran 90)
+  !! calling sequence with a random deviate as the returned function value:
+  !! call with idum a negative integer to initialize; thereafter, do not
+  !! alter idum except to reinitialize. The period of this generator is
+  !! about 3.1 × 10^18.
+  !!
+  SUBROUTINE ran_pmm_r16(idum, ran)
+
+    IMPLICIT NONE 
+    INTEGER, INTENT(inout) :: idum 
+    REAL(rprec16), INTENT(out) :: ran
+    REAL(rprec16), SAVE :: am
+    INTEGER, SAVE :: ix=-1, iy=-1, k
+
+    IF (idum <= 0 .OR. iy < 0) THEN 
+       ! Initialize.
+       am=NEAREST(1.0_rprec16,-1.0_rprec16)/IM
+       iy=IOR(IEOR(888889999,ABS(idum)),1)
+       ix=IEOR(777755555,ABS(idum))
+       ! Set idum positive.
+       idum=ABS(idum)+1
+    END IF
+
+    ! Marsaglia shift sequence with period 2^32 - 1.
+    ix=IEOR(ix,ISHFT(ix,13))
+    ix=IEOR(ix,ISHFT(ix,-17))
+    ix=IEOR(ix,ISHFT(ix,5))
+
+    ! Park-Miller sequence by Schrage's method, period 2^31 - 2
+    k=iy/IQ
+    iy=IA*(iy-k*IQ)-IR*k
+    IF (iy < 0) THEN
+       iy=iy+IM
+    END IF
+
+    !Combine the two generators with masking to ensure nonzero value
+    ran = am*IOR(IAND(IM,IEOR(ix,iy)),1)
+
+  END SUBROUTINE ran_pmm_r16
+
+
+
+
+
+  SUBROUTINE randomNumber_single_r4(ran)
+
+    IMPLICIT NONE
+    REAL(rprec4), INTENT(out) :: ran
+
+    IF (first_ran) THEN
+       idum = idum_prm
+       first_ran = .FALSE.
+    END IF
+    CALL ran_pmm(idum, ran)
+
+  END SUBROUTINE randomNumber_single_r4
+
+
+
+
+
+  SUBROUTINE randomNumber_single_r8(ran)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(out) :: ran
+
+    IF (first_ran) THEN
+       idum = idum_prm
+       first_ran = .FALSE.
+    END IF
+    CALL ran_pmm(idum, ran)
+
+  END SUBROUTINE randomNumber_single_r8
+
+
+
+
+
+  SUBROUTINE randomNumber_single_r16(ran)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(out) :: ran
+
+    IF (first_ran) THEN
+       idum = idum_prm
+       first_ran = .FALSE.
+    END IF
+    CALL ran_pmm(idum, ran)
+
+  END SUBROUTINE randomNumber_single_r16
+
+
+
+
+
+  SUBROUTINE randomNumber_array_r4(ran)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), INTENT(out) :: ran
+    INTEGER :: i
+
+    DO i=1,SIZE(ran)
+       CALL randomNumber(ran(i))
+    END DO
+
+  END SUBROUTINE randomNumber_array_r4
+
+
+
+
+
+  SUBROUTINE randomNumber_2array_r4(ran)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:,:), INTENT(out) :: ran
+    INTEGER :: i, j
+
+    DO i=1,SIZE(ran,dim=1)
+       DO j=1,SIZE(ran,dim=2)
+          CALL randomNumber(ran(i,j))
+       END DO
+    END DO
+
+  END SUBROUTINE randomNumber_2array_r4
+
+
+
+
+
+  SUBROUTINE randomNumber_array_r8(ran)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(out) :: ran
+    INTEGER :: i
+
+    DO i=1,SIZE(ran)
+       CALL randomNumber(ran(i))
+    END DO
+
+  END SUBROUTINE randomNumber_array_r8
+
+
+
+
+
+  SUBROUTINE randomNumber_2array_r8(ran)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(out) :: ran
+    INTEGER :: i, j
+
+    DO i=1,SIZE(ran,dim=1)
+       DO j=1,SIZE(ran,dim=2)
+          CALL randomNumber(ran(i,j))
+       END DO
+    END DO
+
+  END SUBROUTINE randomNumber_2array_r8
+
+
+
+
+
+  SUBROUTINE randomNumber_array_r16(ran)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(out) :: ran
+    INTEGER :: i
+
+    DO i=1,SIZE(ran)
+       CALL randomNumber(ran(i))
+    END DO
+
+  END SUBROUTINE randomNumber_array_r16
+
+
+
+
+
+  SUBROUTINE randomGaussian_single_r4(rangauss)
+
+    IMPLICIT NONE
+    INTEGER, PARAMETER :: nran = 12
+    REAL(rprec4), INTENT(out) :: rangauss
+    REAL(rprec4), DIMENSION(nran) :: ran
+    REAL(rprec4) :: x1, sum 
+    REAL(rprec4), SAVE :: x2, sln
+    LOGICAL, SAVE :: second = .FALSE.
+
+    IF (second) THEN
+       ! Use the second random number generated on last call:
+       rangauss = x2*sln
+       second = .FALSE.
+    ELSE
+       ! Generate a pair of random normals:
+       second = .TRUE.
+       sum = HUGE(sum)
+       DO WHILE (sum >= 1.0_rprec4)
+          CALL randomNumber(ran)
+          x1 = 2.0_rprec4 * ran(1) - 1.0_rprec4
+          ! Because congruential algorithms do not strictly speaking
+          ! produce independent random numbers, more randomness has
+          ! been created by not taking the two first numbers, but the
+          ! first and one of the numbers coming after the two first
+          ! numbers.
+          x2 = 2.0_rprec4 * ran(2+CEILING((nran-2)*ran(2))) - 1.0_rprec4
+          ! Tiny added to prevent LOG(zero)/zero:
+          sum = x1**2.0_rprec4 + x2**2.0_rprec4 + TINY(sum)
+       END DO
+       sln = SQRT((-2.0_rprec4*LOG(sum))/sum)
+       rangauss = x1 * sln
+    END IF
+
+  END SUBROUTINE randomGaussian_single_r4
+
+
+
+
+
+  SUBROUTINE randomGaussian_single_r8(rangauss)
+
+    IMPLICIT NONE
+    INTEGER, PARAMETER :: nran = 12
+    REAL(rprec8), INTENT(out) :: rangauss
+    REAL(rprec8), DIMENSION(nran) :: ran
+    REAL(rprec8) :: x1, sum 
+    REAL(rprec8), SAVE :: x2, sln
+    LOGICAL, SAVE :: second = .FALSE.
+
+    IF (second) THEN
+       ! Use the second random number generated on last call:
+       rangauss = x2*sln
+       second = .FALSE.
+    ELSE
+       ! Generate a pair of random normals:
+       second = .TRUE.
+       sum = HUGE(sum)
+       DO WHILE (sum >= 1.0_rprec8)
+          CALL randomNumber(ran)
+          x1 = 2.0_rprec8 * ran(1) - 1.0_rprec8
+          ! Because congruential algorithms do not strictly speaking
+          ! produce independent random numbers, more randomness has
+          ! been created by not taking the two first numbers, but the
+          ! first and one of the numbers coming after the two first
+          ! numbers.
+          x2 = 2.0_rprec8 * ran(2+CEILING((nran-2)*ran(2))) - 1.0_rprec8
+          ! Tiny added to prevent LOG(zero)/zero:
+          sum = x1**2.0_rprec8 + x2**2.0_rprec8 + TINY(sum)
+       END DO
+       sln = SQRT((-2.0_rprec8*LOG(sum))/sum)
+       rangauss = x1 * sln
+    END IF
+
+  END SUBROUTINE randomGaussian_single_r8
+
+
+
+
+
+  SUBROUTINE randomGaussian_single_r16(rangauss)
+
+    IMPLICIT NONE
+    INTEGER, PARAMETER :: nran = 12
+    REAL(rprec16), INTENT(out) :: rangauss
+    REAL(rprec16), DIMENSION(nran) :: ran
+    REAL(rprec16) :: x1, sum 
+    REAL(rprec16), SAVE :: x2, sln
+    LOGICAL, SAVE :: second = .FALSE.
+
+    IF (second) THEN
+       ! Use the second random number generated on last call:
+       rangauss = x2*sln
+       second = .FALSE.
+    ELSE
+       ! Generate a pair of random normals:
+       second = .TRUE.
+       sum = HUGE(sum)
+       DO WHILE (sum >= 1.0_rprec16)
+          CALL randomNumber(ran)
+          x1 = 2.0_rprec16 * ran(1) - 1.0_rprec16
+          ! Because congruential algorithms do not strictly speaking
+          ! produce independent random numbers, more randomness has
+          ! been created by not taking the two first numbers, but the
+          ! first and one of the numbers coming after the two first
+          ! numbers.
+          x2 = 2.0_rprec16 * ran(2+CEILING((nran-2)*ran(2))) - 1.0_rprec16
+          ! Tiny added to prevent LOG(zero)/zero:
+          sum = x1**2.0_rprec16 + x2**2.0_rprec16 + TINY(sum)
+       END DO
+       sln = SQRT((-2.0_rprec16*LOG(sum))/sum)
+       rangauss = x1 * sln
+    END IF
+
+  END SUBROUTINE randomGaussian_single_r16
+
+
+
+
+
+  SUBROUTINE randomGaussian_array_r4(rangauss)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), INTENT(out) :: rangauss 
+    INTEGER :: i
+
+    DO i=1,SIZE(rangauss)
+       CALL randomGaussian(rangauss(i))
+    END DO
+
+  END SUBROUTINE randomGaussian_array_r4
+
+
+
+
+
+  SUBROUTINE randomGaussian_array_r8(rangauss)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(out) :: rangauss 
+    INTEGER :: i
+
+    DO i=1,SIZE(rangauss)
+       CALL randomGaussian(rangauss(i))
+    END DO
+
+  END SUBROUTINE randomGaussian_array_r8
+
+
+
+
+
+  SUBROUTINE randomGaussian_array_r16(rangauss)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(out) :: rangauss 
+    INTEGER :: i
+
+    DO i=1,SIZE(rangauss)
+       CALL randomGaussian(rangauss(i))
+    END DO
+
+  END SUBROUTINE randomGaussian_array_r16
+
+
+
+
+
+  SUBROUTINE setRandomSeed(seed)
+
+    IMPLICIT NONE
+    INTEGER, OPTIONAL, INTENT(in) :: seed
+    INTEGER, DIMENSION(8) :: dt 
+    INTEGER, DIMENSION(1) :: seed_array
+    INTEGER :: k
+
+    CALL RANDOM_SEED(size=k)
+    IF (PRESENT(seed)) THEN
+       seed_array = seed
+       CALL RANDOM_SEED(put=seed_array(1:k))
+    ELSE
+       CALL DATE_AND_TIME(values=dt)
+       seed_array = dt(8)
+       CALL RANDOM_SEED(put=seed_array(1:k))
+    END IF
+
+  END SUBROUTINE setRandomSeed
+
+
+
+
+
+END MODULE random
Index: trunk/mops/oorb/modules/sort.f90
===================================================================
--- trunk/mops/oorb/modules/sort.f90	(revision 34646)
+++ trunk/mops/oorb/modules/sort.f90	(revision 34646)
@@ -0,0 +1,1416 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010             !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Contains sorting and searching routines.
+!!
+!! @author  MG
+!! @version 2010-03-02
+!!
+MODULE sort
+
+  USE parameters
+  USE utilities
+
+  IMPLICIT NONE
+  INTEGER, PARAMETER :: NN = 15, NSTACK = 100
+
+  INTERFACE insertionSort
+     MODULE PROCEDURE insertionSort_i8
+     MODULE PROCEDURE insertionSort_r16
+     MODULE PROCEDURE insertionSort_ch
+  END INTERFACE
+
+  INTERFACE quickSort
+     MODULE PROCEDURE quickSort_i4
+     MODULE PROCEDURE quickSort_i4_index
+     MODULE PROCEDURE quickSort_i8
+     MODULE PROCEDURE quickSort_i8_index
+     MODULE PROCEDURE quickSort_r8
+     MODULE PROCEDURE quickSort_r8_index
+     MODULE PROCEDURE quickSort_r16
+     MODULE PROCEDURE quickSort_ch
+     MODULE PROCEDURE quickSort_ch_index
+  END INTERFACE
+
+  INTERFACE binarySearch
+     MODULE PROCEDURE binarySearch_i8
+     MODULE PROCEDURE binarySearch_r8
+     MODULE PROCEDURE binarySearch_r16
+     MODULE PROCEDURE binarySearch_ch
+     MODULE PROCEDURE binarySearch_ch_index
+  END INTERFACE
+
+  INTERFACE findLocation
+     MODULE PROCEDURE findLocation_r8
+     MODULE PROCEDURE findLocation_r8_indx
+     MODULE PROCEDURE findLocation_r16
+  END INTERFACE
+
+
+
+
+
+CONTAINS
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The insertion sort technique is the same as the one used for
+  !! sorting cards: Pick out the second card and put it in order with
+  !! the first card. Then pick out the third card and put it into the
+  !! sequence among the first two. Continue until the last card has
+  !! been picked out and inserted. In a random situation the algorithm
+  !! scales as N**2, but assuming an almost sorted array it can even
+  !! reach N.  Generally, the insertion sort should not be used
+  !! for N >= 100. This implementation is an in-place sort.
+  !!
+  SUBROUTINE insertionSort_i8(array)
+
+    IMPLICIT NONE
+    INTEGER(iprec8), DIMENSION(:), INTENT(inout) :: array
+    INTEGER(iprec8)                              :: element
+    INTEGER                                      :: i, j
+
+    DO i=2, SIZE(array)
+       element = array(i)
+       j = i
+       DO WHILE (j > 1)
+          IF (array(j-1) <= element) THEN
+             EXIT
+          END IF
+          array(j) = array(j-1)
+          j = j - 1
+       END DO
+       array(j) = element
+    END DO
+
+  END SUBROUTINE insertionSort_i8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The insertion sort technique is the same as the one used for
+  !! sorting cards: Pick out the second card and put it in order with
+  !! the first card. Then pick out the third card and put it into the
+  !! sequence among the first two. Continue until the last card has
+  !! been picked out and inserted. In a random situation the algorithm
+  !! scales as N**2, but assuming an almost sorted array it can even
+  !! reach N.  Generally, the insertion sort should not be used
+  !! for N >= 100. This implementation is an in-place sort.
+  !!
+  SUBROUTINE insertionSort_ch(array)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=LEN(array(1)))                  :: element
+    INTEGER                                       :: i, j
+
+    DO i=2,SIZE(array)
+       element = array(i)
+       j = i
+       DO WHILE (j > 1)
+          IF (array(j-1) <= element) THEN
+             EXIT
+          END IF
+          array(j) = array(j-1)
+          j = j - 1
+       END DO
+       array(j) = element
+    END DO
+
+  END SUBROUTINE insertionSort_ch
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! The insertion sort technique is the same as the one used for
+  !! sorting cards: Pick out the second card and put it in order with
+  !! the first card. Then pick out the third card and put it into the
+  !! sequence among the first two. Continue until the last card has
+  !! been picked out and inserted. In a random situation the algorithm
+  !! scales as N**2, but assuming an almost sorted array it can even
+  !! reach N.  Generally, the insertion sort should not be used
+  !! for N >= 100. This implementation is an in-place sort.
+  !!
+  SUBROUTINE insertionSort_r16(array)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(inout) :: array
+    REAL(rprec16)                              :: element
+    INTEGER                                    :: i, j
+
+    DO i=2, SIZE(array)
+       element = array(i)
+       j = i
+       DO WHILE (j > 1)
+          IF (array(j-1) <= element) THEN
+             EXIT
+          END IF
+          array(j) = array(j-1)
+          j = j - 1
+       END DO
+       array(j) = element
+    END DO
+
+  END SUBROUTINE insertionSort_r16
+
+
+
+
+
+  SUBROUTINE quickSort_i4(array, error)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER(iprec4) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(i)
+             DO j=i-1,left,-1
+                IF (array(j) <= element) EXIT
+                array(j+1) = array(j)
+             END DO
+             array(j+1) = element
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(array(center),array(left+1))
+          CALL swap(array(left),array(right),array(left)>array(right))
+          CALL swap(array(left+1),array(right),array(left+1)>array(right))
+          CALL swap(array(left),array(left+1),array(left)>array(left+1))
+          i = left + 1
+          j = right
+          element = array(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(i) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(j) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(array(i), array(j))
+          END DO
+          array(left+1) = array(j)
+          array(j)      = element
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_i4
+
+
+
+
+
+  SUBROUTINE quickSort_i4_index(array, ind, error)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(SIZE(array)), INTENT(out) :: ind
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER(iprec4) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack, tmp
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+    DO i=1,SIZE(ind)
+       ind(i) = i
+    END DO
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(ind(i))
+             tmp = ind(i)
+             DO j=i-1,left,-1
+                IF (array(ind(j)) <= element) THEN
+                   EXIT
+                END IF
+                ind(j+1) = ind(j)
+             END DO
+             ind(j+1) = tmp
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(ind(center),ind(left+1))
+          CALL swap(ind(left),ind(right),array(ind(left))>array(ind(right)))
+          CALL swap(ind(left+1),ind(right),array(ind(left+1))>array(ind(right)))
+          CALL swap(ind(left),ind(left+1),array(ind(left))>array(ind(left+1)))
+          i = left + 1
+          j = right
+          element = array(ind(left+1))
+          tmp = ind(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(ind(i)) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(ind(j)) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(ind(i), ind(j))
+          END DO
+          ind(left+1) = ind(j)
+          ind(j)      = tmp
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_i4_index
+
+
+
+
+
+  SUBROUTINE quickSort_i8(array, error)
+
+    IMPLICIT NONE
+    INTEGER(rprec8), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER(rprec8) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(i)
+             DO j=i-1,left,-1
+                IF (array(j) <= element) EXIT
+                array(j+1) = array(j)
+             END DO
+             array(j+1) = element
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(array(center), array(left+1))
+          CALL swap(array(left),   array(right),  array(left)   > array(right))
+          CALL swap(array(left+1), array(right),  array(left+1) > array(right))
+          CALL swap(array(left),   array(left+1), array(left)   > array(left+1))
+          i = left + 1
+          j = right
+          element = array(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(i) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(j) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(array(i), array(j))
+          END DO
+          array(left+1) = array(j)
+          array(j)      = element
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_i8
+
+
+
+
+
+  SUBROUTINE quickSort_i8_index(array, ind, error)
+
+    IMPLICIT NONE
+    INTEGER(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(SIZE(array)), INTENT(out) :: ind
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER(rprec8) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack, tmp
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+    DO i=1,SIZE(ind)
+       ind(i) = i
+    END DO
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(ind(i))
+             tmp = ind(i)
+             DO j=i-1,left,-1
+                IF (array(ind(j)) <= element) THEN
+                   EXIT
+                END IF
+                ind(j+1) = ind(j)
+             END DO
+             ind(j+1) = tmp
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(ind(center),ind(left+1))
+          CALL swap(ind(left),ind(right),array(ind(left))>array(ind(right)))
+          CALL swap(ind(left+1),ind(right),array(ind(left+1))>array(ind(right)))
+          CALL swap(ind(left),ind(left+1),array(ind(left))>array(ind(left+1)))
+          i = left + 1
+          j = right
+          element = array(ind(left+1))
+          tmp = ind(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(ind(i)) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(ind(j)) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(ind(i), ind(j))
+          END DO
+          ind(left+1) = ind(j)
+          ind(j)      = tmp
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_i8_index
+
+
+
+
+
+  SUBROUTINE quickSort_r8(array, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    REAL(rprec8) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(i)
+             DO j=i-1,left,-1
+                IF (array(j) <= element) EXIT
+                array(j+1) = array(j)
+             END DO
+             array(j+1) = element
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(array(center),array(left+1))
+          CALL swap(array(left),array(right),array(left)>array(right))
+          CALL swap(array(left+1),array(right),array(left+1)>array(right))
+          CALL swap(array(left),array(left+1),array(left)>array(left+1))
+          i = left + 1
+          j = right
+          element = array(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(i) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(j) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(array(i), array(j))
+          END DO
+          array(left+1) = array(j)
+          array(j)      = element
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_r8
+
+
+
+
+
+  SUBROUTINE quickSort_r8_index(array, ind, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(SIZE(array)), INTENT(out) :: ind
+    CHARACTER(len=*), INTENT(inout) :: error
+    REAL(rprec8) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack, tmp
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+    DO i=1,SIZE(ind)
+       ind(i) = i
+    END DO
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(ind(i))
+             tmp = ind(i)
+             DO j=i-1,left,-1
+                IF (array(ind(j)) <= element) THEN
+                   EXIT
+                END IF
+                ind(j+1) = ind(j)
+             END DO
+             ind(j+1) = tmp
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(ind(center),ind(left+1))
+          CALL swap(ind(left),ind(right),array(ind(left))>array(ind(right)))
+          CALL swap(ind(left+1),ind(right),array(ind(left+1))>array(ind(right)))
+          CALL swap(ind(left),ind(left+1),array(ind(left))>array(ind(left+1)))
+          i = left + 1
+          j = right
+          element = array(ind(left+1))
+          tmp = ind(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(ind(i)) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(ind(j)) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(ind(i), ind(j))
+          END DO
+          ind(left+1) = ind(j)
+          ind(j)      = tmp
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_r8_index
+
+
+
+
+
+  SUBROUTINE quickSort_r16(array, error)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    REAL(rprec16) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(i)
+             DO j=i-1,left,-1
+                IF (array(j) <= element) EXIT
+                array(j+1) = array(j)
+             END DO
+             array(j+1) = element
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(array(center),array(left+1))
+          CALL swap(array(left),array(right),array(left)>array(right))
+          CALL swap(array(left+1),array(right),array(left+1)>array(right))
+          CALL swap(array(left),array(left+1),array(left)>array(left+1))
+          i = left + 1
+          j = right
+          element = array(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(i) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(j) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(array(i), array(j))
+          END DO
+          array(left+1) = array(j)
+          array(j)      = element
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_r16
+
+
+
+
+
+  SUBROUTINE quickSort_ch(array, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), DIMENSION(:), INTENT(inout) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    CHARACTER(len=LEN(array(1))) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack
+
+    n = SIZE(array,dim=1)
+    istack = 0
+    left  = 1
+    right = n
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(i)
+             DO j=i-1,left,-1
+                IF (array(j) <= element) EXIT
+                array(j+1) = array(j)
+             END DO
+             array(j+1) = element
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(array(center),array(left+1))
+          CALL swap(array(left),array(right),array(left)>array(right))
+          CALL swap(array(left+1),array(right),array(left+1)>array(right))
+          CALL swap(array(left),array(left+1),array(left)>array(left+1))
+          i = left + 1
+          j = right
+          element = array(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(i) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(j) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(array(i), array(j))
+          END DO
+          array(left+1) = array(j)
+          array(j)      = element
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_ch
+
+
+
+
+
+  SUBROUTINE quickSort_ch_index(array, ind, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), DIMENSION(:), INTENT(inout) :: array
+    INTEGER, DIMENSION(SIZE(array)), INTENT(out) :: ind
+    CHARACTER(len=*), INTENT(inout) :: error
+    CHARACTER(len=LEN(array(1))) :: element
+    INTEGER, DIMENSION(NSTACK) :: stack
+    INTEGER :: i, j, center, left, right, n, istack, tmp
+
+    n = SIZE(array)
+    istack = 0
+    left  = 1
+    right = n
+    DO i=1,SIZE(ind)
+       ind(i) = i
+    END DO
+
+    DO
+       IF (right-left < NN) THEN
+          DO i=left+1,right
+             element = array(ind(i))
+             tmp = ind(i)
+             DO j=i-1,left,-1
+                IF (array(ind(j)) <= element) THEN
+                   EXIT
+                END IF
+                ind(j+1) = ind(j)
+             END DO
+             ind(j+1) = tmp
+          END DO
+          IF (istack == 0) RETURN
+          right  = stack(istack)
+          left   = stack(istack-1)
+          istack = istack - 2
+       ELSE
+          center = (left + right)/2
+          CALL swap(ind(center),ind(left+1))
+          CALL swap(ind(left),ind(right),array(ind(left))>array(ind(right)))
+          CALL swap(ind(left+1),ind(right),array(ind(left+1))>array(ind(right)))
+          CALL swap(ind(left),ind(left+1),array(ind(left))>array(ind(left+1)))
+          i = left + 1
+          j = right
+          element = array(ind(left+1))
+          tmp = ind(left+1)
+          DO
+             DO
+                i = i + 1
+                IF (array(ind(i)) >= element) EXIT
+             END DO
+             DO
+                j = j - 1
+                IF (array(ind(j)) <= element) EXIT
+             END DO
+             IF (j < i) EXIT
+             CALL swap(ind(i), ind(j))
+          END DO
+          ind(left+1) = ind(j)
+          ind(j)      = tmp
+          istack = istack + 2
+          IF (istack > NSTACK) THEN
+             error = " -> sort : quickSort : NSTACK too small." // TRIM(error)
+             RETURN
+          END IF
+          IF (right-i+1 >= j-1) THEN
+             stack(istack)   = right
+             stack(istack-1) = i
+             right           = j - 1
+          ELSE
+             stack(istack)   = j - 1
+             stack(istack-1) = left
+             left            = i
+          END IF
+       END IF
+    END DO
+
+  END SUBROUTINE quickSort_ch_index
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position of the search key in
+  !! the one-dimensional input array. If the search key is not found,
+  !! it returns -1.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the search
+  !! key by repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the key, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the value is found, or the interval
+  !! is empty.
+  !!
+  INTEGER FUNCTION binarySearch_i8(key, array, error)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    INTEGER(iprec8), INTENT(in)               :: key
+    INTEGER(iprec8), DIMENSION(:), INTENT(in) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER                              :: n, left, right, center, i
+
+    n = SIZE(array, dim=1)
+    ! Return immediately
+    ! - if the length of the array is zero:
+    IF (n == 0) THEN
+       binarySearch_i8 = -1
+       RETURN
+    END IF
+    ! - if the key (value to be searched for) is smaller or 
+    !   larger than the minimum or maximum values of
+    !   the array:
+    IF (key < array(1) .OR. key > array(n)) THEN
+       binarySearch_i8 = -1
+       RETURN
+    END IF
+
+    i = 1
+    left = 1
+    right = n
+    DO WHILE (left <= right .AND. i<=n+2)
+       i = i + 1
+       center = CEILING((left+right)/2.0)
+       IF (key == array(center)) THEN
+          binarySearch_i8 = center
+          RETURN
+       ELSE IF (key < array(center)) THEN
+          right = center - 1 
+       ELSE IF (key > array(center)) THEN
+          left = center + 1
+       END IF
+    END DO
+
+    IF (i == n+2) THEN
+       error = " -> sort : binarySearch : Search stuck in a loop." // TRIM(error)
+    END IF
+
+    ! The key could not be found in the array. 
+    ! Return a negative index:
+    binarySearch_i8 = -1
+
+  END FUNCTION binarySearch_i8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position of the search key in
+  !! the one-dimensional input array. If the search key is not found,
+  !! it returns -1.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the search
+  !! key by repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the key, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the value is found, or the interval
+  !! is empty.
+  !!
+  INTEGER FUNCTION binarySearch_r8(key, array, error)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)               :: key
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER                           :: n, left, right, center, i
+
+    n = SIZE(array, dim=1)
+    ! Return immediately
+    ! - if the length of the array is zero:
+    IF (n == 0) THEN
+       binarySearch_r8 = -1
+       RETURN
+    END IF
+    ! - if the key (value to be searched for) is smaller or 
+    !   larger than the minimum or maximum values of
+    !   the array:
+    IF (key < array(1) .OR. key > array(n)) THEN
+       binarySearch_r8 = -1
+       RETURN
+    END IF
+
+    i = 1
+    left = 1
+    right = n
+    DO WHILE (left <= right .AND. i<=n+2)
+       i = i + 1
+       center = CEILING((left+right)/2.0)
+       IF (ABS(key - array(center)) < 10.0_rprec8*EPSILON(key)) THEN
+          binarySearch_r8 = center
+          RETURN
+       ELSE IF (key < array(center)) THEN
+          right = center - 1 
+       ELSE IF (key > array(center)) THEN
+          left = center + 1
+       END IF
+    END DO
+
+    IF (i == n+2) THEN
+       error = " -> sort : binarySearch : Search stuck in a loop." // TRIM(error)
+    END IF
+
+    ! The key could not be found in the array. 
+    ! Return a negative index:
+    binarySearch_r8 = -1
+
+  END FUNCTION binarySearch_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position of the search key in
+  !! the one-dimensional input array. If the search key is not found,
+  !! it returns -1.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the search
+  !! key by repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the key, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the value is found, or the interval
+  !! is empty.
+  !!
+  INTEGER FUNCTION binarySearch_r16(key, array, error)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in)               :: key
+    REAL(rprec16), DIMENSION(:), INTENT(in) :: array
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER                            :: n, left, right, center, i
+
+    n = SIZE(array, dim=1)
+    ! Return immediately
+    ! - if the length of the array is zero:
+    IF (n == 0) THEN
+       binarySearch_r16 = -1
+       RETURN
+    END IF
+    ! - if the key (value to be searched for) is smaller or 
+    !   larger than the minimum or maximum values of
+    !   the array:
+    IF (key < array(1) .OR. key > array(n)) THEN
+       binarySearch_r16 = -1
+       RETURN
+    END IF
+
+    i = 1
+    left = 1
+    right = n
+    DO WHILE (left <= right .AND. i<=n+2)
+       i = i + 1
+       center = CEILING((left+right)/2.0)
+       IF (ABS(key - array(center)) < 10.0_rprec16*EPSILON(key)) THEN
+          binarySearch_r16 = center
+          RETURN
+       ELSE IF (key < array(center)) THEN
+          right = center - 1 
+       ELSE IF (key > array(center)) THEN
+          left = center + 1
+       END IF
+    END DO
+
+    IF (i == n+2) THEN
+       error = " -> sort : binarySearch : Search stuck in a loop." // TRIM(error)
+    END IF
+
+    ! The key could not be found in the array. 
+    ! Return a negative index:
+    binarySearch_r16 = -1
+
+  END FUNCTION binarySearch_r16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position of the search key in
+  !! the one-dimensional input array. If the search key is not found,
+  !! it returns -1.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the search
+  !! key by repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the key, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the value is found, or the interval
+  !! is empty.
+  !!
+  INTEGER FUNCTION binarySearch_ch(key, array, error)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)               :: key
+    CHARACTER(len=*), DIMENSION(:), INTENT(in) :: array
+    CHARACTER(len=*), INTENT(inout)            :: error
+
+    INTEGER :: n, left, right, center, i
+
+    n = SIZE(array, dim=1)
+    ! Return immediately
+    ! - if the length of the array is zero:
+    IF (n == 0) THEN
+       binarySearch_ch = -1
+       RETURN
+    END IF
+    ! - if the key (value to be searched for) is smaller or 
+    !   larger than the minimum or maximum values of
+    !   the array:
+    IF (key < array(1) .OR. key > array(n)) THEN
+       binarySearch_ch = -1
+       RETURN
+    END IF
+
+    i = 1
+    left = 1
+    right = n
+    DO WHILE (left <= right .AND. i<=n+2)
+       i = i + 1
+       center = CEILING((left+right)/2.0)
+       IF (key == array(center)) THEN
+          binarySearch_ch = center
+          RETURN
+       ELSE IF (key < array(center)) THEN
+          right = center - 1 
+       ELSE IF (key > array(center)) THEN
+          left = center + 1
+       END IF
+    END DO
+
+    IF (i == n+2) THEN
+       error = " -> sort : binarySearch : Search stuck in a loop." // TRIM(error)
+    END IF
+
+    ! The key could not be found in the array. 
+    ! Return a negative index:
+    binarySearch_ch = -1
+
+  END FUNCTION binarySearch_ch
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position of the search key in
+  !! the one-dimensional input array. If the search key is not found,
+  !! it returns -1.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the search
+  !! key by repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the key, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the value is found, or the interval
+  !! is empty.
+  !!
+  INTEGER FUNCTION binarySearch_ch_index(key, array, indx, error)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)               :: key
+    CHARACTER(len=*), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(:), INTENT(in) :: indx
+    CHARACTER(len=*), INTENT(inout) :: error
+    INTEGER                            :: n, left, right, center, i
+
+    n = SIZE(array, dim=1)
+    ! Return immediately
+    ! - if the length of the array is zero:
+    IF (n == 0) THEN
+       binarySearch_ch_index = -1
+       RETURN
+    END IF
+    ! - if the key (value to be searched for) is smaller or 
+    !   larger than the minimum or maximum values of
+    !   the array:
+    IF (key < array(indx(1)) .OR. key > array(indx(n))) THEN
+       binarySearch_ch_index = -1
+       RETURN
+    END IF
+
+    i = 1
+    left = 1
+    right = n
+    DO WHILE (left <= right .AND. i<=n+2)
+       i = i + 1
+       center = CEILING((left+right)/2.0)
+       IF (key == array(indx(center))) THEN
+          binarySearch_ch_index = indx(center)
+          RETURN
+       ELSE IF (key < array(indx(center))) THEN
+          right = center - 1 
+       ELSE IF (key > array(indx(center))) THEN
+          left = center + 1
+       END IF
+    END DO
+
+    IF (i == n+2) THEN
+       error = " -> sort : binarySearch : Search stuck in a loop." // TRIM(error)
+    END IF
+
+    ! The key could not be found in the array. 
+    ! Return a negative index:
+    binarySearch_ch_index = -1
+
+  END FUNCTION binarySearch_ch_index
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position where the value
+  !! should be found (starting from left) in the one-dimensional input
+  !! array, if the array is sorted in ascending order.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the value by
+  !! repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the value, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the interval is empty.
+  !!
+  INTEGER FUNCTION findLocation_r8(VALUE, array)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)               :: VALUE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER                              :: n, left, right, center
+
+    n = SIZE(array)
+    ! Return immediately, if the value is smaller or larger than the
+    ! minimum or maximum values of the array:
+    IF (VALUE < array(1)) THEN
+       findLocation_r8 = 1
+       RETURN
+    ELSE IF (VALUE >= array(n)) THEN
+       findLocation_r8 = n+1
+       RETURN
+    END IF
+
+    left = 1
+    right = n
+    center = CEILING((left+right)/2.0)
+    DO WHILE (right-left > 1)
+       center = CEILING((left+right)/2.0)
+       IF (VALUE < array(center)) THEN
+          right = center
+       ELSE IF (VALUE >= array(center)) THEN
+          left = center
+       END IF
+    END DO
+    IF (VALUE < array(center)) THEN
+       findLocation_r8 = center
+    ELSE
+       findLocation_r8 = center + 1
+    END IF
+
+  END FUNCTION findLocation_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position where the value
+  !! should be found (starting from left) in the one-dimensional input
+  !! array, given an index array providing the ascending order of the
+  !! array elements.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the value by
+  !! repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the value, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the interval is empty.
+  !!
+  INTEGER FUNCTION findLocation_r8_indx(VALUE, array, indx_array)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    INTEGER, PARAMETER                   :: prec = 8
+    REAL(rprec8), INTENT(in)               :: VALUE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(:), INTENT(in)    :: indx_array
+    INTEGER                              :: n, left, right, center
+
+    n = SIZE(array)
+    ! Return immediately, if the value is smaller or larger than the
+    ! minimum or maximum values of the array:
+    IF (VALUE < array(indx_array(1))) THEN
+       findLocation_r8_indx = 1
+       RETURN
+    ELSE IF (VALUE >= array(indx_array(n))) THEN
+       findLocation_r8_indx = n+1
+       RETURN
+    END IF
+
+    left = 1
+    right = n
+    center = CEILING((left+right)/2.0)
+    DO WHILE (right-left > 1)
+       center = CEILING((left+right)/2.0)
+       IF (VALUE < array(indx_array(center))) THEN
+          right = center
+       ELSE IF (VALUE >= array(indx_array(center))) THEN
+          left = center
+       END IF
+    END DO
+    IF (VALUE < array(indx_array(center))) THEN
+       findLocation_r8_indx = center
+    ELSE
+       findLocation_r8_indx = center + 1
+    END IF
+
+  END FUNCTION findLocation_r8_indx
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Binary search routine. Returns the position where the value
+  !! should be found (starting from left) in the one-dimensional input
+  !! array, if the array is sorted in ascending order.
+  !!
+  !! As a prerequisite, the array which is to be scanned has to be sorted
+  !! in ascending order. The algorithm searches for the value by
+  !! repeatedly dividing the search interval in half. Initially
+  !! the interval covers the whole array. If the item in the middle of
+  !! the interval is larger than the value, the interval is narrowed to
+  !! the lower half. Otherwise it is narrowed to the upper half. The
+  !! procedure is continued until the interval is empty.
+  !!
+  INTEGER FUNCTION findLocation_r16(VALUE, array)
+
+    ! The input array needs to be sorted in ascending order.
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in)               :: VALUE
+    REAL(rprec16), DIMENSION(:), INTENT(in) :: array
+    INTEGER                              :: n, left, right, center
+
+    n = SIZE(array)
+    ! Return immediately, if the value is smaller or larger than the
+    ! minimum or maximum values of the array:
+    IF (VALUE < array(1)) THEN
+       findLocation_r16 = 1
+       RETURN
+    ELSE IF (VALUE >= array(n)) THEN
+       findLocation_r16 = n+1
+       RETURN
+    END IF
+
+    left = 1
+    right = n
+    center = CEILING((left+right)/2.0)
+    DO WHILE (right-left > 1)
+       center = CEILING((left+right)/2.0)
+       IF (VALUE < array(center)) THEN
+          right = center
+       ELSE IF (VALUE >= array(center)) THEN
+          left = center
+       END IF
+    END DO
+    IF (VALUE < array(center)) THEN
+       findLocation_r16 = center
+    ELSE
+       findLocation_r16 = center + 1
+    END IF
+
+  END FUNCTION findLocation_r16
+
+
+
+
+
+END MODULE sort
Index: trunk/mops/oorb/modules/statistics.f90
===================================================================
--- trunk/mops/oorb/modules/statistics.f90	(revision 34646)
+++ trunk/mops/oorb/modules/statistics.f90	(revision 34646)
@@ -0,0 +1,621 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Tools for statistics.
+!!
+!! @author  MG
+!! @version 2011-11-30
+!!
+MODULE statistics
+
+  USE parameters
+  USE utilities
+  USE sort
+
+  IMPLICIT NONE
+
+  PRIVATE :: chi_square_blockdiag
+  PRIVATE :: moments_r8
+  PRIVATE :: confidence_limits_hist_r8
+  PRIVATE :: confidence_limits_sample_r8
+
+  INTERFACE chi_square
+     MODULE PROCEDURE chi_square_blockdiag
+  END INTERFACE chi_square
+
+  INTERFACE moments
+     MODULE PROCEDURE moments_r8
+  END INTERFACE moments
+
+  INTERFACE confidence_limits
+     MODULE PROCEDURE confidence_limits_hist_r8
+     MODULE PROCEDURE confidence_limits_sample_r8
+  END INTERFACE confidence_limits
+
+CONTAINS
+
+
+
+
+  !! *Description*:
+  !!
+  !! Tested.
+  !!
+  !! @author  MG
+  !! @version 2009-10-13
+  !!
+  REAL(rprec8) FUNCTION chi_square_blockdiag(residuals, information_matrix, mask, errstr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: residuals
+    REAL(rprec8), DIMENSION(:,:,:), INTENT(in) :: information_matrix
+    LOGICAL, DIMENSION(:,:), INTENT(in), OPTIONAL :: mask
+    CHARACTER(len=*), INTENT(inout) :: errstr
+
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: residuals_
+    REAL(rprec8), DIMENSION(1) :: chi_square_blockdiag_
+    INTEGER :: i, nobs, nmulti, err
+
+    chi_square_blockdiag = 0.0_rprec8
+    chi_square_blockdiag_ = 0.0_rprec8
+    nobs = SIZE(residuals,dim=1)
+    nmulti = SIZE(residuals,dim=2)
+
+    IF (SIZE(information_matrix,dim=1) /= nobs .OR. &
+         SIZE(information_matrix,dim=2) /= nmulti .OR. &
+         SIZE(information_matrix,dim=3) /= nmulti) THEN
+       errstr = " -> statistics : chi_square : Shape of input matrices do not conform." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+
+    ALLOCATE(residuals_(nobs,nmulti), stat=err)
+    IF (err /= 0) THEN
+       errstr = " -> statistics : chi_square : Could not allocate memory." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+    residuals_ = residuals
+    IF (PRESENT(mask)) THEN
+       WHERE (.NOT. mask)
+          residuals_ = 0.0_rprec8
+       END WHERE
+    END IF
+    DO i=1,nobs
+       chi_square_blockdiag_ = chi_square_blockdiag_ + &
+            MATMUL(MATMUL(residuals_(i,1:nmulti), &
+            information_matrix(i,1:nmulti,1:nmulti)), &
+            TRANSPOSE(residuals_(i:i,1:nmulti)))
+    END DO
+    chi_square_blockdiag = chi_square_blockdiag_(1)
+    DEALLOCATE(residuals_, stat=err)
+    IF (err /= 0) THEN
+       WRITE(0,*) "chi_square" // &
+            "Could not deallocate memory."
+       RETURN
+    END IF
+
+  END FUNCTION chi_square_blockdiag
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes a histogram (histo) for given data (indata) either as
+  !! number density (without pdf) or from pdf (with pdf).
+  !!
+  SUBROUTINE histogram(indata, histo, xmin_in, xmax_in, pdf, xmax, dx)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)                      :: indata
+    REAL(rprec8), DIMENSION(:,:), INTENT(out)                   :: histo
+    REAL(rprec8), INTENT(in), OPTIONAL                          :: xmin_in
+    REAL(rprec8), INTENT(in), OPTIONAL                          :: xmax_in
+    REAL(rprec8), DIMENSION(SIZE(indata)), INTENT(in), OPTIONAL :: pdf
+    REAL(rprec8), INTENT(out), OPTIONAL                         :: xmax
+    REAL(rprec8), INTENT(out), OPTIONAL                         :: dx
+
+    REAL(rprec8), DIMENSION(SIZE(indata)) :: pdf_
+    REAL(rprec8) :: dx_, x_min, x_max
+    INTEGER :: ngrid, nvalue, i, j
+
+    ngrid = SIZE(histo,dim=1)
+    nvalue = SIZE(indata)
+    IF (PRESENT(xmin_in)) THEN
+       x_min = xmin_in
+    ELSE
+       x_min = MINVAL(indata)
+    END IF
+    IF (PRESENT(xmax_in)) THEN
+       x_max = xmax_in
+    ELSE
+       x_max = MAXVAL(indata)
+    END IF
+    dx_ = (x_max-x_min) / ngrid
+    DO i=1, ngrid
+       histo(i,1) = x_min + 0.5_rprec8*dx_ + dx_*(i-1)
+    END DO
+
+    IF (PRESENT(pdf)) THEN
+       ! Use given pdf the sum of which is normalized to unity:
+       pdf_ = pdf/SUM(pdf)
+    ELSE
+       ! Use number density:
+       pdf_ = 1.0_rprec8
+    END IF
+
+    histo(:,2) = 0.0_rprec8
+    DO i=1,nvalue
+       DO j=1,ngrid
+          IF (ABS(indata(i)-histo(j,1)) < 0.5_rprec8*dx_) THEN
+             histo(j,2) = histo(j,2) + pdf_(i)
+             EXIT
+          END IF
+       END DO
+    END DO
+    IF (PRESENT(xmax)) THEN
+       xmax = histo(MAXLOC(histo(:,2),dim=1),1)
+    END IF
+    IF (PRESENT(dx)) THEN
+       dx = dx_
+    END IF
+
+  END SUBROUTINE histogram
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Computes various statistical quantities for a given data set.
+  !! Current output: arithmetic mean, standard deviation, skewness,
+  !! and kurtosis.
+  !!
+  SUBROUTINE moments_r8(indata, pdf, mask, mean, std_dev, skew, kurt, errstr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)           :: indata
+    REAL(rprec8), DIMENSION(:), INTENT(in), OPTIONAL :: pdf
+    LOGICAL, DIMENSION(:), OPTIONAL, INTENT(in)      :: mask
+    REAL(rprec8), OPTIONAL, INTENT(out)              :: mean, std_dev, skew, kurt
+    CHARACTER(len=*), INTENT(inout)                           :: errstr
+
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: pdf_
+    REAL(rprec8) :: mean_, std_dev_
+    INTEGER :: ndata, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask_
+
+    ndata = SIZE(indata)
+    ALLOCATE(mask_(ndata), pdf_(ndata), stat=err)
+    IF (err /= 0) THEN
+       RETURN
+    END IF
+    mask_ = .TRUE.
+    IF (PRESENT(mask)) THEN
+       mask_ = mask
+    END IF
+    ndata = COUNT(mask_)
+    IF (PRESENT(pdf)) THEN
+       ! Make sure the distribution is normalized:
+       pdf_ = pdf/SUM(pdf, mask=mask_)
+    END IF
+
+    ! Lowest moments:
+    ! Mean:
+    IF (PRESENT(pdf)) THEN
+       mean_ = SUM(indata*pdf_, mask=mask_)
+    ELSE
+       mean_ = SUM(indata, mask=mask_)/ndata
+    END IF
+    IF (PRESENT(mean)) THEN
+       mean = mean_
+    END IF
+
+    ! Standard deviation:
+    IF (PRESENT(std_dev) .OR. PRESENT(skew) .OR. PRESENT(kurt)) THEN
+       IF (PRESENT(pdf)) THEN
+          std_dev_ = SQRT(SUM(((indata - &
+               indata(MAXLOC(pdf_,dim=1)))**2.0_rprec8)*pdf_, &
+               mask=mask_))
+       ELSE
+          std_dev_ = SQRT(SUM(((indata - mean_)**2.0_rprec8), &
+               mask=mask_) / (ndata-1))
+       END IF
+       IF (PRESENT(std_dev)) THEN
+          std_dev = std_dev_
+       END IF
+    END IF
+
+    ! Skewness:
+    IF (PRESENT(skew)) THEN
+       IF (PRESENT(pdf)) THEN
+          skew = SUM(((indata - indata(MAXLOC(pdf_,dim=1)))**3.0_rprec8)*pdf_, &
+               mask=mask_) / std_dev_
+       ELSE
+          skew = SUM(((indata - mean_)**3.0_rprec8), &
+               mask=mask_) / (std_dev_*ndata)
+       END IF
+    END IF
+
+    ! Kurtosis:
+    IF (PRESENT(kurt)) THEN
+       IF (PRESENT(pdf)) THEN
+          kurt = SUM(((indata - indata(MAXLOC(pdf_,dim=1)))**4.0_rprec8)*pdf_, &
+               mask=mask_) / std_dev_
+       ELSE
+          kurt = SUM(((indata - mean_)**4.0_rprec8), &
+               mask=mask_) / (std_dev_*ndata)
+       END IF
+    END IF
+
+    !r = sum((data_set-mean_)*(data_set)
+
+    DEALLOCATE(pdf_, mask_, stat=err)
+    IF (err /= 0) THEN
+       DEALLOCATE(pdf_, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE moments_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This routine calculates the end points of the confidence interval
+  !! (or credible interval) by incorporating bins of a histogram until
+  !! the sum of normalized weights is larger than the requested
+  !! probability mass.
+  !!
+  SUBROUTINE confidence_limits_hist_r8(indata, pdf, nhist, &
+       mask, probability_mass, peak, bounds, errstr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)            :: indata
+    REAL(rprec8), DIMENSION(:), INTENT(in)            :: pdf
+    INTEGER, INTENT(in)                               :: nhist
+    REAL(rprec8), INTENT(in), OPTIONAL                :: probability_mass
+    LOGICAL, DIMENSION(:), OPTIONAL, INTENT(in)       :: mask
+    REAL(rprec8), OPTIONAL, INTENT(out)               :: peak
+    REAL(rprec8), DIMENSION(2), OPTIONAL, INTENT(out) :: bounds
+    CHARACTER(len=*), INTENT(inout)                            :: errstr
+
+    REAL(rprec8), DIMENSION(:,:), ALLOCATABLE :: histo, histo_
+    REAL(rprec8) :: probability_mass_
+    INTEGER :: ndata, err, imax, ilo, ihi
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask_
+
+    ndata = SIZE(indata)
+    ALLOCATE(mask_(ndata), histo(nhist,2), histo_(nhist,2), stat=err)
+    IF (err /= 0) THEN
+       errstr = " -> statistics : confidence_limits : Could not allocate memory." // &
+            TRIM(errstr)
+       DEALLOCATE(histo, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+    mask_ = .TRUE.
+    IF (PRESENT(mask)) THEN
+       mask_ = mask
+    ELSE
+       mask_ = .TRUE.
+    END IF
+
+    IF (PRESENT(bounds) .AND. .NOT.PRESENT(probability_mass)) THEN
+       errstr = " -> statistics : confidence_limits : Probability mass not given." // &
+            TRIM(errstr)
+       DEALLOCATE(histo, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+
+    ! Produce histogram based on pdf:
+    CALL histogram(indata, histo, pdf=pdf)
+    IF (PRESENT(peak)) THEN
+       ! ML solution
+       imax = imaxloc(histo(:,2))
+       peak = histo(imax,1)
+    END IF
+
+    IF (PRESENT(bounds)) THEN
+       histo(:,2) = histo(:,2)/SUM(histo(:,2))
+       histo_ = histo
+       bounds(1) = HUGE(bounds(1))
+       bounds(2) = -HUGE(bounds(2))
+       ilo = nhist
+       ihi = 1
+       probability_mass_ = 0.0_rprec8
+       DO WHILE (probability_mass_ < probability_mass)
+          imax = imaxloc(histo_(:,2))
+          IF (imax < ilo) THEN
+             ilo = imax
+          END IF
+          IF (imax > ihi) THEN
+             ihi = imax
+          END IF
+          probability_mass_ = SUM(histo(ilo:ihi,2))
+          IF (histo(imax,1) < bounds(1)) THEN
+             bounds(1) = histo(imax,1)
+          END IF
+          IF (histo(imax,1) > bounds(2)) THEN
+             bounds(2) = histo(imax,1)
+          END IF
+          histo_(imax,2) = 0.0_rprec8
+       END DO
+    END IF
+
+    DEALLOCATE(histo, histo_, mask_, stat=err)
+    IF (err /= 0) THEN
+       errstr = " -> statistics : confidence_limits : Could not deallocate memory." // &
+            TRIM(errstr)
+       DEALLOCATE(histo, stat=err)
+       DEALLOCATE(histo_, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE confidence_limits_hist_r8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This routine calculates the end points of the confidence interval
+  !! (or credible interval) by descending from the ML solution until
+  !! the sum of normalized weights is larger than the requested
+  !! probability mass.
+  !!
+  SUBROUTINE confidence_limits_sample_r8(indata, pdf, mask, &
+       probability_mass, peak, bounds, errstr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)            :: indata
+    REAL(rprec8), DIMENSION(:), INTENT(in)            :: pdf
+    REAL(rprec8), INTENT(in), OPTIONAL                :: probability_mass
+    LOGICAL, DIMENSION(:), OPTIONAL, INTENT(in)       :: mask
+    REAL(rprec8), OPTIONAL, INTENT(out)               :: peak
+    REAL(rprec8), DIMENSION(2), OPTIONAL, INTENT(out) :: bounds
+    CHARACTER(len=*), INTENT(inout)                   :: errstr
+
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: pdf_
+    REAL(rprec8) :: probability_mass_
+    INTEGER, DIMENSION(:), ALLOCATABLE :: indx_arr
+    INTEGER :: ndata, imax, i, err
+    LOGICAL, DIMENSION(:), ALLOCATABLE :: mask_
+
+    ndata = SIZE(indata)
+    IF (ndata /= SIZE(pdf)) THEN
+       errstr = " -> statistics : confidence_limits : Size of vectors does not conform." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+    ALLOCATE(pdf_(ndata), mask_(ndata), stat=err)
+    IF (err /= 0) THEN
+       errstr = " -> statistics : confidence_limits : Could not allocate memory." // &
+            TRIM(errstr)
+       DEALLOCATE(pdf_, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+    mask_ = .TRUE.
+    IF (PRESENT(mask)) THEN
+       IF (ndata /= SIZE(mask)) THEN
+          errstr = " -> statistics : confidence_limits : Size of mask does not conform with data." // &
+               TRIM(errstr)
+          DEALLOCATE(pdf_, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          RETURN
+       END IF
+       mask_ = mask
+    ELSE
+       mask_ = .TRUE.
+    END IF
+    pdf_ = pdf
+    WHERE (.NOT.mask_)
+       pdf_ = 0.0_rprec8
+    END WHERE
+    pdf_ = pdf_/SUM(pdf_)
+
+    IF (PRESENT(bounds) .AND. .NOT.PRESENT(probability_mass)) THEN
+       errstr = " -> statistics : confidence_limits : Probability mass not given." // &
+            TRIM(errstr)
+       DEALLOCATE(pdf_, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+
+    IF (PRESENT(peak)) THEN
+       ! Find peak of phase angle histogram:
+       imax = imaxloc(pdf_)
+       peak = indata(imax)
+    END IF
+    IF (PRESENT(bounds)) THEN
+       ALLOCATE(indx_arr(ndata), stat=err)
+       IF (err /= 0) THEN
+          errstr = " -> statistics : confidence_limits : Caould not allocate memory." // &
+               TRIM(errstr)
+          DEALLOCATE(pdf_, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          DEALLOCATE(indx_arr, stat=err)
+          RETURN
+       END IF
+       CALL quicksort(pdf_, indx_arr, errstr)
+       IF (LEN_TRIM(errstr) /= 0) THEN
+          errstr = " -> statistics : confidence_limits : ." // &
+               TRIM(errstr)
+          DEALLOCATE(pdf_, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          DEALLOCATE(indx_arr, stat=err)
+          RETURN
+       END IF
+       pdf_ = pdf_/SUM(pdf_)
+       bounds(1) = HUGE(bounds(1))
+       bounds(2) = -HUGE(bounds(2))
+       probability_mass_ = 0.0_rprec8
+       DO i=ndata,1,-1
+          IF (mask_(indx_arr(i))) THEN
+             probability_mass_ = probability_mass_ + pdf_(indx_arr(i))
+             IF (indata(indx_arr(i)) < bounds(1)) THEN
+                bounds(1) = indata(indx_arr(i))
+             ELSE IF (indata(indx_arr(i)) > bounds(2)) THEN
+                bounds(2) = indata(indx_arr(i))               
+             END IF
+             IF (probability_mass_ >= probability_mass) THEN
+                EXIT
+             END IF
+          END IF
+       END DO
+       DEALLOCATE(indx_arr, stat=err)
+       IF (err /= 0) THEN
+          errstr = " -> statistics : confidence_limits : Could not deallocate memory (1)." // &
+               TRIM(errstr)
+          DEALLOCATE(pdf_, stat=err)
+          DEALLOCATE(mask_, stat=err)
+          DEALLOCATE(indx_arr, stat=err)
+          RETURN
+       END IF
+    END IF
+
+    DEALLOCATE(pdf_, mask_, stat=err)
+    IF (err /= 0) THEN
+       errstr = " -> statistics : confidence_limits : Could not deallocate memory (2)." // &
+            TRIM(errstr)
+       DEALLOCATE(pdf_, stat=err)
+       DEALLOCATE(mask_, stat=err)
+       RETURN
+    END IF
+
+  END SUBROUTINE confidence_limits_sample_r8
+
+
+
+
+
+  SUBROUTINE credible_region(pdf_arr, probability_mass, indx_arr, errstr, repetition_arr)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: pdf_arr
+    REAL(rprec8), INTENT(in) :: probability_mass
+    INTEGER, DIMENSION(:), INTENT(out) :: indx_arr
+    CHARACTER(len=*), INTENT(inout) :: errstr
+    INTEGER, DIMENSION(:), INTENT(in), OPTIONAL :: repetition_arr
+
+    REAL(rprec8), DIMENSION(:), ALLOCATABLE :: pdf_arr_
+    REAL(rprec8) :: probability_mass_
+    INTEGER :: i, j, irepet, nrepet
+
+    ! Sort the pdf in ascending order:
+    CALL quickSort(pdf_arr, indx_arr, errstr)
+    IF (LEN_TRIM(errstr) /= 0) THEN
+       errstr = " -> statistics : credible_region : TRACE BACK." // &
+            TRIM(errstr)
+       RETURN
+    END IF
+    ! Start from the largest pdf value
+    i = SIZE(pdf_arr)
+    IF (PRESENT(repetition_arr)) THEN
+       ! MCMC 
+       ! Which number of repetitions corresponds to the wanted
+       ! probability mass?
+       nrepet = CEILING(SUM(repetition_arr)*probability_mass)
+       ! Add distinct sampling points until reaching the desired
+       ! number of (typically non-unique) sample points:
+       irepet = 0
+       DO WHILE (irepet < nrepet)
+          irepet = irepet + repetition_arr(indx_arr(i))
+          i = i - 1
+       END DO
+    ELSE
+       ! MC
+       ALLOCATE(pdf_arr_(SIZE(pdf_arr)))
+       ! Normalize the pdf distribution
+       pdf_arr_ = pdf_arr/SUM(pdf_arr)
+       ! Add sample points until the desired probability mass is
+       ! reached:
+       probability_mass_ = 0.0_rprec8
+       DO WHILE (probability_mass_ < probability_mass)
+          probability_mass_ = probability_mass_ + pdf_arr_(indx_arr(i))
+          i = i - 1
+       END DO
+       DEALLOCATE(pdf_arr_)
+    END IF
+    ! Fill the resulting index array with negative values for the
+    ! sample points that do not fit within the desired probability
+    ! mass:
+    DO j=i,1,-1
+       indx_arr(j) = -1
+    END DO
+
+  END SUBROUTINE credible_region
+
+
+
+
+
+  SUBROUTINE population_covariance(indata, covariance, mean, mask)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: indata
+    REAL(rprec8), DIMENSION(:,:), INTENT(out) :: covariance
+    REAL(rprec8), DIMENSION(:), INTENT(out) :: mean
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: mask
+
+    INTEGER :: i, j
+    LOGICAL,DIMENSION(SIZE(indata,dim=2)) :: mask_
+
+    IF (PRESENT(mask)) THEN
+       mask_ = mask
+       covariance = 0.0_rprec8
+    ELSE
+       mask_ = .TRUE.
+    END IF
+
+    DO i=1,SIZE(indata,dim=2)
+       ! Compute mean for variable i
+       mean(i) = SUM(indata(:,i))/SIZE(indata,dim=1)
+       ! Compute elements of covariance matrix from 1,1 to i,i
+       DO j=1,i
+          IF (mask_(i) .AND. mask_(j)) THEN
+             covariance(i,j) = SUM((indata(:,i)-mean(i)) * (indata(:,j)-mean(j))) / &
+                  SIZE(indata,dim=1)
+             covariance(j,i) = covariance(i,j) 
+          END IF
+       END DO
+    END DO
+
+  END SUBROUTINE population_covariance
+
+
+
+
+END MODULE statistics
Index: trunk/mops/oorb/modules/utilities.f90
===================================================================
--- trunk/mops/oorb/modules/utilities.f90	(revision 34646)
+++ trunk/mops/oorb/modules/utilities.f90	(revision 34646)
@@ -0,0 +1,1609 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009,2010,2011        !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! *Module*description*:
+!!
+!! Independent utilities.
+!!
+!! @author  MG
+!! @version 2010-01-26
+!!
+MODULE utilities
+
+  USE parameters
+
+  IMPLICIT NONE
+
+  PRIVATE :: integerToArray_ri8
+  PRIVATE :: arrayToInteger_r8i8
+  PRIVATE :: arrayToReal_r8r16
+  PRIVATE :: realToArray_r16r8
+  PRIVATE :: reallocate_ch_1
+  PRIVATE :: reallocate_ch_2
+  PRIVATE :: reallocate_r4_1
+  PRIVATE :: reallocate_r4_2
+  PRIVATE :: reallocate_r8_1
+  PRIVATE :: reallocate_r8_2
+  PRIVATE :: reallocate_r8_3
+  PRIVATE :: reallocate_r16_1
+  PRIVATE :: reallocate_r16_2
+  PRIVATE :: reallocate_i1_1
+  PRIVATE :: reallocate_i4_1
+  PRIVATE :: reallocate_i4_2
+  PRIVATE :: reallocate_i8_1
+  PRIVATE :: reallocate_i8_2
+  PRIVATE :: reallocate_l_1
+  PRIVATE :: reallocate_l_2
+  PRIVATE :: secToHMS_r4
+  PRIVATE :: secToHMS_r8
+  PRIVATE :: toInt_4
+  PRIVATE :: toReal_8
+  PRIVATE :: toReal_16
+  PRIVATE :: toString_i4
+  PRIVATE :: toString_i8
+  PRIVATE :: toString_r4
+  PRIVATE :: toString_r8
+
+  INTERFACE arrayToInteger
+     MODULE PROCEDURE arrayToInteger_r8i8
+  END INTERFACE arrayToInteger
+
+  INTERFACE arrayToReal
+     MODULE PROCEDURE arrayToReal_r8r16
+  END INTERFACE arrayToReal
+
+  INTERFACE integerToArray
+     MODULE PROCEDURE integerToArray_ri8
+  END INTERFACE integerToArray
+
+  INTERFACE imaxloc
+     MODULE PROCEDURE imaxloc_i4
+     MODULE PROCEDURE imaxloc_i8
+     MODULE PROCEDURE imaxloc_r4
+     MODULE PROCEDURE imaxloc_r8
+     MODULE PROCEDURE imaxloc_r16
+  END INTERFACE imaxloc
+
+  INTERFACE iminloc
+     MODULE PROCEDURE iminloc_i4
+     MODULE PROCEDURE iminloc_i8
+     MODULE PROCEDURE iminloc_r4
+     MODULE PROCEDURE iminloc_r8
+     MODULE PROCEDURE iminloc_r16
+  END INTERFACE iminloc
+
+  INTERFACE realToArray
+     MODULE PROCEDURE realToArray_r16r8
+  END INTERFACE realToArray
+
+  INTERFACE reallocate
+     MODULE PROCEDURE reallocate_ch_1
+     MODULE PROCEDURE reallocate_ch_2
+     MODULE PROCEDURE reallocate_r4_1
+     MODULE PROCEDURE reallocate_r4_2
+     MODULE PROCEDURE reallocate_r8_1
+     MODULE PROCEDURE reallocate_r8_2
+     MODULE PROCEDURE reallocate_r8_3
+     MODULE PROCEDURE reallocate_r16_1
+     MODULE PROCEDURE reallocate_r16_2
+     MODULE PROCEDURE reallocate_i1_1
+     MODULE PROCEDURE reallocate_i4_1
+     MODULE PROCEDURE reallocate_i4_2
+     MODULE PROCEDURE reallocate_i8_1
+     MODULE PROCEDURE reallocate_i8_2
+     MODULE PROCEDURE reallocate_l_1
+     MODULE PROCEDURE reallocate_l_2
+  END INTERFACE reallocate
+
+  INTERFACE swap
+     MODULE PROCEDURE swap_i4
+     MODULE PROCEDURE swap_i8
+     MODULE PROCEDURE swap_scalar_r8
+     MODULE PROCEDURE swap_vector_r8
+     MODULE PROCEDURE swap_r16
+     MODULE PROCEDURE swap_ch
+  END INTERFACE swap
+
+  INTERFACE toInt
+     MODULE PROCEDURE toInt_4
+  END INTERFACE toInt
+
+  INTERFACE secToHMS
+     MODULE PROCEDURE secToHMS_r4
+     MODULE PROCEDURE secToHMS_r8
+  END INTERFACE secToHMS
+
+  INTERFACE toReal
+     MODULE PROCEDURE toReal_8
+     MODULE PROCEDURE toReal_16
+  END INTERFACE toReal
+
+  INTERFACE toString
+     MODULE PROCEDURE toString_i4
+     MODULE PROCEDURE toString_i8
+     MODULE PROCEDURE toString_r4
+     MODULE PROCEDURE toString_r8
+  END INTERFACE toString
+
+
+
+CONTAINS
+
+
+
+
+
+  INTEGER(iprec8) FUNCTION arrayToInteger_r8i8(array, elements, bin_size, nbins, bounds, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)     :: array    ! input array
+    LOGICAL, DIMENSION(:), INTENT(in)         :: elements ! used elements
+    REAL(rprec8), DIMENSION(:), INTENT(in)     :: bin_size ! bin sizes
+    INTEGER, DIMENSION(:), INTENT(in)         :: nbins     ! number of bins
+    REAL(rprec8), DIMENSION(:,:), INTENT(in)   :: bounds   ! variable bounds
+    LOGICAL, INTENT(out)                      :: error
+    INTEGER(iprec8), DIMENSION(:), ALLOCATABLE :: kp
+    INTEGER, DIMENSION(:), ALLOCATABLE        :: help, nbins_
+    INTEGER(iprec8)                            :: bins_coeff, intgr
+    INTEGER                                   :: ncolumn, i, j, err
+
+    ! Make an index (help) of the elements that are used:
+    ncolumn = COUNT(elements)
+    ALLOCATE(kp(ncolumn), help(ncolumn), nbins_(ncolumn), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+    j = 0
+    DO i=1,SIZE(elements)
+       IF (elements(i)) THEN
+          j = j + 1
+          help(j) = i
+          nbins_(j) = nbins(i)
+       END IF
+    END DO
+
+    ! Compute coordinates of the bin:
+    DO i=1,SIZE(kp)
+       ! Compute a value describing a single elements position:
+       kp(i) = INT((array(help(i)) - bounds(help(i),1)) / &
+            bin_size(help(i)),4) + 1
+    END DO
+
+    ! If one or more of the elements are out of bounds, skip the
+    ! array:
+    IF (ANY(kp>nbins_) .OR. ANY(kp<0)) THEN
+       arrayToInteger_r8i8 = 0_iprec8
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+
+    ! Transform bin coordinates to a single integer value
+    ! (size(kp) == size(help)):
+    intgr = 0_iprec8
+    DO i=1,SIZE(kp)
+       bins_coeff = 1_iprec8
+       DO j=2,i
+          bins_coeff = bins_coeff*INT(nbins_(j-1),iprec8)
+       END DO
+       intgr = intgr + INT((kp(i) - 1),iprec8)*bins_coeff
+    END DO
+    intgr = intgr + 1_iprec8
+
+    DEALLOCATE(kp, help, nbins_, stat=err)
+    IF (err /= 0) THEN
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+    END IF
+    arrayToInteger_r8i8 = intgr
+
+  END FUNCTION arrayToInteger_r8i8
+
+
+
+
+
+  REAL(rprec16) FUNCTION arrayToReal_r8r16(array, elements, bin_size, nbins, bounds, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in)   :: array    ! input array
+    LOGICAL, DIMENSION(:), INTENT(in)       :: elements ! used elements
+    REAL(rprec8), DIMENSION(:), INTENT(in)   :: bin_size ! bin sizes
+    INTEGER, DIMENSION(:), INTENT(in)       :: nbins     ! number of bins
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: bounds   ! variable bounds
+    LOGICAL, INTENT(out)                    :: error
+    INTEGER(iprec8), DIMENSION(:), ALLOCATABLE   :: kp
+    INTEGER, DIMENSION(:), ALLOCATABLE      :: help, nbins_
+    REAL(rprec16)                            :: bins_coeff, rreal
+    REAL(rprec8)                             :: tmp
+    INTEGER                                 :: ncolumn, i, j, err
+
+    ! Make an index (help) of the elements that are used:
+    ncolumn = COUNT(elements)
+    ALLOCATE(kp(ncolumn), help(ncolumn), nbins_(ncolumn), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+    j = 0
+    DO i=1,SIZE(elements,dim=1)
+       IF (elements(i)) THEN
+          j = j + 1
+          help(j) = i
+          nbins_(j) = nbins(i)
+       END IF
+    END DO
+
+    ! Compute coordinates of the bin:
+    DO i=1,SIZE(kp,dim=1)
+       ! Compute a value describing a single elements position:
+       tmp = array(help(i)) - bounds(help(i),1)
+       tmp = tmp / bin_size(help(i))
+       kp(i) = INT(tmp,4) + 1
+    END DO
+
+    ! If one or more of the elements are out of bounds, skip the
+    ! array:
+    IF (ANY(kp > nbins_) .OR. ANY(kp < 0)) THEN
+       arrayToReal_r8r16 = 0.0_rprec16
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+
+    ! Transform bin coordinates to a single integer value
+    ! (size(kp) == size(help)):
+    rreal = 0.0_rprec16
+    DO i=1,SIZE(kp,dim=1)
+       bins_coeff = 1.0_rprec16
+       DO j=2,i
+          bins_coeff = bins_coeff*REAL(nbins_(j-1),rprec16)
+       END DO
+       rreal = rreal + REAL((kp(i) - 1),rprec16)*bins_coeff
+    END DO
+    rreal = rreal + 1.0_rprec16
+
+    DEALLOCATE(kp, help, nbins_, stat=err)
+    IF (err /= 0) THEN
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(help, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+    END IF
+    arrayToReal_r8r16 = rreal
+
+  END FUNCTION arrayToReal_r8r16
+
+
+
+
+
+  INTEGER FUNCTION imaxloc_i4(array)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imax
+
+    imax = MAXLOC(array)
+    imaxloc_i4 = imax(1)
+
+  END FUNCTION imaxloc_i4
+
+
+
+
+
+  INTEGER FUNCTION imaxloc_i8(array)
+
+    IMPLICIT NONE
+    INTEGER(iprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imax
+
+    imax = MAXLOC(array)
+    imaxloc_i8 = imax(1)
+
+  END FUNCTION imaxloc_i8
+
+
+
+
+
+  INTEGER FUNCTION imaxloc_r4(array)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imax
+
+    imax = MAXLOC(array)
+    imaxloc_r4 = imax(1)
+
+  END FUNCTION imaxloc_r4
+
+
+
+
+
+  INTEGER FUNCTION imaxloc_r8(array)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imax
+
+    imax = MAXLOC(array)
+    imaxloc_r8 = imax(1)
+
+  END FUNCTION imaxloc_r8
+
+
+
+
+
+  INTEGER FUNCTION imaxloc_r16(array)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imax
+
+    imax = MAXLOC(array)
+    imaxloc_r16 = imax(1)
+
+  END FUNCTION imaxloc_r16
+
+
+
+
+
+  INTEGER FUNCTION iminloc_i4(array)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imin
+
+    imin = MINLOC(array)
+    iminloc_i4 = imin(1)
+
+  END FUNCTION iminloc_i4
+
+
+
+
+
+  INTEGER FUNCTION iminloc_i8(array)
+
+    IMPLICIT NONE
+    INTEGER(iprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imin
+
+    imin = MINLOC(array)
+    iminloc_i8 = imin(1)
+
+  END FUNCTION iminloc_i8
+
+
+
+
+
+  INTEGER FUNCTION iminloc_r4(array)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imin
+
+    imin = MINLOC(array)
+    iminloc_r4 = imin(1)
+
+  END FUNCTION iminloc_r4
+
+
+
+
+
+  INTEGER FUNCTION iminloc_r8(array)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imin
+
+    imin = MINLOC(array)
+    iminloc_r8 = imin(1)
+
+  END FUNCTION iminloc_r8
+
+
+
+
+
+  INTEGER FUNCTION iminloc_r16(array)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), INTENT(in) :: array
+    INTEGER, DIMENSION(1) :: imin
+
+    imin = MINLOC(array)
+    iminloc_r16 = imin(1)
+
+  END FUNCTION iminloc_r16
+
+
+
+
+
+  FUNCTION integerToArray_ri8(intgr, elements, bin_size, nbins, bounds, error)
+
+    IMPLICIT NONE
+    INTEGER(iprec8), INTENT(in)              :: intgr    ! input integer
+    LOGICAL, DIMENSION(:), INTENT(in)        :: elements ! used elements
+    REAL(rprec8), DIMENSION(:), INTENT(in)   :: bin_size ! bin sizes
+    INTEGER, DIMENSION(:), INTENT(in)        :: nbins     ! number of bins
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: bounds   ! variable bounds
+    LOGICAL, INTENT(out)                     :: error
+    REAL(rprec8), DIMENSION(SIZE(elements))  :: integerToArray_ri8
+
+    INTEGER(iprec8)                    :: intgr_coeff, bins_coeff
+    INTEGER, DIMENSION(:), ALLOCATABLE :: kp, nbins_
+    INTEGER                            :: ncolumn, i, j, k, err
+
+    ! Make an index (help) of the elements that are used:
+    ncolumn = COUNT(elements)
+    ALLOCATE(kp(ncolumn), nbins_(ncolumn), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+    j = 0
+    DO i=1,SIZE(elements)
+       IF (elements(i)) THEN
+          j = j + 1
+          nbins_(j) = nbins(i)
+       END IF
+    END DO
+
+    ! Transform integer to bin coordinates
+    ! (size(kp) == size(help)):
+    bins_coeff = 1_rprec8
+    DO i=ncolumn, 1, -1
+       intgr_coeff = intgr
+       DO j=i+1, ncolumn
+          bins_coeff = 1_rprec8
+          DO k=1,j-1
+             bins_coeff = bins_coeff*INT(nbins_(k),rprec8)
+          END DO
+          intgr_coeff = intgr_coeff - INT((kp(j)-1)*bins_coeff,rprec8)
+       END DO
+       bins_coeff = 1_rprec8
+       DO j=1,i-1
+          bins_coeff = bins_coeff*INT(nbins_(j),rprec8)
+       END DO
+       kp(i) = 1 + INT(intgr_coeff/REAL(bins_coeff),iprec4)
+    END DO
+    kp(1) = kp(1) - 1
+
+    ! Transform bin coordinates to real values: 
+    j = 0
+    DO i=1,SIZE(elements)
+       IF (elements(i)) THEN
+          j = j + 1
+          integerToArray_ri8(i) = bounds(i,1) + kp(j)*bin_size(i)
+       ELSE
+          integerToArray_ri8(i) = -1.0_rprec8
+       END IF
+    END DO
+
+    DEALLOCATE(kp, nbins_, stat=err)
+    IF (err /= 0) THEN
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+    END IF
+
+  END FUNCTION integerToArray_ri8
+
+
+
+
+
+  LOGICAL FUNCTION is_downcase(d)
+
+    ! Description:
+    !
+    ! This function returns TRUE if the character 'd' is a lowercase letter.
+    ! It returns FALSE otherwise.
+    !
+    ! Programming interface:
+    !
+    ! Name         In/out  Type          Structure  Meaning
+    !
+    ! is_downcase  out     logical       scalar     TRUE if d is lowercase letter 
+    !                                               FALSE otherwise
+    ! d            in      character(1)  scalar     The character to be examined
+    !
+    ! Errors:
+    !
+    ! No errors should occur and none are trapped.
+    ! This routine assumes the ASCII character set.
+
+    IMPLICIT NONE
+    CHARACTER(len=1) :: d
+
+    is_downcase = ((d >= 'a') .AND. (d <= 'z'))
+
+  END FUNCTION is_downcase
+
+
+
+
+
+  FUNCTION outerand(a,b)
+
+    IMPLICIT NONE
+    LOGICAL, DIMENSION(:), INTENT(IN) :: a,b
+    LOGICAL, DIMENSION(SIZE(a),SIZE(b)) :: outerand
+
+    outerand = SPREAD(a,dim=2,ncopies=SIZE(b)) .AND. &
+         SPREAD(b,dim=1,ncopies=SIZE(a))
+
+  END FUNCTION outerand
+
+
+
+
+
+  FUNCTION realToArray_r16r8(rreal, elements, bin_size, nbins, bounds, error)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(in)               :: rreal    ! input integer (real)
+    LOGICAL, DIMENSION(:), INTENT(in)      :: elements ! used elements
+    REAL(rprec8), DIMENSION(:), INTENT(in)   :: bin_size ! bin sizes
+    INTEGER, DIMENSION(:), INTENT(in)      :: nbins     ! number of bins
+    REAL(rprec8), DIMENSION(:,:), INTENT(in) :: bounds   ! variable bounds
+    LOGICAL, INTENT(out)                   :: error
+    REAL(rprec8), DIMENSION(:), POINTER      :: realToArray_r16r8
+    REAL(rprec16)                          :: rreal_coeff, bins_coeff
+    INTEGER, DIMENSION(:), ALLOCATABLE     :: kp, nbins_
+    INTEGER                                :: ncolumn, i, j, k, err
+
+    ! Make an index (help) of the elements that are used:
+    ncolumn = COUNT(elements)
+    ALLOCATE(realToArray_r16r8(SIZE(elements)), kp(ncolumn), &
+         nbins_(ncolumn), stat=err)
+    IF (err /= 0) THEN
+       error = .TRUE.
+       DEALLOCATE(realToArray_r16r8, stat=err)
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+       RETURN
+    END IF
+    j = 0
+    DO i=1,SIZE(elements)
+       IF (elements(i)) THEN
+          j = j + 1
+          nbins_(j) = nbins(i)
+       END IF
+    END DO
+
+    ! Transform integer to bin coordinates
+    ! (size(kp) == size(help)):
+    bins_coeff = 1.0_rprec16
+    DO i=ncolumn, 1, -1
+       rreal_coeff = rreal
+       DO j=i+1, ncolumn
+          bins_coeff = 1.0_rprec16
+          DO k=1,j-1
+             bins_coeff = bins_coeff*REAL(nbins_(k),rprec16)
+          END DO
+          rreal_coeff = rreal_coeff - REAL((kp(j)-1)*bins_coeff,rprec16)
+       END DO
+       bins_coeff = 1.0_rprec16
+       DO j=1,i-1
+          bins_coeff = bins_coeff*REAL(nbins_(j),rprec16)
+       END DO
+       kp(i) = 1 + INT(rreal_coeff/bins_coeff,iprec4)
+    END DO
+    kp(1) = kp(1) - 1
+
+    ! Transform bin coordinates to real values: 
+    j = 0
+    DO i=1,SIZE(elements)
+       IF (elements(i)) THEN
+          j = j + 1
+          realToArray_r16r8(i) = bounds(i,1) + kp(j)*bin_size(i)
+       ELSE
+          realToArray_r16r8(i) = -1.0_rprec8
+       END IF
+    END DO
+
+    DEALLOCATE(kp, nbins_, stat=err)
+    IF (err /= 0) THEN
+       DEALLOCATE(kp, stat=err)
+       DEALLOCATE(nbins_, stat=err)
+    END IF
+
+  END FUNCTION realToArray_r16r8
+
+
+
+
+
+  FUNCTION reallocate_ch_1(array,n)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), DIMENSION(:), POINTER :: array
+    CHARACTER(len=LEN(array(1))), DIMENSION(:), POINTER :: reallocate_ch_1
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_ch_1(n))
+    reallocate_ch_1 = " "
+    IF (ASSOCIATED(array)) THEN
+       nold = SIZE(array, dim=1)
+       reallocate_ch_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+       DEALLOCATE(array)
+    END IF
+
+  END FUNCTION reallocate_ch_1
+
+
+
+
+
+  FUNCTION reallocate_ch_2(array,n,m)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), DIMENSION(:,:), POINTER :: array
+    CHARACTER(len=LEN(array(1,1))), DIMENSION(:,:), POINTER :: reallocate_ch_2
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold, i, j
+
+    ALLOCATE(reallocate_ch_2(n,m))
+    reallocate_ch_2 = " "
+    IF (.NOT. ASSOCIATED(array)) THEN
+       RETURN
+    END IF
+    nold = SIZE(array, dim=1)
+    mold = SIZE(array, dim=2)
+    DO i=1,MIN(n,nold)
+       DO j=1,MIN(m,mold)
+          reallocate_ch_2(i,j) = array(i,j)
+       END DO
+    END DO
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_ch_2
+
+
+
+
+
+  FUNCTION reallocate_ch18_1(array,n)
+
+    IMPLICIT NONE
+    CHARACTER(len=18), DIMENSION(:), POINTER :: reallocate_ch18_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_ch18_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array, dim=1)
+    reallocate_ch18_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_ch18_1
+
+
+
+
+
+  FUNCTION reallocate_ch24_1(array,n)
+
+    IMPLICIT NONE
+    CHARACTER(len=24), DIMENSION(:), POINTER :: reallocate_ch24_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_ch24_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array, dim=1)
+    reallocate_ch24_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_ch24_1
+
+
+
+
+
+  FUNCTION reallocate_i1_1(array,n)
+
+    IMPLICIT NONE
+    INTEGER(iprec1), DIMENSION(:), POINTER :: reallocate_i1_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_i1_1(n))
+    IF (ASSOCIATED(array)) THEN
+       nold = SIZE(array, dim=1)
+       reallocate_i1_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+       DEALLOCATE(array)
+    END IF
+
+  END FUNCTION reallocate_i1_1
+
+
+
+
+
+  FUNCTION reallocate_i4_1(array,n)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:), POINTER :: reallocate_i4_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_i4_1(n))
+    IF (ASSOCIATED(array)) THEN
+       nold = SIZE(array, dim=1)
+       reallocate_i4_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+       DEALLOCATE(array)
+    END IF
+
+  END FUNCTION reallocate_i4_1
+
+
+
+
+
+  FUNCTION reallocate_i4_2(array,n,m)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), DIMENSION(:,:), POINTER :: reallocate_i4_2, array
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold
+
+    ALLOCATE(reallocate_i4_2(n,m))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,1)
+    mold = SIZE(array,2)
+    reallocate_i4_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+         array(1:MIN(n,nold),1:MIN(m,mold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_i4_2
+
+
+
+
+
+  FUNCTION reallocate_i8_1(array,n)
+
+    IMPLICIT NONE
+    INTEGER(rprec8), DIMENSION(:), POINTER :: reallocate_i8_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_i8_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    reallocate_i8_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_i8_1
+
+
+
+
+
+  FUNCTION reallocate_i8_2(array,n,m)
+
+    IMPLICIT NONE
+    INTEGER(rprec8), DIMENSION(:,:), POINTER :: reallocate_i8_2, array
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold
+
+    ALLOCATE(reallocate_i8_2(n,m))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,1)
+    mold = SIZE(array,2)
+    reallocate_i8_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+         array(1:MIN(n,nold),1:MIN(m,mold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_i8_2
+
+
+
+
+
+  FUNCTION reallocate_r4_1(array,n)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:), POINTER :: reallocate_r4_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_r4_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    reallocate_r4_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_r4_1
+
+
+
+
+
+  FUNCTION reallocate_r4_2(array,n,m)
+
+    IMPLICIT NONE
+    REAL(rprec4), DIMENSION(:,:), POINTER :: reallocate_r4_2, array
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold
+
+    ALLOCATE(reallocate_r4_2(n,m))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,1)
+    mold = SIZE(array,2)
+    reallocate_r4_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+         array(1:MIN(n,nold),1:MIN(m,mold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_r4_2
+
+
+
+
+
+  FUNCTION reallocate_r8_1(array,n)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), POINTER :: reallocate_r8_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_r8_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    reallocate_r8_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_r8_1
+
+
+
+
+
+  FUNCTION reallocate_r8_2(array,n,m,nmask)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:), POINTER :: reallocate_r8_2, array
+    INTEGER, INTENT(in) :: n, m
+    LOGICAL, DIMENSION(:), INTENT(in), OPTIONAL :: nmask
+    INTEGER :: i, in, nold, mold
+
+    ALLOCATE(reallocate_r8_2(n,m))
+    IF (ASSOCIATED(array) .AND. .NOT.PRESENT(nmask)) THEN
+       nold = SIZE(array,1)
+       mold = SIZE(array,2)
+       reallocate_r8_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+            array(1:MIN(n,nold),1:MIN(m,mold))
+       DEALLOCATE(array)
+    ELSE IF (ASSOCIATED(array) .AND. PRESENT(nmask)) THEN
+       in = 0
+       DO i=1,nold
+          IF (in == n) THEN
+             EXIT
+          END IF
+          IF (nmask(i)) THEN
+             in = in + 1
+             reallocate_r8_2(in,1:MIN(m,mold)) = array(i,1:MIN(m,mold))
+          END IF
+       END DO
+       DEALLOCATE(array)
+    END IF
+
+  END FUNCTION reallocate_r8_2
+
+
+
+
+
+  FUNCTION reallocate_r8_3(array,n,m,o)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:,:,:), POINTER :: reallocate_r8_3, array
+    INTEGER, INTENT(in) :: n, m, o
+    INTEGER :: nold, mold, oold
+
+    ALLOCATE(reallocate_r8_3(n,m,o))
+    IF (ASSOCIATED(array)) THEN
+       nold = SIZE(array,1)
+       mold = SIZE(array,2)
+       oold = SIZE(array,3)
+       reallocate_r8_3(1:MIN(n,nold),1:MIN(m,mold),1:MIN(o,oold)) = &
+            array(1:MIN(n,nold),1:MIN(m,mold),1:MIN(o,oold))
+       DEALLOCATE(array)
+    END IF
+
+  END FUNCTION reallocate_r8_3
+
+
+
+
+
+  FUNCTION reallocate_r16_1(array,n)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:), POINTER :: reallocate_r16_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_r16_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    reallocate_r16_1(1:MIN(n,nold)) = array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_r16_1
+
+
+
+
+
+  FUNCTION reallocate_r16_2(array,n,m)
+
+    IMPLICIT NONE
+    REAL(rprec16), DIMENSION(:,:), POINTER :: reallocate_r16_2, array
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold
+
+    ALLOCATE(reallocate_r16_2(n,m))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,1)
+    mold = SIZE(array,2)
+    reallocate_r16_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+         array(1:MIN(n,nold),1:MIN(m,mold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_r16_2
+
+
+
+
+
+  FUNCTION reallocate_l_1(array,n)
+
+    IMPLICIT NONE
+    LOGICAL, DIMENSION(:), POINTER :: reallocate_l_1, array
+    INTEGER, INTENT(in) :: n
+    INTEGER :: nold
+
+    ALLOCATE(reallocate_l_1(n))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array)
+    reallocate_l_1(1:MIN(n,nold)) = &
+         array(1:MIN(n,nold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_l_1
+
+
+
+
+
+  FUNCTION reallocate_l_2(array,n,m)
+
+    IMPLICIT NONE
+    LOGICAL, DIMENSION(:,:), POINTER :: reallocate_l_2, array
+    INTEGER, INTENT(in) :: n, m
+    INTEGER :: nold, mold
+
+    ALLOCATE(reallocate_l_2(n,m))
+    IF (.NOT. ASSOCIATED(array)) RETURN
+    nold = SIZE(array,dim=1)
+    mold = SIZE(array,dim=2)
+    reallocate_l_2(1:MIN(n,nold),1:MIN(m,mold)) = &
+         array(1:MIN(n,nold),1:MIN(m,mold))
+    DEALLOCATE(array)
+
+  END FUNCTION reallocate_l_2
+
+
+
+
+
+  SUBROUTINE removeLeadingBlanks(str)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: str
+
+    DO WHILE (INDEX(TRIM(str),CHAR(0)) == 1 .OR. &
+         INDEX(TRIM(str),CHAR(32)) == 1)
+       str(1:LEN_TRIM(str)) = str(2:LEN_TRIM(str)) // CHAR(32)
+    END DO
+
+  END SUBROUTINE removeLeadingBlanks
+
+
+
+
+
+!!$  FUNCTION TRIM(str_in) RESULT(str_out)
+!!$
+!!$    IMPLICIT NONE
+!!$    CHARACTER(len=*), INTENT(in) :: str_in
+!!$    CHARACTER(len=LEN_TRIM(str_in)) :: str_out
+!!$
+!!$    str_out = str_in(1:LEN_TRIM(str_in))
+!!$
+!!$  END FUNCTION trim
+
+
+
+
+
+  CHARACTER(len=64) FUNCTION secToHMS_r4(sec, error)
+
+    IMPLICIT NONE
+    REAL(rprec4), INTENT(in)    :: sec
+    LOGICAL, INTENT(inout) :: error
+    CHARACTER(len=16)      :: str
+    INTEGER                :: h, min, ind
+
+    secToHMS_r4 = ' '
+    ! Hours:
+    h = FLOOR(sec/3600.0_4)
+    IF (h /= 0) THEN
+       CALL toString(h, str, error)
+       secToHMS_r4 = TRIM(secToHMS_r4) // TRIM(str) // 'h '
+    END IF
+    ! Minutes:
+    min = FLOOR((sec - h*3600.0_4)/60.0_4)
+    IF (min /= 0 .OR. h /= 0) THEN
+       CALL toString(min, str, error)
+       secToHMS_r4 = TRIM(secToHMS_r4) // TRIM(str) // 'min '
+    END IF
+    ! Seconds with 3 decimals:
+    CALL toString((sec-h*3600.0_4-min*60.0_4), str, error)
+    ind = INDEX(str,'.') + 6
+    secToHMS_r4 = TRIM(secToHMS_r4) // str(1:ind) // 'sec'
+
+  END FUNCTION secToHMS_r4
+
+
+
+
+
+  CHARACTER(len=64) FUNCTION secToHMS_r8(sec, error)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)    :: sec
+    LOGICAL, INTENT(inout) :: error
+    CHARACTER(len=32)      :: str
+    INTEGER                :: h, min, ind
+
+    secToHMS_r8 = ' '
+    ! Hours:
+    h = FLOOR(sec/3600.0_rprec8)
+    IF (h /= 0) THEN
+       CALL toString(h, str, error)
+       secToHMS_r8 = TRIM(secToHMS_r8) // TRIM(str) // 'h '
+    END IF
+    ! Minutes:
+    min = FLOOR((sec - h*3600.0_rprec8)/60.0_rprec8)
+    IF (min /= 0 .OR. h /= 0) THEN
+       CALL toString(min, str, error)
+       secToHMS_r8 = TRIM(secToHMS_r8) // TRIM(str) // 'min '
+    END IF
+    ! Seconds with 3 decimals:
+    CALL toString((sec-h*3600.0_rprec8-min*60.0_rprec8), str, error)
+    ind = INDEX(str,'.') + 6
+    secToHMS_r8 = TRIM(secToHMS_r8) // str(1:ind) // 'sec'
+
+  END FUNCTION secToHMS_r8
+
+
+
+
+
+  SUBROUTINE swap_i4(first, second, mask)
+
+    IMPLICIT NONE
+    INTEGER(iprec4), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    INTEGER(iprec4) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_i4
+
+
+
+
+
+  SUBROUTINE swap_i8(first, second, mask)
+
+    IMPLICIT NONE
+    INTEGER(iprec8), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    INTEGER(iprec8) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_i8
+
+
+
+
+
+  SUBROUTINE swap_scalar_r8(first, second, mask)
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    REAL(rprec8) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_scalar_r8
+
+
+
+
+
+  SUBROUTINE swap_vector_r8(first, second, mask)
+
+    IMPLICIT NONE
+    REAL(rprec8), DIMENSION(:), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    REAL(rprec8), DIMENSION(SIZE(first,dim=1)) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_vector_r8
+
+
+
+
+
+  SUBROUTINE swap_r16(first, second, mask)
+
+    IMPLICIT NONE
+    REAL(rprec16), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    REAL(rprec16) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_r16
+
+
+
+
+
+  SUBROUTINE swap_ch(first, second, mask)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: first, second
+    LOGICAL, OPTIONAL, INTENT(in) :: mask
+    CHARACTER(len=MAX(LEN(first),LEN(second))) :: dum
+
+    IF (PRESENT(mask)) THEN
+       IF (mask) THEN
+          dum = first
+          first = second
+          second = dum
+       END IF
+    ELSE
+       dum = first
+       first = second
+       second = dum
+    END IF
+
+  END SUBROUTINE swap_ch
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Converts a string to a integer(4) number. An error is reported if
+  !! the string cannot be converted to number.
+  !!
+  SUBROUTINE toInt_4(str, k, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in) :: str
+    INTEGER(iprec4), INTENT(out) :: k
+    LOGICAL, INTENT(inout)       :: error
+    INTEGER                      :: err
+
+    READ(str,'(I30)',iostat=err) k
+    IF (err /= 0) THEN
+       error = .TRUE.
+    END IF
+
+  END SUBROUTINE toInt_4
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Converts a string to a real(prec8) number. An error is reported if
+  !! the string cannot be converted to number.
+  !!
+  SUBROUTINE toReal_8(str, r, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)   :: str
+    REAL(rprec8), INTENT(out)        :: r
+    LOGICAL, INTENT(inout)         :: error
+    CHARACTER(len=LEN_TRIM(str)+2) :: lstr
+    REAL(rprec8)                     :: plusminus
+    INTEGER                        :: err
+
+    plusminus = 1.0_rprec8
+
+    lstr = TRIM(str)
+    IF (INDEX(lstr, '+') == 1) THEN
+       lstr = lstr(2:LEN_TRIM(lstr)) 
+    ELSE IF (INDEX(lstr, '-') == 1) THEN
+       plusminus = -1.0_rprec8
+       lstr = lstr(2:LEN_TRIM(lstr)) 
+    END IF
+    IF (INDEX(str, '.') == 0) lstr = TRIM(str) // '.0'
+    READ(lstr, '(F35.16)', iostat=err) r
+    IF (err /= 0) THEN
+       error = .TRUE.
+    END IF
+    r = plusminus * r
+
+  END SUBROUTINE toReal_8
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! Converts a string to a real(16) number. An error is reported if
+  !! the string cannot be converted to number.
+  !!
+  SUBROUTINE toReal_16(str, r, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in)   :: str
+    REAL(rprec16), INTENT(out)        :: r
+    LOGICAL, INTENT(inout)         :: error
+    CHARACTER(len=LEN_TRIM(str)+2) :: lstr
+    REAL(rprec16)                     :: plusminus
+    INTEGER                        :: err
+
+    plusminus = 1.0_rprec16
+
+    lstr = TRIM(str) 
+    IF (INDEX(lstr, '+') == 1) THEN
+       lstr = lstr(2:LEN_TRIM(lstr)) 
+    ELSE IF (INDEX(lstr, '-') == 1) THEN
+       plusminus = -1.0_rprec16
+       lstr = lstr(2:LEN_TRIM(lstr)) 
+    END IF
+    IF (INDEX(str, '.') == 0) lstr = TRIM(str) // '.0' 
+    READ(lstr, '(F64.32)', iostat=err) r
+    IF (err /= 0) THEN
+       error = .TRUE.
+    END IF
+    r = plusminus * r
+
+  END SUBROUTINE toReal_16
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This subroutine returns the input string with all the lowercase
+  !! letters converted to uppercase letters.
+  !!
+  SUBROUTINE upcase(str)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: str
+    INTEGER :: i, limit
+
+    limit = LEN_TRIM(str)
+    DO i=1,limit
+       IF ((str(i:i) >= 'a') .AND. (str(i:i) <= 'z')) THEN
+          str(i:i) = CHAR(ICHAR(str(i:i))-32)
+       END IF
+    END DO
+
+  END SUBROUTINE upcase
+
+
+
+
+
+  !! *Description*:
+  !!
+  !! This subroutine returns the input string with all the uppercase
+  !! letters converted to lowercase letters.
+  !!
+  SUBROUTINE locase(str, error)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(inout) :: str
+    LOGICAL, INTENT(inout) :: error
+    INTEGER :: i, limit, ilo, ihi
+
+    limit = LEN(str)
+    ilo = IACHAR('A')
+    ihi = IACHAR('Z')
+    DO i=1,limit
+       IF (IACHAR(str(i:i)) > 127 .OR. IACHAR(str(i:i)) < 0) THEN
+          error = .TRUE.
+          RETURN
+       END IF
+       IF (IACHAR(str(i:i)) >= ilo .AND. IACHAR(str(i:i)) <= ihi) THEN
+          str(i:i) = CHAR(ICHAR(str(i:i))+32)
+       END IF
+    END DO
+
+  END SUBROUTINE locase
+
+
+
+
+
+  !!
+  !!
+  SUBROUTINE toString_i4(k, str, error)
+
+    ! Description:
+    !
+    ! This routine converts an integer number to a string.
+    !
+    ! Programming interface:
+    !
+    ! Name   In/Out  Type       Structure  Meaning
+    ! 
+    ! str    out    character  Scalar     The string
+    ! k      in     integer(4) Scalar     The integer number to be converted
+    ! error  inout  logical    Scalar     Set TRUE if an error occurs
+    !
+    ! Errors:
+    !
+    ! An error is reported if the number cannot be converted to an integer.
+
+    IMPLICIT NONE
+    INTEGER(iprec4), INTENT(in)   :: k
+    CHARACTER(len=*), INTENT(out) :: str
+    LOGICAL, INTENT(inout)        :: error
+    INTEGER                       :: err
+
+    WRITE(str,'(I0)',iostat=err) k
+    IF (err /= 0) THEN
+       error = .TRUE.
+       str = '***** Error in utilities / toString *****'
+    END IF
+
+  END SUBROUTINE toString_i4
+
+
+
+
+
+  !!
+  !!
+  SUBROUTINE toString_i8(k, str, error)
+
+    ! Description:
+    !
+    ! This routine converts an integer number to a string.
+    !
+    ! Programming interface:
+    !
+    ! Name   In/Out  Type       Structure  Meaning
+    ! 
+    ! str    out    character  Scalar     The string
+    ! k      in     integer(4) Scalar     The integer number to be converted
+    ! error  inout  logical    Scalar     Set TRUE if an error occurs
+    !
+    ! Errors:
+    !
+    ! An error is reported if the number cannot be converted to an integer.
+
+    IMPLICIT NONE
+    INTEGER(iprec8), INTENT(in)   :: k
+    CHARACTER(len=*), INTENT(out) :: str
+    LOGICAL, INTENT(inout)        :: error
+    INTEGER                       :: err
+
+    WRITE(str,'(I0)',iostat=err) k
+    IF (err /= 0) THEN
+       error = .TRUE.
+       str = '***** Error in utilities / toString *****'
+    END IF
+
+  END SUBROUTINE toString_i8
+
+
+
+
+
+  !!
+  !!
+  SUBROUTINE toString_r4(r, str, error, frmt)
+
+    ! Description:
+    !
+    ! This routine converts a real number to a string.
+    !
+    ! Programming interface:
+    !
+    ! Name   In/Out  Type       Structure  Meaning
+    ! 
+    ! str    out    character  Scalar     The string
+    ! r4     in     real(4)    Scalar     The real number to be converted
+    ! error  inout  logical    Scalar     Set TRUE if an error occurs
+    !
+    ! Errors:
+    !
+    ! An error message is written to the output string, if the number
+    ! cannot be converted to an integer.
+
+    IMPLICIT NONE
+    REAL(rprec4), INTENT(in)               :: r
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frmt
+    CHARACTER(len=*), INTENT(out)          :: str
+    LOGICAL, INTENT(inout)                 :: error
+
+    INTEGER :: err
+
+    IF (PRESENT(frmt)) THEN
+       WRITE(str,TRIM(frmt),iostat=err) r
+    ELSE
+       WRITE(str,'(F0.8)',iostat=err) r
+    END IF
+    IF (err /= 0) THEN
+       error = .TRUE.
+       str = '***** Error in utilities / toString *****'
+    END IF
+    CALL removeLeadingBlanks(str)
+
+  END SUBROUTINE toString_r4
+
+
+
+
+
+  !!
+  !!
+  SUBROUTINE toString_r8(r, str, error, frmt)
+
+    ! Description:
+    !
+    ! This routine converts a real number to a string.
+    !
+    ! Programming interface:
+    !
+    ! Name   In/Out  Type       Structure  Meaning
+    ! 
+    ! str    out    character  Scalar     The string (len > 19)
+    ! r4     in     real(8)    Scalar     The real number to be converted
+    ! error  inout  logical    Scalar     Set TRUE if an error occurs
+    !
+    ! Errors:
+    !
+    ! An error message is written to the output string, if the number
+    ! cannot be converted to an integer.
+
+    IMPLICIT NONE
+    REAL(rprec8), INTENT(in)               :: r
+    CHARACTER(len=*), INTENT(out)          :: str
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: frmt
+    LOGICAL, INTENT(inout)                 :: error
+
+    INTEGER :: err
+
+    IF (PRESENT(frmt)) THEN
+       WRITE(str,TRIM(frmt),iostat=err) r
+    ELSE
+       WRITE(str,'(F0.16)',iostat=err) r
+    END IF
+    IF (err /= 0) THEN
+       error = .TRUE.
+       str = '***** Error in utilities / toString *****'
+    END IF
+    str = ADJUSTL(str)
+
+  END SUBROUTINE toString_r8
+
+
+
+
+
+END MODULE utilities
Index: trunk/mops/oorb/python/Makefile
===================================================================
--- trunk/mops/oorb/python/Makefile	(revision 34646)
+++ trunk/mops/oorb/python/Makefile	(revision 34646)
@@ -0,0 +1,79 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+# M. Granvik
+
+include ../make.config
+include ../Makefile.include
+
+all: liboorb.$(LIBEXT)
+
+liboorb.o: liboorb.f90
+	$(FC) -c $(FCOPTIONS) $(FC_INC)../$(CLASSPATH) \
+	$(FC_INC)../$(MODULEPATH) $(FC_INC)../main liboorb.f90
+
+wrapper.o: wrapper.f90 liboorb.o
+	$(FC) -c $(FCOPTIONS) $(FC_INC)../$(CLASSPATH) \
+	$(FC_INC)../$(MODULEPATH) \
+	$(FC_INC)../main \
+	wrapper.f90
+
+liboorb.$(LIBEXT): modules classes main wrapper.o liboorb.o
+	$(FC) $(FCOPTIONS) -shared -o liboorb.$(LIBEXT) \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH) \
+	liboorb.o wrapper.o \
+	../main/io.o \
+	../$(CLASSPATH)/*.o \
+	../$(MODULEPATH)/*.o
+
+pyoorb: liboorb
+	f2py2.6 -m pyoorb pyoorb.f90 --build-dir ./build -c --noarch -loorb -L../lib \
+	--f90exec=$(FC) --f90flags="$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH)" 
+
+pyoorb.o: liboorb
+	$(FC) -c $(FCOPTIONS) pyoorb.f90 $(FC_INC)../$(MAINPATH) \
+	$(FC_INC)../$(CLASSPATH) $(FC_INC)../$(MODULEPATH)
+
+liboorb:
+	cd ../$(LIBPATH) ; make
+
+test: test.f90 pyoorb.o
+	$(FC) $(FCOPTIONS) pyoorb.o -loorb -L../lib test.f90 -o test
+
+
+
+main:
+	cd ../main/ ; make io.o
+
+classes:
+	cd ../$(CLASSPATH) ; $(MAKE) all
+
+modules:
+	cd ../$(MODULEPATH) ; $(MAKE) all
+
+
+# Remove library and modules:
+clean:
+	rm -fr build *~ *.mod *.o \
+	*.so *.dylib *.$(LIBEXT) *.pyc *.pyc.$(OS) \
+	test
+
Index: trunk/mops/oorb/python/README
===================================================================
--- trunk/mops/oorb/python/README	(revision 34646)
+++ trunk/mops/oorb/python/README	(revision 34646)
@@ -0,0 +1,43 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+
+OpenOrb Python wrappers.
+
+
+To build, cd into this directory and then
+    shell> make clean
+    shell> make
+    shell> python setup.py install
+
+Test by running
+    shell> python api.py
+
+If you get an error from python saying that liboorb cannot be found, copy
+liboorb.so (or liboorb.dylib if you are on a Mac) somewhere in your
+LD_LIBRARY_PATH (or DYLD_LIBRARY_PATH if you are on a Mac).
+
+
+Tested on a Mac OS X system running OSX 10.5.x and gfortran 4.4.x
+
+These wrappers are not in their final version and so they should not be used in
+production software. You have been warned!
Index: trunk/mops/oorb/python/__init__.py
===================================================================
--- trunk/mops/oorb/python/__init__.py	(revision 34646)
+++ trunk/mops/oorb/python/__init__.py	(revision 34646)
@@ -0,0 +1,65 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+"""
+OpenOrb Python Module
+"""
+import os
+
+from api import *
+import constants
+import defaults
+import utils
+
+
+
+# Constants
+__verbosity__ = 0
+__version__ = '1.0a1'
+__author__ = 'F. Pierfederici <fpierfed@gmail.com>'
+__all__ = ('calendardate_to_mjd',
+           'ranging_fast',
+           'ranging',
+           'lsl_fast',
+           'lsl',
+           'propagate_orbit_fast',
+           'propagate_orbit',
+           'ephemeris_fast',
+           'ephemeris',
+           'moid',
+           'classification')
+
+
+# Get the path to the data dir and infer the JPL ephemeris location.
+dataDir = os.environ.get('OORB_DATA', None)
+if(not dataDir):
+    raise(Exception('Please point $OORB_DATA to the OpenOrb data directory.'))
+ephemFilePath = os.path.join(dataDir, 'JPL_ephemeris', 'de405.dat')
+
+# Init the module.
+err = init(ephemFilePath, __verbosity__)
+if(err):
+    raise(Exception('OpenOrb initialization failed with error code %d' %(err)))
+
+
+
+
Index: trunk/mops/oorb/python/api.py
===================================================================
--- trunk/mops/oorb/python/api.py	(revision 34646)
+++ trunk/mops/oorb/python/api.py	(revision 34646)
@@ -0,0 +1,955 @@
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation, Mikael Granvik.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+# M. Granvik <mgranvik@iki.fi>
+#
+import os
+import ctypes
+import ctypes.util
+import numpy
+
+from constants import *
+import utils
+
+
+# Find the oorb library
+libPath = utils.findLibrary('oorb')
+if(not libPath):
+    raise(Exception('Could not find liboorb!'))
+ffi = ctypes.CDLL(libPath)
+
+
+
+
+
+def init(ephemFile, verbosity=0):
+    """
+    Init the oorb module.
+    
+    @param ephemFile: full path of the JPL ephemeris de405.dat file
+    @param verbosity: integer indicating verbosity level. 0=quiet.
+    
+    Return
+    None
+    """
+    # Init the error code.
+    err = ctypes.c_int(0)
+    
+    # Do a simple sanity check in the input.
+    if(not ephemFile):
+        raise(Exception('Bad input.'))
+    if(verbosity < 0):
+        verbosity = 0
+    elif(verbosity > 5):
+        verbosity = 5
+    
+    # Invoke the fortran init function.
+    ffi.oorb_init_(ctypes.c_char_p(ephemFile), 
+                   ctypes.byref(ctypes.c_int(verbosity)), 
+                   ctypes.byref(err),
+                   ctypes.c_int(len(ephemFile)))
+    if(err.value):
+        raise(Exception('Error: oorb_init failed (error=%d)' \
+                        %(err.value)))
+    return
+
+
+
+def calendardate_to_mjd(y, m, d, timescale='TT'):
+    """
+    Convert a calendar date expressed as year, month, day.fraction to MJD.
+    timescale is either UTC, UT1 or TT. Output MJD is TAI
+    
+    @param y: year number
+    @param m: month number
+    @param d: day number
+    @param timescale: either "UTC", "UT1", "TT" or "TAI"
+    
+    Return
+    MJD TAI
+    """
+    # Init.
+    mjd = ctypes.c_double(0.)
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(y < MIN_YEAR or m < 0 or m > 12 or d < 0 or d >= 32 or not timescale):
+        raise(Exception('Bad input.'))
+    
+    # Enter Fortran land.
+    ffi.oorb_calendardate_to_mjd_(ctypes.byref(ctypes.c_int(y)), 
+                                  ctypes.byref(ctypes.c_int(m)), 
+                                  ctypes.byref(ctypes.c_double(d)), 
+                                  ctypes.byref(mjd), 
+                                  ctypes.c_char_p(timescale), 
+                                  ctypes.byref(err), 
+                                  ctypes.c_int(len(timescale)))
+    if(err.value):
+        raise(Exception('Error: oorb_calendardate_to_mjd failed (error=%d)' \
+                        %(err.value)))
+    return(mjd.value)
+
+
+
+def mjdutc_to_mjdtai(mjdIn):
+    """
+    Convert a calendar date expressed as MJD UTC to MJD TAI.
+    
+    @param mjdIn: MJD UTC
+    
+    Return
+    MJD TAI
+    """
+    return(_convertTimescale(mjdIn, fctn=ffi.oorb_mjdutc_to_mjdtai_))
+
+
+
+def mjdtai_to_mjdutc(mjdIn):
+    """
+    Convert a calendar date expressed as MJD TAI to MJD UTC.
+    
+    @param mjdIn: MJD TAI
+    
+    Return
+    MJD UTC
+    """
+    return(_convertTimescale(mjdIn, fctn=ffi.oorb_mjdtai_to_mjdutc_))
+
+
+
+def mjdtt_to_mjdtai(mjdIn):
+    """
+    Convert a calendar date expressed as MJD TT to MJD TAI. Remember that, in 
+    first approximation, TT = TAI + 32.184 seconds.
+    
+    @param mjdIn: MJD TT
+    
+    Return
+    MJD TAI
+    """
+    return(_convertTimescale(mjdIn, fctn=ffi.oorb_mjdtt_to_mjdtai_))
+
+
+
+def mjdtai_to_mjdtt(mjdIn):
+    """
+    Convert a calendar date expressed as MJD TAI to MJD TT. Remember that, in 
+    first approximation, TT = TAI + 32.184 seconds.
+    
+    @param mjdIn: MJD TAI
+    
+    Return
+    MJD TT
+    """
+    return(_convertTimescale(mjdIn, fctn=ffi.oorb_mjdtai_to_mjdtt_))
+
+
+
+def ranging_fast(trackId, coords, mjds, mags, obscodes, filters, elementType, 
+                 numOrbits):
+    """
+    Statistical ranging. Given a track (meaning an ID, coordinates, times, mags,
+    filters, obscodes), produce an orbit cloud of the given size.
+    
+    Use a 2-body dynamical model.
+    
+    
+    @param trackId: track ID. Just a number, really.
+    @param coords: RA, Dec array. RA and Dec in decimal degrees.
+    @param mjds: MJD TAI array
+    @param mags: mag array
+    @param obscodes: obscode array. Obscodes are strings of length 4
+    @param filters: filter array. Filters are strings of length 1
+    @param elementType: desired type of orbital elements: keplerian or cartesian
+    @param numOrbits: number of ranging orbits to generate.
+    
+    Return
+    List of numOrbits flattened orbits. Each orbits is a 15-element array of the
+    form
+        [trackId, *elements, epochMJD, Un-normalized p.d.f., Reduced chi2, 
+         Regularized apr, *Jacobian, elementTypeIdx]
+    where
+        elements is the 6-element orbital element array.
+        Jacobian is the 3-element Jacobian array (diagonal of the 3x3 matrix).
+    """
+    return(_ranging(trackId, 
+                    coords, 
+                    mjds, 
+                    mags, 
+                    obscodes, 
+                    filters, 
+                    elementType, 
+                    numOrbits,
+                    fctn=ffi.oorb_ranging_fast_))
+
+
+
+def ranging(trackId, coords, mjds, mags, obscodes, filters, elementType, 
+            numOrbits):
+    """
+    Statistical ranging. Given a track (meaning an ID, coordinates, times, mags,
+    filters, obscodes), produce an orbit cloud of the given size.
+    
+    Use the full n-body dynamical model.
+    
+    
+    @param trackId: track ID. Just a number, really.
+    @param coords: RA, Dec array. RA and Dec in decimal degrees.
+    @param mjds: MJD TAI array
+    @param mags: mag array
+    @param obscodes: obscode array. Obscodes are strings of length 4
+    @param filters: filter array. Filters are strings of length 1
+    @param elementType: desired type of orbital elements: keplerian or cartesian
+    @param numOrbits: number of ranging orbits to generate.
+    
+    Return
+    List of numOrbits flattened orbits. Each orbits is a 15-element array of the
+    form
+        [trackId, *elements, epochMJD, Un-normalized p.d.f., Reduced chi2, 
+         Regularized apr, *Jacobian, elementTypeIdx]
+    where
+        elements is the 6-element orbital element array.
+        Jacobian is the 3-element Jacobian array (diagonal of the 3x3 matrix).
+    """
+    return(_ranging(trackId, 
+                    coords, 
+                    mjds, 
+                    mags, 
+                    obscodes, 
+                    filters, 
+                    elementType, 
+                    numOrbits,
+                    fctn=ffi.oorb_ranging_))
+
+
+
+def lsl_fast(trackId, coords, mjds, mags, obscodes, filters, rangingOrbits):
+    """
+    Orbital inversion using least squares with linearized covariances, that is, 
+    fixing the resulting shape of the orbital-element pdf to a Gaussian. 
+    
+    Given a track (meaning an ID, coordinates, times, mags, filters, obscodes) 
+    and a cloud of ranging orbits, produce a single orbit. The orbit cloud is a
+    list of lists of the same form as the output of the ranging routines.
+    
+    Use a 2-body dynamical model.
+    
+    
+    @param trackId: track ID. Just a number, really.
+    @param coords: RA, Dec array. RA and Dec in decimal degrees.
+    @param mjds: MJD TAI array
+    @param mags: mag array
+    @param obscodes: obscode array. Obscodes are strings of length 4
+    @param filters: filter array. Filters are strings of length 1
+    @param rangingOrbits: orbit cloud generated by statistical ranging.
+    
+    Return
+    Tuple of the form
+        (orb, cov)
+    where
+        orb is a single flatted orbit of the form
+            [track_id, *elements, epoch, H, G, el_type_index]
+        cov is the 6x6 covariance matrix
+        elements is the 6-element orbital element array of the same type as the
+            ranging orbit cloud elements.
+        el_type_index is an internal index. Leave it alone, unless you know what
+            you are doing.
+    """
+    return(_lsl(trackId, 
+                coords, 
+                mjds, 
+                mags, 
+                obscodes, 
+                filters, 
+                rangingOrbits,
+                fctn=ffi.oorb_lsl_fast_))
+
+
+
+def lsl(trackId, coords, mjds, mags, obscodes, filters, rangingOrbits):
+    """
+    Orbital inversion using least squares with linearized covariances, that is, 
+    fixing the resulting shape of the orbital-element pdf to a Gaussian. 
+    
+    Given a track (meaning an ID, coordinates, times, mags, filters, obscodes) 
+    and a cloud of ranging orbits, produce a single orbit. The orbit cloud is a
+    list of lists of the same form as the output of the ranging routines.
+    
+    Use the full n-body dynamical model.
+    
+    
+    @param trackId: track ID. Just a number, really.
+    @param coords: RA, Dec array. RA and Dec in decimal degrees.
+    @param mjds: MJD TAI array
+    @param mags: mag array
+    @param obscodes: obscode array. Obscodes are strings of length 4
+    @param filters: filter array. Filters are strings of length 1
+    @param rangingOrbits: orbit cloud generated by statistical ranging.
+    
+    Return
+    Tuple of the form
+        (orb, cov)
+    where
+        orb is a single flatted orbit of the form
+            [track_id, *elements, epoch, H, G, el_type_index]
+        cov is the 6x6 covariance matrix
+        elements is the 6-element orbital element array of the same type as the
+            ranging orbit cloud elements.
+        el_type_index is an internal index. Leave it alone, unless you know what
+            you are doing.
+    """
+    return(_lsl(trackId, 
+                coords, 
+                mjds, 
+                mags, 
+                obscodes, 
+                filters, 
+                rangingOrbits,
+                fctn=ffi.oorb_lsl_))
+
+
+
+def propagate_orbit_fast(orb, cov, mjd):
+    """
+    Propagate a single orbit to a given MJD TAI.
+    
+    Use a 2-body dynamical model.
+    
+    
+    @param orb: flattened orbit in the same format as the output of lsl
+    @param cov: covariance 6x6 matrix (same format as lsl)
+    @param mjd: MJD TAI to propagate the input orbit to
+    
+    Return
+    Tuple of the form
+        (newOrb, newCov)
+    where 
+        newOrb is the new propagated orbit
+        newCov is the new propagated 6x6 covariance matrix
+    """
+    return(_propagate_orbit(orb, 
+                            cov, 
+                            mjd,
+                            fctn=ffi.oorb_propagate_orbit_fast_))
+
+
+
+def propagate_orbit(orb, cov, mjd):
+    """
+    Propagate a single orbit to a given MJD TAI.
+    
+    Use the full n-body dynamical model.
+    
+    
+    @param orb: flattened orbit in the same format as the output of lsl
+    @param cov: covariance 6x6 matrix (same format as lsl)
+    @param mjd: MJD TAI to propagate the input orbit to
+    
+    Return
+    Tuple of the form
+        (newOrb, newCov)
+    where 
+        newOrb is the new propagated orbit
+        newCov is the new propagated 6x6 covariance matrix
+    """
+    return(_propagate_orbit(orb, 
+                            cov, 
+                            mjd,
+                            fctn=ffi.oorb_propagate_orbit_))
+
+
+
+def ephemeris_fast(orb, cov, obscode, n, step):
+    """
+    Compute n ephemeris step (fractional) days apart for the given orbit and 
+    covariance matrix at the orbit epoch. To compute ephemeris from an arbitrary
+    MJD, propagate the orbit to that MJD first.
+    
+    Use a 2-body dynamical model.
+    
+    
+    @param orb: flattened orbit in the same format as the output of lsl
+    @param cov: covariance 6x6 matrix (same format as lsl)
+    @param obscode: 4-letter MPC observatory code
+    @param n: number of ephemeris to compute
+    @param step: time separation in fractional days for successive ephemeris
+    
+    Return
+    A list of n ephemeris. Each ephemeris is a list of the form
+        [dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa]
+    where
+        dist is the distance from Earth in AU
+        ra is RA in decimal degrees
+        dec is Dec in decimal degrees
+        mag is the predicted magnitude (NOT COMPUTED YET)
+        mjd is the MJD TAI of the ephemeris
+        raErr is the error on RA (NOT COMPUTED YET)
+        decErr is the error on Dec (NOT COMPUTED YET)
+        smaa is the positional error ellipse semi major axis (NOT COMPUTED YET)
+        smia is the positional error ellipse semi minor axis (NOT COMPUTED YET)
+        pa is the positional error ellipse position angle (NOT COMPUTED YET)
+    """
+    return(_ephemeris(orb, 
+                      cov, 
+                      obscode, 
+                      n, 
+                      step, 
+                      fctn=ffi.oorb_ephemeris_fast_))
+
+
+
+def ephemeris(orb, cov, obscode, n, step):
+    """
+    Compute n ephemeris step (fractional) days apart for the given orbit and 
+    covariance matrix at the orbit epoch. To compute ephemeris from an arbitrary
+    MJD, propagate the orbit to that MJD first.
+    
+    Use the full n-body dynamical model.
+    
+    
+    @param orb: flattened orbit in the same format as the output of lsl
+    @param cov: covariance 6x6 matrix (same format as lsl)
+    @param obscode: 4-letter MPC observatory code
+    @param n: number of ephemeris to compute
+    @param step: time separation in fractional days for successive ephemeris
+    
+    Return
+    A list of n ephemeris. Each ephemeris is a list of the form
+        [dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa]
+    where
+        dist is the distance from Earth in AU
+        ra is RA in decimal degrees
+        dec is Dec in decimal degrees
+        mag is the predicted magnitude (NOT COMPUTED YET)
+        mjd is the MJD TAI of the ephemeris
+        raErr is the error on RA (NOT COMPUTED YET)
+        decErr is the error on Dec (NOT COMPUTED YET)
+        smaa is the positional error ellipse semi major axis (NOT COMPUTED YET)
+        smia is the positional error ellipse semi minor axis (NOT COMPUTED YET)
+        pa is the positional error ellipse position angle (NOT COMPUTED YET)
+    """
+    return(_ephemeris(orb, 
+                      cov, 
+                      obscode, 
+                      n, 
+                      step, 
+                      fctn=ffi.oorb_ephemeris_))
+
+
+
+def moid(orb, cov):
+    """
+    Compute the MOID given an orbit and its covariance matrix.
+    
+    
+    @param orb: flattened orbit in the same format as the output of lsl
+    @param cov: covariance 6x6 matrix (same format as lsl)
+    
+    Return
+    moid
+    """
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(orb == None or cov == None):
+        raise(Exception('Bad input.'))
+    
+    # Allocate space for the output moid: a simple float.
+    moid = ctypes.c_double(-1.)
+    
+    # Enter Fortran land.
+    ffi.oorb_moid_(orb.ctypes.data_as(ctypes.c_void_p),
+                   cov.ctypes.data_as(ctypes.c_void_p),
+                   ctypes.byref(moid),
+                   ctypes.byref(err))
+    if(err.value):
+        raise(Exception('Error: oorb_moid failed (error=%d)' \
+                        %(err.value)))
+    return(moid.value)
+
+
+
+def classification(rangingOrbits):
+    """
+    Compute the likelihood that a given ranging orbit cloud could represent a
+    given asteroid class.
+    
+    
+    @param rangingOrbits: orbit cloud generated by statistical ranging.
+    
+    Return
+    Tuple of the form
+        (asteroid_classes, likelihoods)
+    where
+        asteroid_classes is a list of asteroid class names
+        likelihoods is a list of probability values
+    both lists are ordered so that likelihoods[j] corresponds to 
+    asteroid_classes[j]
+    """
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(rangingOrbits == None):
+        raise(Exception('Bad input.'))
+    
+    # Allocate space for the output weights: a 1-d array of 17 doubles.
+    weights = numpy.zeros(shape=(17,), dtype='d', order='Fortran')
+    
+    # Enter Fortran land.
+    ffi.priv_classification_(rangingOrbits.ctypes.data_as(ctypes.c_void_p),
+                             ctypes.byref(ctypes.c_int(len(rangingOrbits))),
+                             weights.ctypes.data_as(ctypes.c_void_p),
+                             ctypes.byref(err))
+    return(ASTEROID_CLASSES, weights)
+
+
+
+# Internal routines.
+def _ranging(trackId, coords, mjds, mags, obscodes, filters, elementType, 
+            numOrbits, fctn):
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(coords == None or obscodes == None or filters == None or 
+       elementType == None):
+        raise(Exception('Bad input.'))
+    
+    # Make sure that each obscode element is indeed 4-char long and that filters
+    # are 1-char long.
+    obscodes = ['%-4s' %(o[:4]) for o in obscodes]
+    filters = ['%s' %(f[:1]) for f in filters]
+    # And make sure that elementType is 11 char long.
+    elementType = '%-11s' %(elementType[:11])
+    
+    # Allocate space for the output orbits: an array of the form
+    # [[id, elements(0:5), epoch, Un-normalized p.d.f., Reduced chi2, 
+    #   Regularized apr, Jacobian det(0:2), elementTypeIdx], ] with numOrbits elements.
+    rawOrbits = numpy.zeros(shape=(numOrbits, 15), dtype='d', order='Fortran')
+    # orbits = numpy.zeros(shape=(15, numOrbits), dtype='d')
+    mjds = numpy.array(mjds, dtype='d', order='Fortran')
+    mags = numpy.array(mags, dtype='d', order='Fortran')
+    coords = numpy.array(coords, dtype='d', order='Fortran')
+    numCoords = len(mjds)
+    
+    # Enter Fortran land.
+    fctn(ctypes.c_char_p(''.join(obscodes)),
+         ctypes.c_char_p(''.join(filters)),
+         ctypes.byref(ctypes.c_int(trackId)),
+         ctypes.byref(ctypes.c_int(numCoords)),
+         coords.ctypes.data_as(ctypes.c_void_p),
+         mjds.ctypes.data_as(ctypes.c_void_p),
+         mags.ctypes.data_as(ctypes.c_void_p),
+         ctypes.c_char_p(elementType),
+         ctypes.byref(ctypes.c_int(numOrbits)),
+         rawOrbits.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(err),
+         ctypes.c_int(len(elementType)))
+    if(err.value):
+        raise(Exception('Error: %s failed (error=%d)' \
+              %(fctn.__name__[5:-1], err.value)))
+    
+    # Now transpose the array and create a matrix.
+#     for j in range(numOrbits):
+#         for k in range(15):
+#             orbits[j][k]  = rawOrbits[numOrbits*k + j]
+    return(rawOrbits)
+
+
+    
+def _lsl(trackId, coords, mjds, mags, obscodes, filters, rangingOrbits, fctn):
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(coords == None or obscodes == None or filters == None or 
+       rangingOrbits == None):
+        raise(Exception('Bad input.'))
+    
+    # Make sure that each obscode element is indeed 4-char long and that filters
+    # are 1-char long.
+    obscodes = ['%-4s' %(o[:4]) for o in obscodes]
+    filters = ['%-1s' %(f[:1]) for f in filters]
+    
+    # Allocate space for the output orbit: a 1-d array of the form
+    # [track_id, elements(1:6), epoch, H, G, el_type_index]
+    orbit = numpy.zeros(shape=(11,), dtype='d', order='Fortran')
+    # covariance is a 6x6 matrix of doubles:
+    cov = numpy.zeros(shape=(6, 6), dtype='d', order='Fortran')
+    sigmas = numpy.zeros(shape=(6,), dtype='d', order='Fortran')
+    corr = numpy.zeros(shape=(6, 6), dtype='d', order='Fortran')
+    mjds = numpy.array(mjds, dtype='d', order='Fortran')
+    mags = numpy.array(mags, dtype='d', order='Fortran')
+    coords = numpy.array(coords, dtype='d', order='Fortran')
+    numCoords = len(mjds)
+    numOrbits = len(rangingOrbits)
+    
+    # Enter Fortran land.
+    fctn(ctypes.c_char_p(''.join(obscodes)),
+         ctypes.c_char_p(''.join(filters)),
+         ctypes.byref(ctypes.c_int(trackId)),
+         ctypes.byref(ctypes.c_int(numCoords)),
+         coords.ctypes.data_as(ctypes.c_void_p),
+         mjds.ctypes.data_as(ctypes.c_void_p),
+         mags.ctypes.data_as(ctypes.c_void_p),
+         rangingOrbits.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(ctypes.c_int(numOrbits)),
+         orbit.ctypes.data_as(ctypes.c_void_p),
+         cov.ctypes.data_as(ctypes.c_void_p),
+         sigmas.ctypes.data_as(ctypes.c_void_p),
+         corr.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(err))
+    if(err.value):
+        raise(Exception('Error: %s failed (error=%d)' \
+              %(fctn.__name__[5:-1], err.value)))
+    return(orbit, cov)
+
+
+
+def _propagate_orbit(orb, cov, mjd, fctn):
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(orb == None or cov == None or not mjd):
+        raise(Exception('Bad input.'))
+    
+    # Allocate space for the output orbit: a 1-d array of the form
+    # [track_id, elements(1:6), epoch, H, G, el_type_index]
+    newOrbit = numpy.zeros(shape=(11,), dtype='d', order='Fortran')
+    # covariance is a 6x6 matrix of doubles:
+    newCov = numpy.zeros(shape=(6, 6), dtype='d', order='Fortran')
+    newSigmas = numpy.zeros(shape=(6,), dtype='d', order='Fortran')
+    newCorr = numpy.zeros(shape=(6, 6), dtype='d', order='Fortran')
+    
+    # Enter Fortran land.
+    fctn(orb.ctypes.data_as(ctypes.c_void_p),
+         cov.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(ctypes.c_double(mjd)),
+         newOrbit.ctypes.data_as(ctypes.c_void_p),
+         newCov.ctypes.data_as(ctypes.c_void_p),
+         newSigmas.ctypes.data_as(ctypes.c_void_p),
+         newCorr.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(err))
+    if(err.value):
+        raise(Exception('Error: %s failed (error=%d)' \
+              %(fctn.__name__[5:-1], err.value)))
+    return(newOrbit, newCov)
+
+
+
+def _ephemeris(orb, cov, obscode, n, step, fctn):
+    # Init.
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(orb == None or cov == None or not n or not step):
+        raise(Exception('Bad input.'))
+    
+    # Allocate space for the output ephems: a n-d array of the form
+    # [[dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa], ]
+    ephems = numpy.zeros(shape=(n, 10), dtype='d', order='Fortran')
+    
+    # Make sure obscode is 4-char long.
+    obscode = '%-4s' %(obscode[:4])
+    
+    # Enter Fortran land.
+    fctn(orb.ctypes.data_as(ctypes.c_void_p),
+         cov.ctypes.data_as(ctypes.c_void_p),
+         ctypes.c_char_p(obscode),
+         ctypes.byref(ctypes.c_int(n)),
+         ctypes.byref(ctypes.c_double(step)),
+         ephems.ctypes.data_as(ctypes.c_void_p),
+         ctypes.byref(err),
+         ctypes.c_int(len(obscode)))
+    if(err.value):
+        raise(Exception('Error: %s failed (error=%d)' \
+              %(fctn.__name__[5:-1], err.value)))
+    return(ephems)
+
+
+
+def _convertTimescale(mjdIn, fctn):
+    # Init.
+    mjdOut = ctypes.c_double(-1.)
+    err = ctypes.c_int(0)
+    
+    # Simple sanity check.
+    if(not mjdIn):
+        raise(Exception('Bad input.'))
+    
+    # Enter Fortran land.
+    fctn(ctypes.byref(ctypes.c_double(mjdIn)), 
+         ctypes.byref(mjdOut), 
+         ctypes.byref(err))
+    if(err.value):
+        raise(Exception('Error: oorb_calendardate_to_mjd failed (error=%d)' \
+                        %(err.value)))
+    return(mjdOut.value)
+
+
+
+
+
+
+
+
+if(__name__ == '__main__'):
+    import sys
+    # Do not use sys.stdout.write|flush because it confuses the fortran code :-)
+    # print is OK.
+    
+    # All times in/out need to be TAI. The MJD constants used below are UTC and
+    # therefore need to be converted...
+    
+    sys.stdout.write('oorb.init:                        ')
+    ef = os.path.join(os.environ['OORB_DATA'], 'de405.dat')
+    init(ef, verbosity=2)
+    sys.stdout.write('.')
+    sys.stdout.write(' (all tests ok)\n')
+    
+    sys.stdout.write('oorb.calendardate_to_mjd:         ')
+    mjd = calendardate_to_mjd(2008, 5, 31.35234, 'UTC')
+    assert(mjd == mjdtt_to_mjdtai(54617.353094444443))
+    sys.stdout.write('.')
+    mjd = calendardate_to_mjd(2008, 5, 31.39302, 'UTC')
+    assert(mjd == mjdtt_to_mjdtai(54617.393774444448))
+    sys.stdout.write('.')
+    mjd = calendardate_to_mjd(2008, 5, 31.43442, 'UTC')
+    assert(mjd == mjdtt_to_mjdtai(54617.435174444443))
+    sys.stdout.write('.')
+    sys.stdout.write(' (all tests ok)\n')
+    
+    coords = [[253.64316666666659, 8.33333333333333306E-05, 19.381388888888889, 8.33333333333333306E-05],
+              [253.64175000000000, 8.33333333333333306E-05, 19.381833333333333, 8.33333333333333306E-05],
+              [253.64033333333330, 8.33333333333333306E-05, 19.382222222222218, 8.33333333333333306E-05]]
+    mjds = [mjdtt_to_mjdtai(54617.353094444443), 
+            mjdtt_to_mjdtai(54617.393774444448), 
+            mjdtt_to_mjdtai(54617.435174444443)]
+    mags = [23.699999999999999, 
+            23.699999999999999, 
+            23.800000000000001]
+    obscodes = ['568', ] * len(mags)
+    filters = ['r', ] * len(mags)
+        
+    
+    
+    try:
+        rangingOrbits = ranging_fast(0, coords, mjds, mags, obscodes, filters,
+                                'keplerian', 5000)
+        for i in range(10):
+            print(rangingOrbits[i])
+    except:
+        print('ranging failed (which is normal for this data set).')
+        
+
+
+    rangingOrbits = ranging_fast(0, coords, mjds, mags, obscodes, filters,
+                                 'keplerian', 5000)
+    for i in range(10):
+        print(rangingOrbits[i])
+    
+    
+    
+    
+    
+    coords = [[253.64316666666659, 8.3333333333333331e-05, 19.381388888888889, 8.3333333333333331e-05], 
+              [253.64175000000000, 8.3333333333333331e-05, 19.381833333333333, 8.3333333333333331e-05], 
+              [253.64033333333330, 8.3333333333333331e-05, 19.382222222222222, 8.3333333333333331e-05], 
+              [253.37720833333330, 8.3333333333333331e-05, 19.449750000000002, 8.3333333333333331e-05], 
+              [253.37575000000001, 8.3333333333333331e-05, 19.450166666666664, 8.3333333333333331e-05], 
+              [253.34449999999998, 8.3333333333333331e-05, 19.456777777777777, 8.3333333333333331e-05], 
+              [252.87362500000003, 8.3333333333333331e-05, 19.518361111111112, 8.3333333333333331e-05], 
+              [252.87212500000004, 8.3333333333333331e-05, 19.518388888888889, 8.3333333333333331e-05], 
+              [252.84200000000004, 8.3333333333333331e-05, 19.519861111111108, 8.3333333333333331e-05], 
+              [252.84029166666667, 8.3333333333333331e-05, 19.519944444444445, 8.3333333333333331e-05], 
+              [252.42179166666665, 8.3333333333333331e-05, 19.507138888888889, 8.3333333333333331e-05], 
+              [252.42158333333333, 8.3333333333333331e-05, 19.507111111111112, 8.3333333333333331e-05], 
+              [252.42124999999999, 8.3333333333333331e-05, 19.507055555555556, 8.3333333333333331e-05], 
+              [252.42108333333331, 8.3333333333333331e-05, 19.507055555555556, 8.3333333333333331e-05], 
+              [252.42091666666667, 8.3333333333333331e-05, 19.507027777777779, 8.3333333333333331e-05]]
+    mjds = [mjdtt_to_mjdtai(54617.353094444443), 
+            mjdtt_to_mjdtai(54617.393774444448), 
+            mjdtt_to_mjdtai(54617.435174444443), 
+            mjdtt_to_mjdtai(54625.212504444447), 
+            mjdtt_to_mjdtai(54625.256664444445), 
+            mjdtt_to_mjdtai(54626.181794444448), 
+            mjdtt_to_mjdtai(54640.367084444442), 
+            mjdtt_to_mjdtai(54640.414734444443), 
+            mjdtt_to_mjdtai(54641.353904444448), 
+            mjdtt_to_mjdtai(54641.406674444443), 
+            mjdtt_to_mjdtai(54655.124204444444), 
+            mjdtt_to_mjdtai(54655.131814444445), 
+            mjdtt_to_mjdtai(54655.145554444447), 
+            mjdtt_to_mjdtai(54655.150364444446), 
+            mjdtt_to_mjdtai(54655.155144444449)]
+    mags = [23.699999999999999, 
+            23.699999999999999, 
+            23.800000000000001, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006, 
+            99.900000000000006]
+    obscodes = ['568',
+                '568',
+                '568',
+                '807',
+                '807',
+                '807',
+                '696',
+                '696',
+                '696',
+                '696',
+                '807',
+                '807',
+                '807',
+                '807',
+                '807']
+    filters = ['r',
+               'r',
+               'r',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '',
+               '']
+    
+    
+    
+    sys.stdout.write('oorb.lsl:                         ')
+    sys.stdout.write('\n')
+    orb, cov = lsl(0, coords, mjds, mags, obscodes, filters, rangingOrbits)
+    
+    
+    
+    
+    
+    sys.stdout.write('oorb.lsl_fast:                    ')
+    sys.stdout.write('\n')
+    orb, cov = lsl_fast(0, coords, mjds, mags, obscodes, filters, rangingOrbits)
+    # print(orb)
+    # print(cov)
+    
+    
+    
+    
+    
+    mjd = mjdtt_to_mjdtai(54994.)
+    sys.stdout.write('oorb.propagate_orbit:             ')
+    sys.stdout.write('\n')
+    newOrb, newCov = propagate_orbit(orb, cov, mjd)
+    # print(orb)
+    # print(cov)
+    
+    
+    
+    
+    
+    mjd = mjdtt_to_mjdtai(54994.)
+    sys.stdout.write('oorb.propagate_orbit_fast:        ')
+    sys.stdout.write('\n')
+    newOrb, newCov = propagate_orbit_fast(orb, cov, mjd)
+    # print(orb)
+    # print(cov)
+
+    
+    
+    
+    
+    
+    obscode = '500'
+    n = 10
+    step = 1.
+    sys.stdout.write('oorb.ephemeris                    ')
+    sys.stdout.write('\n')
+    ephems = ephemeris(newOrb, newCov, obscode, n, step)
+    print(ephems)
+    
+    
+    
+    
+    
+    obscode = '500'
+    n = 10
+    step = 1.
+    sys.stdout.write('oorb.ephemeris_fast               ')
+    sys.stdout.write('\n')
+    ephems = ephemeris_fast(newOrb, newCov, obscode, n, step)
+    print(ephems)
+    
+    
+    
+    
+    
+    moid = moid(newOrb, newCov)
+    print('moid: %.6f' %(moid))
+    
+    
+    
+    
+    
+    
+    classes, weights = classification(rangingOrbits)
+    # Write classification out.
+    print("Class             Probability")
+    for j in range(len(weights)):
+        print(" %s  %f" %(classes[j], weights[j]))
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: trunk/mops/oorb/python/constants.py
===================================================================
--- trunk/mops/oorb/python/constants.py	(revision 34646)
+++ trunk/mops/oorb/python/constants.py	(revision 34646)
@@ -0,0 +1,49 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+arcsec_to_deg = 1. / 3600.
+ASTEROID_CLASSES = ("Apohele",
+                    "NEO/Aten",
+                    "NEO/Apollo",
+                    "NEO/Amor",
+                    "Aethra",
+                    "Hungaria",
+                    "MBO/Phocaea",
+                    "MBO exc. Phocaea",
+                    "Hilda",
+                    "Jupiter Trojan",
+                    "Centaur",
+                    "TNO/Inner belt",
+                    "TNO/Plutino",
+                    "TNO/Classical",
+                    "TNO/Outer belt",
+                    "TNO/Scattered",
+                    "The rest")
+
+# Other constants.
+MIN_YEAR = 0
+
+# Error codes.
+ERROR_INTERNAL = -100
+ERROR_BADINPUT = -1
+ERROR_BADEBV = -2
+
Index: trunk/mops/oorb/python/defaults.py
===================================================================
--- trunk/mops/oorb/python/defaults.py	(revision 34646)
+++ trunk/mops/oorb/python/defaults.py	(revision 34646)
@@ -0,0 +1,75 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+from constants import *
+
+
+
+initModel = "n-body"
+fullModel = "n-body"
+method = "continued fraction"
+method_sw = "continued fraction"
+step = 5.0
+initStep = 5.0
+a_max = 1000.0
+a_min = 0.00465424
+periapsis_max = -1.0
+periapsis_min = -1.0
+apoapsis_max = -1.0
+apoapsis_min = -1.0
+rho_max = -1.0
+rho_min = -1.0
+sor_type = 2
+norb = 5000
+norb_sw = 500
+ntrial = 10000000
+ntrial_sw = 200000
+niter = 3
+genwin_mult = 6.0
+accwin_mult = 4.0
+i = 0
+j = 0
+elementMask = True
+outlierRejection = False
+uniform = False
+regularized = False
+random_obs = False
+gaussian_rho = False
+pdf_ml_init = -1.0
+ephemStep = 0.0
+obscode = "500"
+timespan = 10.0
+mjd = 54994.0
+moid = -1.0
+sor_rho_init = [1.79769313486231571E+308, ] * 4
+sor_genwin_offset = [0.0, ] * 4
+stdev_arr = [0.3 * arcsec_to_deg, ] * 6
+outlierMultiplier = 3.0
+elementType = "keplerian"
+sor_norb = 5000
+sor_ntrial = 10000000
+sor_norb_sw = 500
+sor_ntrial_sw = 200000
+correctionFactor = 0.2
+niterMajorMax = 20
+niterMajorMin = 2
+niterMinor = 100
Index: trunk/mops/oorb/python/liboorb.f90
===================================================================
--- trunk/mops/oorb/python/liboorb.f90	(revision 34646)
+++ trunk/mops/oorb/python/liboorb.f90	(revision 34646)
@@ -0,0 +1,2611 @@
+!
+! LSST Data Management System
+! Copyright 2008, 2009 LSST Corporation, Mikael Granvik
+!
+! This product includes software developed by the
+! LSST Project (http://www.lsst.org/).
+!
+! 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 LSST License Statement and
+! the GNU General Public License along with this program.  If not,
+! see <http://www.lsstcorp.org/LegalNotices/>.
+!
+! 
+! OpenOrb library
+! F. Pierfederici <fpierfed@gmail.com>
+! M. Granvik <mgranvik@iki.fi>
+! 
+! Description
+! 
+! Notes
+! error is a boolean global and is defined somewhere in liboorb.so!
+! 
+! 
+! 
+! -------------------------------- IMPORTANT -----------------------------------
+! All angles coming in and out are in radians. 
+! All times coming in and out in MJD TAI
+! -------------------------------- IMPORTANT -----------------------------------
+! 
+! 
+! The way I find out the max value used for errorCodes is:
+! $NF is the number of fields in the record and so it points to the last column.
+! awk '/errorCode = / { if (x < $NF) x = $NF} END { print x }' *.f90
+
+MODULE liboorb
+
+  USE Base_cl
+  ! use File_cl
+  ! use PhysicalParameters_cl
+  USE Time_cl
+  USE CartesianCoordinates_cl
+  USE SphericalCoordinates_cl
+  USE Observatories_cl
+  USE Orbit_cl
+  USE Observation_cl
+  USE Observations_cl
+  USE StochasticOrbit_cl
+  USE planetary_data
+  USE utilities
+  USE io
+
+  IMPLICIT NONE
+  SAVE
+  PRIVATE
+  TYPE (Observatories), PUBLIC            :: obsies
+  ! Orbital elements that we support.
+  CHARACTER(len=11), DIMENSION(4), PUBLIC :: ORBITAL_ELEMENTS = (/             &
+       "keplerian  ",&
+       "delaunay   ",&
+       "poincare   ",&
+       "equinoctial" &
+       /)
+  ! One can change the internal timescale to something other than TAI but let's
+  ! be quiet about it ;-)
+  CHARACTER(len=3), PARAMETER, PUBLIC     :: internal_timescale = "TAI"
+
+  ! Public API
+  PUBLIC ::                                 &
+                                ! These are the functions we provide here.
+       init,                                &
+       propagateOrbit,                      &
+       ranging,                             &
+                                ! mcmc,                                &
+       lsl,                                 &
+       ephemeris,                           &
+       classification,                      &
+       computeMoid,                         &
+       dumpRangingOrbits,                   &
+       dumpLslOrbit,                        &
+       dumpEphemeris,                       &
+       readOpenOrbOrbit,                    &
+       readObsFile,                         &
+       obssFromCoords,                      &
+       exportRangingOrbits,                 &
+       exportLslOrbit,                      &
+       calendarDateToMjd,                   &
+       mjdConvert,                          &
+       rangingOrbitsToStochasticOrbit,      &
+       lslOrbitToStochasticOrbit,           &
+       exportEphemeris
+
+
+
+  ! Constants and global variables.
+
+
+  ! Code!
+CONTAINS
+
+
+  SUBROUTINE init(ephemFileName, verbosity, errorCode)
+    ! Initialize the OpenOrb module.
+    !
+    ! @param ephemFileName: full path of the JPL ephem file (usually 
+    !        $OORB_DATA/JPL_ephemeris/de405.dat).
+    ! @param verbosity: verbosity level for OpenOrb calls [0, 5] (default 0)
+    ! @return errorCode: int error code. 0 = success, otherwise, failure.
+
+    ! Input/Output variables.
+    CHARACTER(len=*), INTENT(IN)    :: ephemFileName
+    INTEGER, OPTIONAL, INTENT(in)   :: verbosity
+    INTEGER, INTENT(OUT)            :: errorCode
+
+    ! Variable declaration.
+    LOGICAL                         :: error = .FALSE.
+    TYPE (Time)                     :: t
+
+
+    ! Defaults.
+    error = .FALSE.
+    errorCode = 0
+
+    ! Verbosity levels.
+    IF(PRESENT(verbosity) .AND. verbosity >= 0 .AND. verbosity <= 5) THEN 
+       info_verb = verbosity
+       err_verb = verbosity
+    ELSE
+       info_verb = 0
+       err_verb = 0
+    END IF
+
+    ! Init global variable OORB_DATA.
+    CALL setAccessToDataFiles()
+    IF(error) THEN
+       ! CALL errorMessage("oorb / init", "TRACE BACK (1)", 1)
+       errorCode = 1
+       RETURN
+    END IF
+
+    ! Init JPL ephemeris.
+    CALL JPL_ephemeris_init(error, filename=TRIM(ephemFileName))
+    IF(error) THEN
+       ! Error Could not initialize planetary ephemerides.
+       CALL errorMessage("oorb / init", "TRACE BACK (2)", 1)
+       errorCode = 1
+       RETURN
+    END IF
+
+    ! Read data from ET-UT.dat, TAI-UTC.dat, OBSCODE.dat
+    CALL NEW(t)
+    CALL NULLIFY(t)
+    CALL NEW(obsies)
+    IF(error) THEN
+       ! Error Could not initialize observatory codes.
+       errorCode = 45
+       RETURN
+    END IF
+
+  END SUBROUTINE init
+
+
+  SUBROUTINE ranging(obs_in, &
+       element_type, &
+       epoch_mjd, &
+       dyn_model, &
+                                ! From here below it is either config file params or output
+       integration_step, &
+       perturbers, &
+       apriori_a_max, &
+       apriori_a_min, &
+       apriori_periapsis_max, &
+       apriori_periapsis_min, &
+       apriori_apoapsis_max, &
+       apriori_apoapsis_min, &
+       apriori_rho_max, &
+       apriori_rho_min, &
+       outlier_rejection, &
+       outlier_multiplier, &
+       sor_type_prm, &
+       sor_2point_method, &
+       sor_2point_method_sw, &
+       sor_norb, &
+       sor_norb_sw, &
+       sor_ntrial, &
+       sor_ntrial_sw, &
+       sor_niter, &
+       sor_rho_init, &
+       sor_genwin_multiplier, &
+       sor_genwin_offset, &
+       accwin_multiplier, &
+       gaussian_rho, &
+       pdf_ml_init, &
+       uniform, &
+       regularized, &
+       random_obs, &
+       outOrbit, &
+       errorCode)
+    ! Orbital inversion using statistical orbital ranging, that is,
+    ! without making any assumptions on the shape of the resulting
+    ! orbital-element pdf.
+
+    ! Input/Output variables.
+    ! Observations (i.e. DiASources) to be used as input.
+    TYPE (Observations), INTENT(inout)                  :: obs_in
+    ! Element type used in the orbit computation (default keplerian)
+    CHARACTER(len=*), OPTIONAL, INTENT(in)              :: element_type
+    ! Computation epoch TAI (MJD) 
+    ! If left unspecified and doing inversion, the midnight closest to the 
+    ! observational mid-epoch will be used.
+    REAL(bp), OPTIONAL, INTENT(in)                      :: epoch_mjd
+    ! Dynamical model [ "2-body" | "n-body" ]. Defaults to "2-body".
+    CHARACTER(len=6), OPTIONAL, INTENT(in)              :: dyn_model
+    ! Integrator step length (in days)
+    REAL(bp), INTENT(in)                                :: integration_step
+    LOGICAL, DIMENSION(:), POINTER                      :: perturbers
+    ! BAYESIAN (INFORMATIVE) A PRIORI PARAMETERS
+    ! Upper limit for semimajor axis in AU
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_a_max
+    ! Lower limit for semimajor axis in AU (default: r_Sun = 0.00465424 AU)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_a_min
+    ! Upper limit for perihelion distance in AU
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_periapsis_max
+    ! Lower limit for perihelion distance in AU
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_periapsis_min
+    ! Upper limit for aphelion distance in AU
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_apoapsis_max
+    ! Lower limit for aphelion distance in AU
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_apoapsis_min
+    ! Upper limit for rho in AU (default: not defined)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_rho_max
+    ! Lower limit for rho in AU (default: 10*r_Earth = 0.000425641 AU)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: apriori_rho_min
+    ! Toggle outlier rejection (default false)
+    LOGICAL, OPTIONAL, INTENT(in)                       :: outlier_rejection
+    ! Outlier criterion (sigma multiplier) (default 3.0)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: outlier_multiplier
+    ! Type of ranging (1=basic, 2=automatic, 3=stepwise)
+    INTEGER, INTENT(in)                                 :: sor_type_prm
+    ! Method used for 2-point boundary-value problem. 
+    ! [ continued fraction | p-iteration | n-body amoeba ]
+    CHARACTER(len=*),INTENT(in)                         :: sor_2point_method
+    ! Method for solving the two-point boundary-value problem during the 
+    ! preliminary steps of stepwise Ranging
+    ! [ continued fraction | p-iteration | n-body amoeba ]
+    CHARACTER(len=*),INTENT(in)                         :: sor_2point_method_sw
+    ! Number of requested sample orbits
+    INTEGER, INTENT(in)                                 :: sor_norb
+    ! Number of requested sample orbits for the preliminary steps of stepwise 
+    ! ranging
+    INTEGER, INTENT(in)                                 :: sor_norb_sw
+    ! Maximum number of trial orbits
+    INTEGER, INTENT(in)                                 :: sor_ntrial
+    ! Maximum number of trial orbits for the preliminary steps of stepwise 
+    ! ranging
+    INTEGER, INTENT(in)                                 :: sor_ntrial_sw
+    ! Maximum number of iterations in automatic/stepwise Ranging
+    INTEGER, INTENT(in)                                 :: sor_niter
+    ! [Lower topocentric range bound corresponding to the first date 
+    !  (observer -> target) [AU],
+    !  Upper topocentric range bound corresponding to the first date
+    !  (observer -> target) [AU],
+    !  Lower topocentric range bound of the second date relative to the 
+    !  generated range of the first date [AU],
+    !  Upper topocentric range bound of the second date relative to the 
+    !  generated range of the first date [AU]]
+    ! (observer -> target) [AU]
+    REAL(bp), DIMENSION(4), INTENT(inout)               :: sor_rho_init
+    ! Sigma multiplier for generation windows
+    REAL(bp), INTENT(in)                                :: sor_genwin_multiplier
+    ! Offset for generation windows RA1, Dec1, RA2, Dec2 [asec]
+    REAL(bp), DIMENSION(4), INTENT(in)                  :: sor_genwin_offset
+    ! Sigma multiplier for acceptance windows
+    REAL(bp), INTENT(in)                                :: accwin_multiplier
+    ! sor.rho.gauss
+    LOGICAL, OPTIONAL, INTENT(in)                       :: gaussian_rho
+    ! pdf.init (default -1.0)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: pdf_ml_init
+    ! Toggle use of a uniform p.d.f. (default off)
+    LOGICAL, OPTIONAL, INTENT(in)                       :: uniform
+    ! Toggle use of regularization (default off)
+    LOGICAL, OPTIONAL, INTENT(in)                       :: regularized
+    ! Toggle use of random observation pair. Default is off, that is, use fixed
+    ! pair (cronologically first and last) (default false)
+    LOGICAL, OPTIONAL, INTENT(in)                       :: random_obs
+    ! Output Sthocastic orbit.
+    TYPE (StochasticOrbit), INTENT(out)                 :: outOrbit
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal variables.
+    ! Integrator (only used if dynamical model is different from 2-body).
+    ! [ "bulirsch-stoer" ]
+    CHARACTER(len=INTEGRATOR_LEN)               :: integrator = "bulirsch-stoer"!
+    CHARACTER(len=DESIGNATION_LEN)              :: id
+    REAL(bp)                                    :: dt
+    TYPE (Time)                                 :: t
+    ! Element type to be used in computations.
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    INTEGER                                     :: j = 0
+    ! Bounds to be iterated in automatical versions 
+    ! (rho1_lo, rho1_hi, rho2_lo, rho2_hi)
+    LOGICAL, DIMENSION(4)                       :: sor_iterate_bounds
+    TYPE (Time)                                 :: epoch
+    CHARACTER(len=6)                            :: dynModel = "2-body"
+    REAL(bp)                                    :: aprioriAMax = -1.0_bp
+    REAL(bp)                                    :: aprioriAMin = 0.00465424_bp
+    REAL(bp)                                    :: aprioriPeriapsisMax = -1.0_bp
+    REAL(bp)                                    :: aprioriPeriapsisMin = -1.0_bp
+    REAL(bp)                                    :: aprioriApoapsisMax = -1.0_bp
+    REAL(bp)                                    :: aprioriApoapsisMin = -1.0_bp
+    REAL(bp)                                    :: aprioriRhoMax = -1.0_bp
+    REAL(bp)                                    :: aprioriRhoMin = -1.0_bp
+    LOGICAL                                     :: outlierRejection = .FALSE.
+    REAL(bp)                                    :: outlierMultiplier = 3.0_bp
+    LOGICAL                                     :: gaussianRho = .FALSE.
+    REAL(bp)                                    :: pdfMLInit = -1.0_bp
+    LOGICAL                                     :: uniformPDF = .FALSE.
+    LOGICAL                                     :: regularizedPDF = .FALSE.
+    LOGICAL                                     :: randomObs = .FALSE.
+
+    !    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: scoords
+    !    REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_matrices
+    !    integer                                             :: i = 0
+    !    type (Time)                                         :: scoords_t
+    !    CHARACTER(len=DESIGNATION_LEN)                      :: obsId = " "
+    !    type (Observation)                                  :: obs_in_i
+    !    type (Time)                                         :: obs_t
+
+
+    !    cov_matrices => getCovarianceMatrices(obs_in)
+    !    scoords => getObservationSCoords(obs_in)
+    !    obsId = getID(obs_in)
+    !    
+    !    write(*, *) "ID: ", obsId
+    !    DO i=1,size(scoords)
+    !        obs_in_i = getObservation(obs_in, i)
+    !        scoords_t = getTime(scoords(i))
+    !        if(error) then
+    !            write(*, *) "Error getting Time object from SphCoords."
+    !        end if
+    !        obs_t = getTime(obs_in_i)
+    !        
+    !        write(*, *) "mag: ", getMagnitude(obs_in_i)
+    !        write(*, *) "RA:  ", getRA(obs_in_i)
+    !        write(*, *) "Dec: ", getDec(obs_in_i)
+    !        write(*, *) "MJD: ", getMJD(obs_t, internal_timescale)
+    !        write(*, *) "RA:  ", getLongitude(scoords(i))
+    !        write(*, *) "Dec: ", getLatitude(scoords(i))
+    !        write(*, *) "MJD: ", getMJD(scoords_t, internal_timescale)
+    !        write(*, *) "COV: ", cov_matrices(i,:,:)
+    !        call nullify(scoords_t)
+    !    END DO
+    !    write(*, *) "element_type: ", element_type
+    !    write(*, *) "dyn_model: ", dyn_model
+    !    write(*, *) "integration_step: ", integration_step
+    !    write(*, *) "perturbers: ", perturbers
+    !    write(*, *) "apriori_a_max: ", apriori_a_max
+    !    write(*, *) "apriori_a_min: ", apriori_a_min
+    !    write(*, *) "apriori_rho_min: ", apriori_rho_min
+    !    write(*, *) "apriori_rho_max: ", apriori_rho_max
+    !    write(*, *) "outlier_rejection: ", outlier_rejection
+    !    write(*, *) "outlier_multiplier: ", outlier_multiplier
+    !    write(*, *) "sor_type_prm: ", sor_type_prm
+    !    write(*, *) "sor_2point_method: ", sor_2point_method
+    !    write(*, *) "sor_2point_method_sw: ", sor_2point_method_sw
+    !    write(*, *) "sor_norb: ", sor_norb
+    !    write(*, *) "sor_norb_sw: ", sor_norb_sw
+    !    write(*, *) "sor_ntrial: ", sor_ntrial
+    !    write(*, *) "sor_ntrial_sw: ", sor_ntrial_sw
+    !    write(*, *) "sor_niter: ", sor_niter
+    !    write(*, *) "sor_rho_init: ", sor_rho_init
+    !    write(*, *) "sor_genwin_multiplier: ", sor_genwin_multiplier
+    !    write(*, *) "sor_genwin_offset: ", sor_genwin_offset
+    !    write(*, *) "accwin_multiplier: ", accwin_multiplier
+    !    write(*, *) "gaussian_rho: ", gaussian_rho
+    !    write(*, *) "pdf_ml_init: ", pdf_ml_init
+    !    write(*, *) "uniform: ", uniform
+    !    write(*, *) "regularized: ", regularized
+    !    write(*, *) "random_obs: ", random_obs
+
+    ! Init optional and output vars.
+    errorCode = 0
+    error = .FALSE.
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+    IF(.NOT.PRESENT(epoch_mjd)) THEN
+       CALL NULLIFY(epoch)
+    ELSE
+       CALL NEW(epoch, epoch_mjd, internal_timescale)
+    END IF
+    IF(PRESENT(dyn_model) .AND. &
+         dyn_model .NE. "2-body" .AND. &
+         dyn_model .NE. "n-body") THEN
+       ! Error: unsupported dynamical model.
+       errorCode = 21
+       RETURN
+    ELSEIF(dyn_model .EQ. "n-body") THEN
+       dynModel = "n-body"
+    END IF
+    IF(PRESENT(apriori_a_max)) THEN
+       aprioriAMax = apriori_a_max
+    END IF
+    IF(PRESENT(apriori_a_min)) THEN
+       aprioriAMin = apriori_a_min
+    END IF
+    IF(PRESENT(apriori_periapsis_max)) THEN
+       aprioriPeriapsisMax = apriori_periapsis_max
+    END IF
+    IF(PRESENT(apriori_periapsis_min)) THEN
+       aprioriPeriapsisMin = apriori_periapsis_min
+    END IF
+    IF(PRESENT(apriori_apoapsis_max)) THEN
+       aprioriApoapsisMax = apriori_apoapsis_max
+    END IF
+    IF(PRESENT(apriori_apoapsis_min)) THEN
+       aprioriApoapsisMin = apriori_apoapsis_min
+    END IF
+    IF(PRESENT(apriori_rho_max)) THEN
+       aprioriRhoMax = apriori_rho_max
+    END IF
+    IF(PRESENT(apriori_rho_min)) THEN
+       aprioriRhoMin = apriori_rho_min
+    END IF
+    IF(PRESENT(outlier_rejection)) THEN
+       outlierRejection = outlier_rejection
+    END IF
+    IF(PRESENT(outlier_multiplier)) THEN
+       outlierMultiplier = outlier_multiplier
+    END IF
+    IF(PRESENT(gaussian_rho)) THEN
+       gaussianRho = gaussian_rho
+    END IF
+    IF(PRESENT(pdf_ml_init)) THEN
+       pdfMLInit = pdf_ml_init
+    END IF
+    IF(PRESENT(uniform)) THEN
+       uniformPDF = uniform
+    END IF
+    IF(PRESENT(regularized)) THEN
+       regularizedPDF = regularized
+    END IF
+    IF(PRESENT(random_obs)) THEN
+       randomObs = random_obs
+    END IF
+
+    ! Init global error variables.
+    error  = .FALSE.
+
+    ! Init other variables.
+    j = 0
+
+    ! sor_iterate_bounds
+    sor_iterate_bounds(1) = .TRUE.
+    sor_iterate_bounds(2) = .TRUE.
+    sor_iterate_bounds(3) = .TRUE.
+    sor_iterate_bounds(4) = .TRUE.
+
+    id = getID(obs_in)
+    IF (error) THEN
+       ! Error in getID()
+       errorCode = 2
+       RETURN
+    END IF
+
+    dt = getObservationalTimespan(obs_in)
+    IF (error) THEN
+       ! Error in getObservationalTimeInterval()
+       errorCode = 3
+       RETURN
+    END IF
+
+    ! write(*, *) "dt: ", dt
+
+
+    IF (sor_rho_init(3) > HUGE(sor_rho_init(3))/2) THEN
+       ! Initialize the rho2-rho1 range based on the observational timespan.
+       IF (dt > 10) THEN
+          sor_rho_init(3) = -0.5_bp
+       ELSE
+          sor_rho_init(3) = -0.05_bp*dt
+       END IF
+       sor_rho_init(4) = -sor_rho_init(3)
+    END IF
+
+    ! write(*, *) "sor_rho_init: ", sor_rho_init
+
+
+    IF (.NOT.exist(epoch)) THEN
+       CALL epochFromObservations(obs_in, t, errorCode)
+       IF(errorCode /= 0) THEN
+          RETURN
+       END IF
+    ELSE
+       CALL NULLIFY(t)
+       t = copy(epoch)
+    END IF
+    CALL NEW(outOrbit, obs_in)
+    IF (error) THEN
+       ! Error in new(outOrbit)
+       errorCode = 8
+       RETURN
+    END IF
+    CALL setParameters(outOrbit, dyn_model=dynModel, perturbers=perturbers, &
+         integrator=integrator, integration_step=integration_step, &
+         outlier_rejection=outlierRejection, &
+         outlier_multiplier=outlierMultiplier, t_inv=t, &
+         element_type=elementType, &
+         regularized_pdf=regularizedPDF, uniform_pdf=uniformPDF, &
+         pdf_ml=pdfMLInit, accept_multiplier=accwin_multiplier, &
+         apriori_a_max=aprioriAMax, apriori_a_min=aprioriAMin, &
+         apriori_periapsis_max=aprioriPeriapsisMax, &
+         apriori_periapsis_min=aprioriPeriapsisMin, &
+         apriori_apoapsis_max=aprioriApoapsisMax, &
+         apriori_apoapsis_min=aprioriApoapsisMin, &
+         apriori_rho_min=aprioriRhoMin, &
+         sor_2point_method=sor_2point_method, &
+         sor_2point_method_sw=sor_2point_method_sw, sor_norb=sor_norb, &
+         sor_ntrial=sor_ntrial, sor_rho1_l=sor_rho_init(1), &
+         sor_rho1_u=sor_rho_init(2), sor_rho2_l=sor_rho_init(3), &
+         sor_rho2_u=sor_rho_init(4), sor_iterate_bounds=sor_iterate_bounds, &
+         sor_random_obs_selection=randomObs, gaussian_pdf=gaussianRho, &
+         sor_generat_multiplier=sor_genwin_multiplier, &
+         sor_generat_offset=sor_genwin_offset)
+    IF (error) THEN
+       ! Error in setParameters()
+       errorCode = 9
+       RETURN
+    END IF
+
+    !    write(*, *) "dynModel: ", dynModel
+    !    write(*, *) "perturbers: ", perturbers
+    !    write(*, *) "integrator: ", integrator
+    !    write(*, *) "integration_step: ", integration_step
+    !    write(*, *) "outlierRejection: ", outlierRejection
+    !    write(*, *) "outlierMultiplier: ", outlierMultiplier
+    !    write(*, *) "t (MJD TAI): ", getMjd(t, internal_timescale)
+    !    write(*, *) "elementType: ", elementType
+    !    write(*, *) "regularizedPDF: ", regularizedPDF
+    !    write(*, *) "uniformPDF: ", uniformPDF
+    !    write(*, *) "pdfMLInit: ", pdfMLInit
+    !    write(*, *) "accwin_multiplier: ", accwin_multiplier
+    !    write(*, *) "aprioriAMax: ", aprioriAMax
+    !    write(*, *) "aprioriAMin: ", aprioriAMin
+    !    write(*, *) "aprioriPeriapsisMax: ", aprioriPeriapsisMax
+    !    write(*, *) "aprioriPeriapsisMin: ", aprioriPeriapsisMin
+    !    write(*, *) "aprioriApoapsisMax: ", aprioriApoapsisMax
+    !    write(*, *) "aprioriApoapsisMin: ", aprioriApoapsisMin
+    !    write(*, *) "aprioriRhoMin: ", aprioriRhoMin
+    !    write(*, *) "sor_2point_method: ", sor_2point_method
+    !    write(*, *) "sor_2point_method_sw: ", sor_2point_method_sw
+    !    write(*, *) "sor_norb: ", sor_norb
+    !    write(*, *) "sor_ntrial: ", sor_ntrial
+    !    write(*, *) "sor_rho_init(1): ", sor_rho_init(1)
+    !    write(*, *) "sor_rho_init(2): ", sor_rho_init(2)
+    !    write(*, *) "sor_rho_init(3): ", sor_rho_init(3)
+    !    write(*, *) "sor_rho_init(4): ", sor_rho_init(4)
+    !    write(*, *) "sor_iterate_bounds: ", sor_iterate_bounds
+    !    write(*, *) "randomObs: ", randomObs
+    !    write(*, *) "gaussianRho: ", gaussianRho
+    !    write(*, *) "sor_genwin_multiplier: ", sor_genwin_multiplier
+    !    write(*, *) "sor_genwin_offset: ", sor_genwin_offset
+
+
+
+    SELECT CASE (sor_type_prm)
+    CASE (1)
+       CALL statisticalRanging(outOrbit)
+    CASE (2)
+       CALL setParameters(outOrbit, sor_niter=sor_niter)
+       IF (error) THEN
+          ! Error in setParameters()
+          errorCode = 10
+          RETURN
+       END IF
+       CALL autoStatisticalRanging(outOrbit)
+    CASE (3)
+       CALL setParameters(outOrbit, &
+            sor_norb_sw=sor_norb_sw, &
+            sor_ntrial_sw=sor_ntrial_sw, &
+            sor_niter=sor_niter)
+       IF (error) THEN
+          ! Error in setParameters()
+          errorCode = 11
+          RETURN
+       END IF
+       CALL stepwiseRanging(outOrbit, nobs_max=-1)
+    CASE default
+       ! Error: unknown type of ranging
+       errorCode = 12
+       RETURN
+    END SELECT
+
+    ! Did we get any error?
+    IF (error) THEN
+       ! Error
+       errorCode = 13
+       error  = .FALSE.
+       CALL NULLIFY(outOrbit)
+       RETURN
+    END IF
+
+    ! Cleanup everything
+    RETURN
+  END SUBROUTINE ranging
+
+
+  SUBROUTINE mcmc
+    WRITE (*,*)  "mcmc"
+    RETURN
+  END SUBROUTINE mcmc
+
+
+  SUBROUTINE lsl(obs_in, &
+       element_type, &
+       epoch_mjd, &
+       dyn_model, &
+       dyn_model_init, &
+                                ! From here below it is either config file params or output
+       integration_step, &
+       integration_step_init, &
+       perturbers, &
+       ls_correction_factor, &
+       ls_element_mask, &
+       ls_niter_major_max, &
+       ls_niter_major_min, &
+       ls_niter_minor, &
+       outlier_rejection, &
+       outlier_multiplier, &
+       accwin_multiplier, &
+       inStochOrbit, &
+       outStochOrbit, &
+       errorCode)
+    ! Orbital inversion using least squares with linearized
+    ! covariances, that is, fixing the resulting shape of
+    ! the orbital-element pdf to a Gaussian.
+
+    ! Input/Output variables.
+    ! Observations (i.e. DiASources) to be used as input.
+    TYPE (Observations), INTENT(inout)                  :: obs_in
+    ! Element type used in the orbit computation (default keplerian)
+    CHARACTER(len=*), OPTIONAL, INTENT(in)              :: element_type
+    ! Computation epoch TAI (MJD) 
+    ! If left unspecified and doing inversion, the midnight closest to the 
+    ! observational mid-epoch will be used.
+    REAL(bp), OPTIONAL, INTENT(in)                      :: epoch_mjd
+    ! Dynamical model [ "2-body" | "n-body" ]. Defaults to "n-body".
+    CHARACTER(len=6), OPTIONAL, INTENT(in)              :: dyn_model
+    ! Dynamical model for initial orbit [ "2-body" | "n-body" ]. Defaults to 
+    ! "2-body".
+    CHARACTER(len=6), OPTIONAL, INTENT(in)              :: dyn_model_init
+    ! Integrator step length (in days)
+    REAL(bp), INTENT(in)                                :: integration_step
+    ! Integrator step length (in days) for initial orbit
+    REAL(bp), INTENT(in)                                :: integration_step_init
+    ! Perturbers array (planets and moon).
+    LOGICAL, DIMENSION(:), POINTER                      :: perturbers
+    ! Correction factor for the iterative solution of the least-squares
+    ! problem [0:1] (default 0.2)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: ls_correction_factor
+    ! Elements to included in the correction process (indicated with T). Fixed 
+    ! elements should be marked with F. (default all true)
+    LOGICAL, DIMENSION(6), OPTIONAL, INTENT(in)         :: ls_element_mask
+    ! Maximum number of major iterations (default 20)
+    INTEGER, OPTIONAL, INTENT(in)                       :: ls_niter_major_max
+    ! Minimum number of major iterations (default 2)
+    INTEGER, OPTIONAL, INTENT(in)                       :: ls_niter_major_min
+    ! Number of iterations per scheme (default 10)
+    INTEGER, OPTIONAL, INTENT(in)                       :: ls_niter_minor
+    ! Toggle outlier rejection (default false)
+    LOGICAL, OPTIONAL, INTENT(in)                       :: outlier_rejection
+    ! Outlier criterion (sigma multiplier) (default 3.0)
+    REAL(bp), OPTIONAL, INTENT(in)                      :: outlier_multiplier
+    ! Sigma multiplier for acceptance windows
+    REAL(bp), INTENT(in)                                :: accwin_multiplier
+    ! Input Sthocastic orbit from ranging.
+    TYPE (StochasticOrbit), INTENT(in)                  :: inStochOrbit
+    ! Output Stichastic Orbit.
+    TYPE (StochasticOrbit), INTENT(out)                 :: outStochOrbit
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal variables.
+    INTEGER                                             :: nobs = 0
+    INTEGER                                             :: norb = 0
+    TYPE (Orbit), DIMENSION(:), POINTER                 :: orb_arr
+    TYPE (Time)                                         :: t
+    ! Internal variables.
+    ! Integrator (only used if dynamical model is different from 2-body).
+    ! [ "bulirsch-stoer" ]
+    CHARACTER(len=INTEGRATOR_LEN)               :: integrator = "bulirsch-stoer"
+    CHARACTER(len=INTEGRATOR_LEN)          :: integratorInit = "bulirsch-stoer"
+    INTEGER                                     :: err = 0
+    ! Element type to be used in computations.
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    INTEGER                                     :: j = 0
+    TYPE (Time)                                 :: epoch
+    CHARACTER(len=6)                            :: dynModel = "n-body"
+    CHARACTER(len=6)                            :: dynModelInit = "2-body"
+    LOGICAL                                     :: outlierRejection = .FALSE.
+    REAL(bp)                                    :: outlierMultiplier = 3.0_bp
+    LOGICAL, DIMENSION(6)                       :: lsElementMask = .TRUE.
+    INTEGER                                     :: lsNIterMajorMax = 20
+    INTEGER                                     :: lsNIterMajorMin = 2
+    INTEGER                                     :: lsNIterMinor = 10
+    REAL(bp)                                    :: lsCorrectionFactor = 0.2_bp
+
+    ! Init
+    CALL NULLIFY(t)
+    errorCode = 0
+    error = .FALSE.
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+    IF(.NOT.PRESENT(epoch_mjd)) THEN
+       CALL NULLIFY(epoch)
+    ELSE
+       CALL NEW(epoch, epoch_mjd, internal_timescale)
+    END IF
+    IF(PRESENT(dyn_model) .AND. &
+         dyn_model .NE. "2-body" .AND. &
+         dyn_model .NE. "n-body") THEN
+       ! Error: unsupported dynamical model.
+       errorCode = 21
+       RETURN
+    ELSEIF(dyn_model .EQ. "2-body") THEN
+       dynModel = "2-body"
+    END IF
+    IF(PRESENT(dyn_model_init) .AND. &
+         dyn_model_init .NE. "2-body" .AND. &
+         dyn_model_init .NE. "n-body") THEN
+       ! Error: unsupported dynamical model.
+       errorCode = 21
+       RETURN
+    ELSEIF(dyn_model_init .EQ. "n-body") THEN
+       dynModelInit = "n-body"
+    END IF
+    IF(PRESENT(ls_correction_factor)) THEN
+       lsCorrectionFactor = ls_correction_factor
+    END IF
+    IF(PRESENT(ls_element_mask)) THEN
+       lsElementMask = ls_element_mask
+    END IF
+    IF(PRESENT(ls_niter_major_max)) THEN
+       lsNIterMajorMax = ls_niter_major_max
+    END IF
+    IF(PRESENT(ls_niter_major_min)) THEN
+       lsNIterMajorMin = ls_niter_major_min
+    END IF
+    IF(PRESENT(ls_niter_minor)) THEN
+       lsNIterMinor = ls_niter_minor
+    END IF
+    IF(PRESENT(outlier_rejection)) THEN
+       outlierRejection = outlier_rejection
+    END IF
+    IF(PRESENT(outlier_multiplier)) THEN
+       outlierMultiplier = outlier_multiplier
+    END IF
+
+    ! Make sure that we have at least 4 observations!
+    nobs = getNrOfObservations(obs_in)
+    IF (error) THEN
+       ! Error in getNrOfObservations()
+       errorCode = 22
+       RETURN
+    END IF
+    IF (nobs < 4) THEN
+       ! Error: Too few observations!
+       errorCode = 23
+       RETURN
+    END IF
+
+    ! Get the sample orbits from ranging.
+    IF (containsSampledPDF(inStochOrbit)) THEN
+       orb_arr => getSampleOrbits(inStochOrbit)
+       IF (error) THEN
+          ! Error in getSampleOrbits()
+          errorCode = 16
+          RETURN
+       END IF
+       norb = SIZE(orb_arr)
+    ELSE
+       ALLOCATE(orb_arr(1))
+       orb_arr(1) = getNominalOrbit(inStochOrbit)
+       IF (error) THEN
+          ! Error in getNominalOrbit()
+          errorCode = 24
+          RETURN
+       END IF
+       norb = 1
+    END IF
+    IF (norb == 0) THEN
+       CALL errorMessage("oorb4mops / lsl", &
+            "Initial orbit not available.", 1)
+       STOP
+    END IF
+
+    IF (.NOT.exist(epoch)) THEN
+       CALL epochFromObservations(obs_in, t, errorCode)
+       IF(errorCode /= 0) THEN
+          RETURN
+       END IF
+    ELSE
+       t = copy(epoch)
+    END IF
+
+
+
+    !    write(*, *) "element_type: ", elementType
+    !    write(*, *) "dyn_model: ", dynModel
+    !    write(*, *) "dyn_model_init: ", dynModelInit
+    !    write(*, *) "integration_step: ", integration_step
+    !    write(*, *) "integration_step_init: ", integration_step_init
+    !    write(*, *) "perturbers: ", perturbers
+    !    write(*, *) "ls_correction_factor: ", lsCorrectionFactor
+    !    write(*, *) "ls_element_mask: ", lsElementMask
+    !    write(*, *) "ls_niter_major_max: ", lsNIterMajorMax
+    !    write(*, *) "ls_niter_major_min: ", lsNIterMajorMin
+    !    write(*, *) "ls_niter_minor: ", lsNiterMinor
+    !    write(*, *) "outlier_rejection: ", outlierRejection
+    !    write(*, *) "outlier_multiplier: ", outlierMultiplier
+    !    write(*, *) "accwin_multiplier: ", accwin_multiplier
+
+
+
+    ! Create the output Stochastic Orbit.
+    CALL NEW(outStochOrbit, obs_in)
+    IF (error) THEN
+       ! Error in createing a new Stochasic Orbit
+       errorCode = 8
+       RETURN
+    END IF
+    CALL setParameters(outStochOrbit, &
+         dyn_model=dynModel, &
+         perturbers=perturbers, &
+         integrator=integrator, &
+         integration_step=integration_step, &
+         outlier_rejection=outlierRejection, &
+         outlier_multiplier=outlierMultiplier, &
+         t_inv=t, &
+         element_type=elementType, &
+         accept_multiplier=accwin_multiplier, &
+         ls_correction_factor=lsCorrectionFactor, &
+         ls_element_mask=lsElementMask, &
+         ls_niter_major_max=lsNIterMajorMax, &
+         ls_niter_major_min=lsNIterMajorMin, &
+         ls_niter_minor=lsNiterMinor)
+    IF (error) THEN
+       ! Error in setParameters()
+       errorCode = 9
+       RETURN
+    END IF
+
+    DO j=1,SIZE(orb_arr,dim=1)
+       CALL setParameters(orb_arr(j), &
+            dyn_model=dynModelInit, &
+            perturbers=perturbers, &
+            integrator=integratorInit, &
+            integration_step=integration_step_init)
+       IF (error) THEN
+          ! Error in setParameters()
+          errorCode = 9
+          RETURN
+       END IF
+
+       CALL propagate(orb_arr(j), t)
+       IF (error) THEN
+          ! Error in propagate()
+          errorCode = 25
+          RETURN
+       END IF
+       CALL setParameters(orb_arr(j), &
+            dyn_model=dynModel, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          ! Error in setParameters()
+          errorCode = 9
+          RETURN
+       END IF
+
+       CALL levenbergMarquardt(outStochOrbit, orb_arr(j))
+       IF (.NOT.error) THEN
+          EXIT
+       ELSE IF (j < norb) THEN
+          error = .FALSE.
+       END IF
+    END DO
+    IF (error) THEN
+       ! Error: least squares fit failed.
+       errorCode = 26
+       RETURN
+    END IF
+
+    ! Cleanup and quit.
+    DEALLOCATE(orb_arr, stat=err)
+    IF (err /= 0) THEN
+       ! Error in deallocating orbit array.
+       errorCode = 27
+    END IF
+
+  END SUBROUTINE lsl
+
+
+  SUBROUTINE propagateOrbit(storb, &
+       dyn_model, &
+       integration_step, &
+       perturbers, &
+       epoch_mjd, &
+       errorCode)
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(inout)                :: storb
+    ! Dynamical model [ "2-body" | "n-body" ]. Defaults to "2-body".
+    CHARACTER(len=6), OPTIONAL, INTENT(in)              :: dyn_model
+    ! Integrator step length (in days)
+    REAL(bp), INTENT(in)                                :: integration_step
+    LOGICAL, DIMENSION(:), POINTER                      :: perturbers
+    ! Propagate the orbit to epoch_mjd (TAI)
+    REAL(bp), INTENT(in)                                :: epoch_mjd
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal variables.
+    ! Integrator (only used if dynamical model is different from 2-body).
+    ! [ "bulirsch-stoer" ]
+    CHARACTER(len=INTEGRATOR_LEN)               :: integrator = "bulirsch-stoer"!
+    TYPE(Time)                                  :: epoch
+    CHARACTER(len=6)                            :: dynModel = "2-body"
+
+
+    ! Init vars
+    error = .FALSE.
+    errorCode = 0
+    CALL NULLIFY(epoch)
+    IF (epoch_mjd > 0.0_bp) THEN
+       CALL NEW(epoch, epoch_mjd, internal_timescale)
+       IF (error) THEN
+          ! Error in creating a new epoch
+          errorCode = 39
+          RETURN
+       END IF
+    END IF
+    IF (.NOT.exist(epoch)) THEN
+       ! Error creating a viable epoch.
+       errorCode = 40
+       RETURN
+    END IF
+    IF(PRESENT(dyn_model) .AND. &
+         dyn_model .NE. "2-body" .AND. &
+         dyn_model .NE. "n-body") THEN
+       ! Error: unsupported dynamical model.
+       errorCode = 21
+       RETURN
+    ELSEIF(dyn_model .EQ. "n-body") THEN
+       dynModel = "n-body"
+    END IF
+
+    ! Set integration parameters
+    CALL setParameters(storb, &
+         dyn_model=dynModel, &
+         perturbers=perturbers, &
+         integrator=integrator, &
+         integration_step=integration_step)
+    IF (error) THEN
+       ! Error in setParameters()
+       errorCode = 37
+       RETURN
+    END IF
+
+    ! Compute topocentric ephemerides
+    CALL propagate(storb, epoch)
+    IF (error) THEN
+       ! Error in propagate()
+       errorCode = 41
+       RETURN
+    END IF
+
+  END SUBROUTINE propagateOrbit
+
+
+  SUBROUTINE ephemeris(storb, &
+       element_type, &
+       dyn_model, &
+       integration_step, &
+       perturbers, &
+       obsy_code, &
+       timespan, &
+       step, &
+       ephemerides, &
+       cov_arr, &
+       pdfs_arr, &
+       observers, &
+       errorCode)
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(inout)                :: storb
+    ! Element type used in the orbit computation (default keplerian)
+    CHARACTER(len=*), OPTIONAL, INTENT(in)              :: element_type
+    ! Dynamical model [ "2-body" | "n-body" ]. Defaults to "2-body".
+    CHARACTER(len=6), OPTIONAL, INTENT(in)              :: dyn_model
+    ! Integrator step length (in days)
+    REAL(bp), INTENT(inout)                             :: integration_step
+    LOGICAL, DIMENSION(:), POINTER, OPTIONAL            :: perturbers
+    ! IAU/MPC designated observatory code.
+    CHARACTER(len=OBSY_CODE_LEN), INTENT(in)            :: obsy_code
+    ! Range in days for ephemeris production.
+    REAL(bp), INTENT(in)                                :: timespan
+    ! Step in days for ephemeris production.
+    REAL(bp), INTENT(inout)                             :: step
+    ! Output ephem array (intent(inout)).
+    TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephemerides
+    ! Ephem uncertainty matrices (intent(inout)).
+    REAL(bp), DIMENSION(:,:,:), POINTER                 :: cov_arr
+    REAL(bp), DIMENSION(:,:), POINTER                   :: pdfs_arr
+    ! observatory coordinates and ephem time array (intent(inout)).
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal variables.
+    ! Integrator (only used if dynamical model is different from 2-body).
+    ! [ "bulirsch-stoer" ]
+    CHARACTER(len=INTEGRATOR_LEN)               :: integrator = "bulirsch-stoer"!
+    TYPE (Time)                                 :: t
+    ! Element type to be used in computations.
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    INTEGER                                     :: j = 0
+    CHARACTER(len=6)                            :: dynModel = "2-body"
+    INTEGER                                     :: nstep = 0
+    REAL(bp)                                    :: mjd_tai
+
+
+    ! Init vars
+    error = .FALSE.
+    errorCode = 0
+    IF (step <= 0.0_bp) THEN
+       nstep = 1        
+    ELSE
+       step = SIGN(ABS(step),timespan)
+       IF (ABS(timespan) > 10.0_bp*EPSILON(timespan) .AND. &
+            ABS(timespan) < ABS(step)) THEN
+          step = timespan
+       END IF
+       nstep = NINT(timespan/step) + 1
+    END IF
+    integration_step = MIN(ABS(step),integration_step)
+
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+    IF(PRESENT(dyn_model) .AND. &
+         dyn_model .NE. "2-body" .AND. &
+         dyn_model .NE. "n-body") THEN
+       ! Error: unsupported dynamical model.
+       errorCode = 21
+       RETURN
+    ELSEIF(dyn_model .EQ. "n-body") THEN
+       dynModel = "n-body"
+    END IF
+
+    ! Use equatorial coordinates:
+    CALL toCartesian(storb, "equatorial")
+
+    ! Get orbit epoch at the observatory.
+    t = getTime(storb)
+    mjd_tai = getMJD(t, internal_timescale)
+    CALL NULLIFY(t)
+    ALLOCATE(observers(nstep))
+    DO j=1,nstep
+       CALL NEW(t, mjd_tai+(j-1)*step, internal_timescale)
+       IF (error) THEN
+          ! Error in creating a new Time object.
+          errorCode = 35
+          RETURN
+       END IF
+       ! Compute heliocentric observatory coordinates
+       observers(j) = getObservatoryCCoord(obsies, obsy_code, t)
+       IF (error) THEN
+          ! Error in getObservatoryCCoord()
+          errorCode = 36
+          RETURN
+       END IF
+       CALL rotateToEquatorial(observers(j))
+       CALL NULLIFY(t)
+    END DO
+
+    ! Set integration parameters
+    IF (dynModel == "n-body") THEN
+       CALL setParameters(storb, &
+            dyn_model=dynModel, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+    ELSE
+       CALL setParameters(storb, &
+            dyn_model=dynModel)
+    END IF
+    IF (error) THEN
+       ! Error in setParameters()
+       errorCode = 37
+       RETURN
+    END IF
+
+    ! Compute topocentric ephemerides
+    CALL getEphemerides(storb, &
+         observers, &
+         ephemerides, &
+         cov_arr=cov_arr, &
+         pdfs_arr=pdfs_arr)
+    IF (error) THEN
+       ! Error in getEphemerides()
+       errorCode = 38
+       RETURN
+    END IF
+
+  END SUBROUTINE ephemeris
+
+
+  SUBROUTINE classification(storb, group_name_arr, weight_arr, errorCode)
+    ! Compute probability for an object with the input
+    ! orbital-element pdf to belong to a group of asteroids. Caveat:
+    ! an, ap, M are not currently taken into account, that is,
+    ! e.g. Jupiter Trojans not correctly accounted for.
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(inout)                    :: storb
+    ! Class names and probability arrays.
+    REAL(bp), DIMENSION(:), POINTER                         :: weight_arr
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER   :: group_name_arr
+    INTEGER, INTENT(out)                                    :: errorCode
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+
+    IF (.NOT.containsSampledPDF(storb)) THEN
+       ! Error: we need sampled uncertainty information required for this task.
+       errorCode = 44
+       RETURN
+    END IF
+
+    ! Propagate input orbital-element pdf to Keplerian-element pdf:
+    CALL toKeplerian(storb)
+    ! Compute weights for each class that has been defined:
+    CALL getGroupWeights(storb, weight_arr, group_name_arr)
+
+  END SUBROUTINE classification
+
+
+  SUBROUTINE computeMoid(storb, moid, errorCode)
+    ! Compute Earth MOID (w/o uncertainty) for the input orbit.
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(in)                   :: storb
+    REAL(bp), INTENT(out)                               :: moid
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal variables.
+    REAL(bp), DIMENSION(6)                              :: elements
+    TYPE(Orbit)                                         :: orb
+    TYPE(Orbit)                                         :: ref_orb
+    TYPE(Time)                                          :: epoch
+    REAL(bp)                                            :: mjd_tai
+    INTEGER                                             :: err = 0
+    REAL(bp), DIMENSION(:,:), POINTER                   :: planeph
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+    moid = -1.0_bp
+
+    ! Get the nominal orbit.
+    orb = getNominalOrbit(storb)
+    elements = getElements(orb, "cometary")
+    IF (elements(2) > 1.0_bp) THEN
+       ! Error: MOID for hyperbolic orbits currently not computed...
+       errorCode = 42
+       moid = -1.0_bp
+       RETURN
+    END IF
+
+    ! Epoch of the asteroid orbit:
+    epoch = getTime(orb)
+    mjd_tai = getMJD(epoch, internal_timescale)
+    ! Earth's osculating elements for the epoch of the asteroid orbit:
+    planeph => JPL_ephemeris(mjd_tai, 3, 11, error)
+    CALL NEW(ref_orb, planeph(1,:), "cartesian", "equatorial", epoch)
+    ! MOID between Earth and asteroid orbits:
+    moid = getMOID(orb, ref_orb)
+    IF (error) THEN
+       ! Error in getMOID()
+       moid = -1.0_bp
+       error = .FALSE.
+       errorCode = 43
+    END IF
+
+    ! Cleanup.
+    CALL NULLIFY(epoch)
+    CALL NULLIFY(ref_orb)
+    CALL NULLIFY(orb)
+    DEALLOCATE(planeph, stat=err)
+
+  END SUBROUTINE computeMoid
+
+
+  SUBROUTINE epochFromObservations(obs_in, t, errorCode)
+    TYPE (Observations), INTENT(in)             :: obs_in
+    TYPE (Time), INTENT(out)                    :: t
+    INTEGER, INTENT(OUT)                        :: errorCode
+
+    ! Internal variables.
+    REAL(bp)                                    :: dt = 0
+    REAL(bp)                                    :: mjd = 0
+    TYPE (Observation)                          :: obs
+
+
+    ! init
+    errorCode = 0
+    error = .FALSE.
+    CALL NULLIFY(t)
+    CALL NULLIFY(obs)
+    dt = getObservationalTimespan(obs_in)
+    IF (error) THEN
+       ! Error in getObservationalTimeInterval()
+       errorCode = 3
+       RETURN
+    END IF
+    obs = getObservation(obs_in,1)
+    IF (error) THEN
+       ! Error in getObservation()
+       errorCode = 4
+       RETURN
+    END IF
+    t = getTime(obs)
+    IF (error) THEN
+       ! Error in getTime()
+       errorCode = 5
+       RETURN
+    END IF
+    CALL NULLIFY(obs)
+    mjd = getMJD(t, internal_timescale)
+    IF (error) THEN
+       ! Error in getMJD()
+       errorCode = 6
+       RETURN
+    END IF
+    CALL NULLIFY(t)
+    mjd = REAL(NINT(mjd+dt/2.0_bp),bp)
+    CALL NEW(t, mjd, internal_timescale)
+    IF (error) THEN
+       ! Error in new(t)
+       errorCode = 7
+       RETURN
+    END IF
+
+  END SUBROUTINE epochFromObservations
+
+
+  SUBROUTINE dumpRangingOrbits(storb, element_type, errorCode)
+    TYPE (StochasticOrbit), INTENT(in)          :: storb
+    CHARACTER(len=*), OPTIONAL, INTENT(in)      :: element_type
+    INTEGER, INTENT(out)                        :: errorCode
+
+    ! Internal variables.
+    REAL(bp), DIMENSION(2,2)                    :: sor_rho_cmp
+    TYPE (Orbit), DIMENSION(:), POINTER         :: orb_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: pdf_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: rchi2_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: reg_apr_arr_cmp
+    REAL(bp), DIMENSION(:,:), POINTER           :: jac_arr_cmp
+    INTEGER                                     :: numOutOrbits
+    REAL(bp), DIMENSION(6)                      :: elements
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    TYPE (Time)                                 :: t0
+    REAL(bp)                                    :: orbMjd
+    INTEGER                                     :: j = 0
+    INTEGER                                     :: err = 0
+    CHARACTER(len=85)                           :: fmt
+
+    INTEGER                                     :: year
+    INTEGER                                     :: month
+    REAL(bp)                                    :: day
+    CHARACTER(len=9)                            :: id = "K08K0042V"
+
+    ! Init
+    errorCode = 0
+    error = .FALSE.
+    fmt = "(A16,6(1X,E21.14),1X,I4,1X,I2,1X,F8.5,1X,A12,1X,E18.10,1X,E18.10,1X,E18.10,1X,E18.10)"
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+
+    CALL getResults(storb, sor_rho_cmp=sor_rho_cmp)
+    IF (error) THEN
+       WRITE(*, *) "Error in getResults()"
+       errorCode = 15
+       RETURN
+    END IF
+    ! Get ORBITAL-ELEMENT PDF
+    orb_arr_cmp => getSampleOrbits(storb)
+    IF (error) THEN
+       WRITE(*, *) "Error in getSampleOrbits()"
+       errorCode = 16
+       RETURN
+    END IF
+    pdf_arr_cmp => getPDFValues(storb)
+    IF (error) THEN
+       WRITE(*, *) "Error in getPDFValues()"
+       errorCode = 17
+       RETURN
+    END IF
+    rchi2_arr_cmp => getReducedChi2Distribution(storb)
+    IF (error) THEN
+       WRITE(*, *) "Error in getReducedChi2Distribution()"
+       errorCode = 17
+       RETURN
+    END IF
+    CALL getResults(storb, &
+         reg_apr_arr=reg_apr_arr_cmp, &
+         jac_arr=jac_arr_cmp)
+    IF (error) THEN
+       WRITE(*, *) "Error in getResults()"
+       numOutOrbits = 0
+       errorCode = 18
+       RETURN
+    END IF
+
+    ! This is where we wrere originally writing the .orb file(s) out.
+    numOutOrbits = SIZE(orb_arr_cmp,dim=1)
+    DO j=1,numOutOrbits
+       elements = getElements(orb_arr_cmp(j), &
+            elementType, &
+            frame="ecliptic")
+       IF (error) THEN
+          WRITE(*, *) "Error in fetching the orbit"
+          errorCode = 19
+          RETURN
+       END IF
+       IF (elementType == "keplerian") THEN
+          elements(3:6) = elements(3:6)/rad_deg
+       ELSE IF (elementType == "delaunay") THEN
+          elements(1:3) = elements(1:3)/rad_deg
+       ELSE IF (elementType == "poincare") THEN
+          elements(4) = elements(4)/rad_deg
+       ELSE IF (elementType == "equinoctial") THEN
+          elements(6) = elements(6)/rad_deg
+       END IF
+
+       t0 = getTime(orb_arr_cmp(j))
+       CALL getCalendarDate(t0, "tdt", year, month, day)
+       orbMjd = getMjd(t0, internal_timescale)
+       CALL NULLIFY(t0)
+       IF (error) THEN
+          WRITE(*, *) "Error in getTime/getMjd"
+          errorCode = 5
+          RETURN
+       END IF
+
+
+       WRITE(*, fmt) id, elements(1:6), year, month, day, elementType, &
+            pdf_arr_cmp(j), rchi2_arr_cmp(j), reg_apr_arr_cmp(j), &
+            jac_arr_cmp(j, 1:3)
+
+       !           write(*, *) "elements:             ", elements(1:6)
+       !           write(*, *) "epoch:                ", orbMjd
+       !           write(*, *) "Un-normalized p.d.f.: ", pdf_arr_cmp(j)
+       !           write(*, *) "Reduced chi2:         ", rchi2_arr_cmp(j)
+       !           write(*, *) "Regularized apr:      ", reg_apr_arr_cmp(j)
+       !           write(*, *) "Jacobian det:         ", jac_arr_cmp(j, 1:3)
+    END DO
+    ! WRITE RESIDUALS
+
+    ! This is where we were originally writing out the .res file.
+    ! CALL writeResiduals(storb, obs_in, getUnit(out_file))
+
+    ! Cleanup everything
+    DO j=1,SIZE(orb_arr_cmp)
+       CALL NULLIFY(orb_arr_cmp(j))
+    END DO
+    DEALLOCATE(orb_arr_cmp, stat=err)
+    DEALLOCATE(pdf_arr_cmp, stat=err)
+    DEALLOCATE(rchi2_arr_cmp, stat=err)
+    DEALLOCATE(reg_apr_arr_cmp, stat=err)
+    DEALLOCATE(jac_arr_cmp, stat=err)
+    IF (err /= 0) THEN
+       WRITE(*, *) "Error: Could not deallocate memory"
+       errorCode = 19
+       RETURN
+    END IF
+
+  END SUBROUTINE dumpRangingOrbits
+
+
+  SUBROUTINE dumpLslOrbit(storb, element_type, errorCode)
+    TYPE (StochasticOrbit), INTENT(in)          :: storb
+    CHARACTER(len=*), OPTIONAL, INTENT(in)      :: element_type
+    INTEGER, INTENT(out)                        :: errorCode
+
+    ! Internal variables.
+    REAL(bp), DIMENSION(6)                      :: elements
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    TYPE (Time)                                 :: t0
+    REAL(bp)                                    :: orbMjd
+    INTEGER                                     :: j = 0
+    INTEGER                                     :: k = 0
+    TYPE (Orbit)                                :: orb
+    REAL(bp), DIMENSION(6,6)                    :: cov
+    REAL(bp), DIMENSION(6,6)                    :: corr
+    REAL(bp), DIMENSION(6)                      :: sigmas
+
+
+
+    ! Init
+    errorCode = 0
+    error = .FALSE.
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+
+    ! Get the nominal orbit out.
+    orb = getNominalOrbit(storb)
+    IF (error) THEN
+       WRITE(*, *) "Error in getNominalOrbit()"
+       errorCode = 28
+       RETURN
+    END IF
+
+    ! Get the orbital elements.
+    elements = getElements(orb, elementType, frame="ecliptic")
+    IF (error) THEN
+       WRITE(*, *) "Error in fetching the orbit"
+       errorCode = 19
+       RETURN
+    END IF
+    IF (elementType == "keplerian") THEN
+       elements(3:6) = elements(3:6)/rad_deg
+    ELSE IF (elementType == "delaunay") THEN
+       elements(1:3) = elements(1:3)/rad_deg
+    ELSE IF (elementType == "poincare") THEN
+       elements(4) = elements(4)/rad_deg
+    ELSE IF (elementType == "equinoctial") THEN
+       elements(6) = elements(6)/rad_deg
+    END IF
+
+    ! Get orbit epoch.
+    t0 = getTime(orb)
+    orbMjd = getMjd(t0, internal_timescale)
+    CALL NULLIFY(t0)
+    IF (error) THEN
+       WRITE(*, *) "Error in getTime/getMjd"
+       errorCode = 5
+       RETURN
+    END IF
+
+    ! Covariance matrix.
+    cov = getCovarianceMatrix(storb, elementType, "ecliptic")
+    IF (error) THEN
+       WRITE(*, *) "Error in getCovarianceMatrix"
+       errorCode = 29
+       RETURN
+    END IF
+    DO j=1,6
+       sigmas(j) = SQRT(cov(j, j))
+       IF (elementType == "keplerian" .AND. j >= 3) THEN
+          sigmas(j) = sigmas(j) / rad_deg
+       END IF
+    END DO
+
+    ! Correlations.
+    DO j=1,6
+       DO k=1,6
+          corr(j,k) = cov(j,k) / (sigmas(j)*sigmas(k))
+       END DO
+    END DO
+
+
+    WRITE(*, *) "elements:             ", elements(1:6)
+    WRITE(*, *) "epoch:                ", orbMjd
+    WRITE(*, *) "Covariance:           ", cov
+    WRITE(*, *) "Sigmas:               ", sigmas
+    WRITE(*, *) "Correlation:          ", corr
+
+    ! Cleanup everything
+    CALL NULLIFY(orb)
+
+  END SUBROUTINE dumpLslOrbit
+
+
+  SUBROUTINE dumpEphemeris(storb, ephemerides, cov, pdfs, observers, &
+       obscode, errorCode)
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(inout)                :: storb
+    ! Output ephem array (intent(inout)).
+    TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephemerides
+    ! Ephem uncertainty matrices (intent(inout)).
+    REAL(bp), DIMENSION(:,:,:), POINTER                 :: cov
+    REAL(bp), DIMENSION(:,:), POINTER                   :: pdfs
+    ! observatory coordinates and ephem time array (intent(inout)).
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+    ! Observatory code.
+    CHARACTER(len=*), INTENT(in)                        :: obscode
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal vars.
+    TYPE (Time)                                         :: t
+    INTEGER                                             :: j = 0
+    INTEGER                                             :: k = 0
+    INTEGER                                             :: l = 0
+    REAL(bp)                                            :: mjd_tai = 0.0_bp
+    REAL(bp), DIMENSION(6)                              :: coordinates
+    REAL(bp), DIMENSION(6)                              :: stdev
+    REAL(bp), DIMENSION(6,6)                            :: corr
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+
+
+    DO j=1,SIZE(observers)
+       t = getTime(observers(j))
+       mjd_tai = getMJD(t, internal_timescale)
+       CALL NULLIFY(t)
+       IF (containsSampledPDF(storb)) THEN
+          ! Input orbits correspond to one or more sampled pdfs.
+          ! Loop over sampled orbits:
+          DO k=1,SIZE(ephemerides, dim=1)
+             ! Make sure that the ephemeris is equatorial:
+             CALL rotateToEquatorial(ephemerides(k,j))
+             coordinates = getCoordinates(ephemerides(k,j))
+             WRITE(*, *) TRIM(obscode), &
+                  mjd_tai, coordinates(1), &
+                  coordinates(2:3)/rad_deg, coordinates(4), &
+                  coordinates(5:6)/rad_deg, pdfs(k,j)
+          END DO
+       ELSE
+          ! Input orbits correspond to one or more single-point estimates of the pdf.
+          ! Make sure that the ephemeris is equatorial:
+          CALL rotateToEquatorial(ephemerides(1,j))
+          coordinates = getCoordinates(ephemerides(1,j))
+          DO k=1,6
+             stdev(k) = SQRT(cov(k,k,j)) 
+          END DO
+          DO k=1,6
+             DO l=1,6
+                corr(k,l) = cov(k,l,j) / &
+                     (stdev(k)*stdev(l))
+             END DO
+          END DO
+          WRITE(*, "(A18,28(1X,F18.10))") TRIM(obscode), mjd_tai, &
+               coordinates(1), &
+               coordinates(2:3)/rad_deg, coordinates(4), &
+               coordinates(5:6)/rad_deg, stdev(1), &
+               stdev(2:3)/rad_deg, stdev(4), &
+               stdev(5:6)/rad_deg, corr(1,2:6), &
+               corr(2,3:6), corr(3,4:6), corr(4,5:6), corr(5,6)
+       END IF
+    END DO
+
+  END SUBROUTINE dumpEphemeris
+
+
+  SUBROUTINE readOpenOrbOrbit(fileName, storb, errorCode)
+    CHARACTER(len=*), INTENT(in)                :: fileName
+    TYPE (StochasticOrbit), INTENT(out)         :: storb
+    INTEGER, INTENT(out)                        :: errorCode
+
+    ! Internal vars.
+    INTEGER                                     :: norb = 0
+    TYPE (File)                                 :: orb_in_file
+    CHARACTER(len=1024), DIMENSION(4)           :: header
+    REAL(bp), DIMENSION(:,:), POINTER           :: HG_arr_in
+    INTEGER                                     :: j = 0
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: id_arr_in
+    CHARACTER(len=ELEMENT_TYPE_LEN), DIMENSION(:), ALLOCATABLE :: element_type_pdf_arr_in
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE       :: jac_arr_in
+    REAL(bp), DIMENSION(:,:,:), POINTER         :: cov_arr_in
+    REAL(bp), DIMENSION(:), ALLOCATABLE         :: rchi2_arr_in, &
+         pdf_arr_in, &
+         reg_apr_arr_in
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: element_type_in
+    CHARACTER(len=DESIGNATION_LEN)              :: id
+    TYPE (Orbit), DIMENSION(:), POINTER         :: orb_arr_in
+
+    ! Init vars.
+    error = .FALSE.
+    errorCode = 0
+
+    CALL NEW(orb_in_file, fileName)
+    IF (error) THEN
+       ! Error in creating input file instance
+       errorCode = 30
+       RETURN
+    END IF
+    CALL setStatusOld(orb_in_file)
+    CALL OPEN(orb_in_file)
+    IF (error) THEN
+       ! Error in opeining input file.
+       errorCode = 31
+       RETURN
+    END IF
+    ! 4 header lines are not taken into account.
+    norb = getNrOfLines(orb_in_file) - 4
+    IF (error) THEN
+       ! Error in getNrOfLines()
+       errorCode = 32
+       RETURN
+    END IF
+    ALLOCATE(id_arr_in(norb), orb_arr_in(norb), &
+         element_type_pdf_arr_in(norb), cov_arr_in(norb,6,6), &
+         HG_arr_in(norb,2), pdf_arr_in(norb), &
+         rchi2_arr_in(norb), jac_arr_in(norb,3), &
+         reg_apr_arr_in(norb), stat=errorCode)
+    IF (errorCode /= 0) THEN
+       ! Error in memory allocation
+       errorCode = 33
+       RETURN
+    END IF
+    jac_arr_in = -1.0_bp
+    pdf_arr_in = -1.0_bp
+    cov_arr_in = -1.0_bp
+    id_arr_in = " "
+    element_type_pdf_arr_in = " "
+    header(1:4)(:) = " "
+    FORALL (j=1:norb)
+       HG_arr_in(j,1:2) = (/ 99.0_bp, 9.9_bp /)
+    END FORALL
+    DO j=1,norb
+       CALL readOpenOrbOrbitFile(getUnit(orb_in_file), header, &
+            element_type_in=element_type_in, id=id_arr_in(j), &
+            orb=orb_arr_in(j), &
+            element_type_pdf=element_type_pdf_arr_in(j), &
+            cov=cov_arr_in(j,:,:), H=HG_arr_in(j,1), &
+            G=HG_arr_in(j,2), pdf=pdf_arr_in(j), &
+            rchi2=rchi2_arr_in(j), reg_apr=reg_apr_arr_in(j), &
+            jac_sph_inv=jac_arr_in(j,1), &
+            jac_car_kep=jac_arr_in(j,2), &
+            jac_equ_kep=jac_arr_in(j,3))
+       IF (error) THEN
+          ! Error in readOpenOrbOrbitFile()
+          errorCode = 34
+          RETURN
+       END IF
+    END DO
+    CALL NULLIFY(orb_in_file)
+
+    ! Initialize stochasticorbits if uncertainty information available:
+    IF (norb > 1 .AND. &
+         ALL(pdf_arr_in > 0.0_bp) .AND. &
+         ALL(jac_arr_in > 0.0_bp)) THEN
+       CALL NULLIFY(storb)
+       CALL NEW(storb, orb_arr_in, pdf_arr_in, &
+            element_type_pdf_arr_in(1), jac_arr=jac_arr_in, &
+            reg_apr_arr=reg_apr_arr_in, &
+            rchi2_arr=rchi2_arr_in)
+       id = id_arr_in(1)
+       DEALLOCATE(id_arr_in)
+       ALLOCATE(id_arr_in(1))
+       id_arr_in(1) = id
+    ELSE IF (norb == 1 .AND. ALL(cov_arr_in(:,1,1) > 0.0_bp)) THEN
+       CALL NEW(storb, orb_arr_in(1), cov_arr_in(1,:,:), &
+            cov_type=element_type_in, element_type=element_type_in)
+    ELSE
+       ! Error in StochasticOrbit instantiation
+       errorCode = 34
+       RETURN
+    END IF
+
+    ! Cleanup.
+    DO j=1,norb
+       CALL NULLIFY(orb_arr_in(j))
+    END DO
+    DEALLOCATE(orb_arr_in, pdf_arr_in, rchi2_arr_in, jac_arr_in, &
+         reg_apr_arr_in, element_type_pdf_arr_in)
+
+  END SUBROUTINE readOpenOrbOrbit
+
+
+  SUBROUTINE rangingOrbitsToStochasticOrbit(orbits, norb, storb, errorCode)
+    ! Flattened orbit array. Each elememnt is
+    !  (id, elements(1:6), epoch_mjd, Un-normalized p.d.f., Reduced chi2, 
+    !   Regularized apr, Jacobian det(1:3), element_type_index)
+    INTEGER, INTENT(in)                         :: norb
+    REAL(bp), DIMENSION(norb, 15), INTENT(in)   :: orbits
+    TYPE (StochasticOrbit), INTENT(out)         :: storb
+    INTEGER, INTENT(out)                        :: errorCode
+
+    ! Internal vars.
+    REAL(bp), DIMENSION(:,:), POINTER           :: HG_arr_in
+    INTEGER                                     :: j = 0
+    INTEGER                                     :: i = 0
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: id_arr_in
+    CHARACTER(len=ELEMENT_TYPE_LEN), DIMENSION(:), ALLOCATABLE :: element_type_pdf_arr_in
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE       :: jac_arr_in
+    REAL(bp), DIMENSION(:,:,:), POINTER         :: cov_arr_in
+    REAL(bp), DIMENSION(:), ALLOCATABLE         :: rchi2_arr_in, &
+         pdf_arr_in, &
+         reg_apr_arr_in
+    CHARACTER(len=DESIGNATION_LEN)              :: id
+    TYPE (Orbit), DIMENSION(:), POINTER         :: orb_arr_in
+    REAL(bp), DIMENSION(15)                     :: correlation
+    REAL(bp), DIMENSION(6)                      :: stdev
+    REAL(bp), DIMENSION(6)                      :: elements
+    TYPE(Time)                                  :: t
+    CHARACTER(len=11)                           :: element_type
+    INTEGER                                     :: element_type_index = -1
+
+
+    ! Init vars.
+    error = .FALSE.
+    errorCode = 0
+
+    ! Get the element type from the input flattened orbits (the are supposed 
+    ! be all the same).
+    element_type_index = orbits(1, 15)
+    IF(element_type_index .LE. 0 .OR.                               &
+         element_type_index .GT. SIZE(ORBITAL_ELEMENTS)) THEN
+       ! Error: unsupported orbital elements.
+       errorCode = 58
+       RETURN
+    END IF
+    element_type = ORBITAL_ELEMENTS(element_type_index)
+
+    ! Allocate memory for the orbit arrays.
+    ALLOCATE(id_arr_in(norb), orb_arr_in(norb), &
+         element_type_pdf_arr_in(norb), cov_arr_in(norb,6,6), &
+         HG_arr_in(norb,2), pdf_arr_in(norb), &
+         rchi2_arr_in(norb), jac_arr_in(norb,3), &
+         reg_apr_arr_in(norb), stat=errorCode)
+    IF (errorCode /= 0) THEN
+       ! Error in memory allocation
+       errorCode = 33
+       RETURN
+    END IF
+    jac_arr_in = -1.0_bp
+    pdf_arr_in = -1.0_bp
+    cov_arr_in = 0.0_bp
+    id_arr_in = " "
+    ! There are no H/G in the input orbits.
+    FORALL (j=1:norb)
+       HG_arr_in(j,1:2) = (/ 99.0_bp, 9.9_bp /)
+    END FORALL
+    stdev = -1.0_bp
+    correlation = 2.0_bp
+    element_type_pdf_arr_in = element_type
+
+    ! Get each flattened orbit and create an Orbit instance.
+    DO j=1,norb
+       ! Just to beat on a dead horse:
+       ! orbits(j,1):      id
+       ! orbits(j,2:7):    elements(1:6)
+       ! orbits(j,8):      epoch_mjd
+       ! orbits(j,9):      Un-normalized p.d.f.
+       ! orbits(j,10):     Reduced chi2
+       ! orbits(j,11):     Regularized apr
+       ! orbits(j,12:14):  Jacobian det(1:3)
+       ! orbits(j,15):     element_type_index
+       ! Convert angles to radians, if needed.
+       WRITE(id_arr_in(j), fmt="(A,I10.10)") "TRK", IDINT(orbits(j, 1))
+
+       elements(1:6) = orbits(j,2:7)
+       IF (element_type == "keplerian") THEN
+          elements(3:6) = elements(3:6) * rad_deg
+       ELSE IF (element_type == "delaunay") THEN
+          elements(1:3) = elements(1:3) * rad_deg
+       ELSE IF (element_type == "poincare") THEN
+          elements(4) = elements(4) * rad_deg
+       ELSE IF (element_type == "equinoctial") THEN
+          elements(6) = elements(6) * rad_deg
+       END IF
+
+       ! Create a Time instance.
+       CALL NEW(t, orbits(j, 8), internal_timescale)
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          errorCode = 57
+          RETURN
+       END IF
+
+       ! Now create an Orbit instance.
+       CALL NEW(orb_arr_in(j),                                 &
+            elements(1:6),                                 &
+            element_type,                                  &
+            "ecliptic",                                    &
+            copy(t))
+       CALL NULLIFY(t)
+
+       ! Covariance: we fake it since we do not have it.
+       cov_arr_in(j,:,:) = 0.0_bp
+       DO i=1,6
+          cov_arr_in(j,i,i) = -1.0_bp
+       END DO
+
+       ! Populate the uncertinty arrays.
+       pdf_arr_in(j) = orbits(j, 9)
+       rchi2_arr_in(j) = orbits(j, 10)
+       reg_apr_arr_in(j) = orbits(j, 11)
+       jac_arr_in(j,1:3) = orbits(j, 12:14)
+    END DO
+
+    ! Initialize stochasticorbits if uncertainty information available:
+    IF (norb > 1 .AND. &
+         ALL(pdf_arr_in > 0.0_bp) .AND. &
+         ALL(jac_arr_in > 0.0_bp)) THEN
+       CALL NULLIFY(storb)
+       CALL NEW(storb, orb_arr_in, pdf_arr_in, &
+            element_type_pdf_arr_in(1), jac_arr=jac_arr_in, &
+            reg_apr_arr=reg_apr_arr_in, &
+            rchi2_arr=rchi2_arr_in)
+       id = id_arr_in(1)
+       DEALLOCATE(id_arr_in)
+       ALLOCATE(id_arr_in(1))
+       id_arr_in(1) = id
+    ELSE IF (norb == 1 .AND. ALL(cov_arr_in(:,1,1) > 0.0_bp)) THEN
+       CALL NEW(storb, orb_arr_in(1), cov_arr_in(1,:,:), &
+            cov_type=element_type, element_type=element_type)
+    ELSE
+       ! Error in StochasticOrbit instantiation
+       errorCode = 34
+       RETURN
+    END IF
+
+    ! Cleanup.
+    DO j=1,norb
+       CALL NULLIFY(orb_arr_in(j))
+    END DO
+    DEALLOCATE(orb_arr_in, pdf_arr_in, rchi2_arr_in, jac_arr_in, &
+         reg_apr_arr_in, element_type_pdf_arr_in)
+
+  END SUBROUTINE rangingOrbitsToStochasticOrbit
+
+
+  SUBROUTINE lslOrbitToStochasticOrbit(in_orbit,                          &
+       in_covariance,                     &
+       storb,                             &
+       errorCode)
+    ! Input/Output variables.
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+    ! FIXME: H and G are not currently computed.
+    REAL(8),DIMENSION(11), INTENT(in)                   :: in_orbit
+    ! Uncertainty matrices:
+    REAL(8), DIMENSION(6,6), INTENT(in)                 :: in_covariance
+    TYPE(StochasticOrbit), INTENT(out)                  :: storb
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal vars.
+    REAL(bp), DIMENSION(:,:), POINTER           :: HG_arr_in
+    INTEGER                                     :: j = 0
+    CHARACTER(len=DESIGNATION_LEN), DIMENSION(:), POINTER :: id_arr_in
+    CHARACTER(len=ELEMENT_TYPE_LEN), DIMENSION(:), ALLOCATABLE :: element_type_pdf_arr_in
+    REAL(bp), DIMENSION(:,:), ALLOCATABLE       :: jac_arr_in
+    REAL(bp), DIMENSION(:,:,:), POINTER         :: cov_arr_in
+    REAL(bp), DIMENSION(:), ALLOCATABLE         :: rchi2_arr_in, &
+         pdf_arr_in, &
+         reg_apr_arr_in
+    CHARACTER(len=DESIGNATION_LEN)              :: id
+    TYPE (Orbit), DIMENSION(:), POINTER         :: orb_arr_in
+    REAL(bp), DIMENSION(6)                      :: elements
+    TYPE(Time)                                  :: t
+    CHARACTER(len=11)                           :: element_type
+    INTEGER                                     :: element_type_index = -1
+    INTEGER                                     :: norb = 1
+
+
+    ! Init vars.
+    error = .FALSE.
+    errorCode = 0
+    ! We try to keep these two subroutines similar so that we can merge in 
+    ! the future, hence the norb = 1 thing here.
+    norb = 1
+
+    ! Get the element type from the input flattened in_orbit.
+    element_type_index = in_orbit(11)
+    IF(element_type_index .LE. 0 .OR.                               &
+         element_type_index .GT. SIZE(ORBITAL_ELEMENTS)) THEN
+       ! Error: unsupported orbital elements.
+       errorCode = 58
+       RETURN
+    END IF
+    element_type = ORBITAL_ELEMENTS(element_type_index)
+
+    ! Allocate memory for the orbit arrays.
+    ALLOCATE(id_arr_in(norb), orb_arr_in(norb), &
+         element_type_pdf_arr_in(norb), cov_arr_in(norb,6,6), &
+         HG_arr_in(norb,2), pdf_arr_in(norb), &
+         rchi2_arr_in(norb), jac_arr_in(norb,3), &
+         reg_apr_arr_in(norb), stat=errorCode)
+    IF (errorCode /= 0) THEN
+       ! Error in memory allocation
+       errorCode = 33
+       RETURN
+    END IF
+    jac_arr_in = -1.0_bp
+    pdf_arr_in = -1.0_bp
+    cov_arr_in = 0.0_bp
+    id_arr_in = " "
+    ! There are no H/G in the input in_orbit.
+    FORALL (j=1:norb)
+       HG_arr_in(j,1:2) = (/ 99.0_bp, 9.9_bp /)
+    END FORALL
+    element_type_pdf_arr_in = element_type
+
+    ! Get each flattened orbit and create an Orbit instance.
+    DO j=1,norb
+       ! Just to beat on a dead horse:
+       ! in_orbit(1):      id
+       ! in_orbit(2:7):    elements(1:6)
+       ! in_orbit(8):      epoch_mjd
+       ! in_orbit(9):      H
+       ! in_orbit(10):     G
+       ! in_orbit(j,11):   element_type_index
+       ! Convert angles to radians, if needed.
+       WRITE(id_arr_in(j), fmt="(A,I10.10)") "TRK", IDINT(in_orbit(1))
+
+       elements(1:6) = in_orbit(2:7)
+       IF (element_type == "keplerian") THEN
+          elements(3:6) = elements(3:6) * rad_deg
+       ELSE IF (element_type == "delaunay") THEN
+          elements(1:3) = elements(1:3) * rad_deg
+       ELSE IF (element_type == "poincare") THEN
+          elements(4) = elements(4) * rad_deg
+       ELSE IF (element_type == "equinoctial") THEN
+          elements(6) = elements(6) * rad_deg
+       END IF
+
+       ! Create a Time instance.
+       CALL NEW(t, in_orbit(8), internal_timescale)
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          errorCode = 57
+          RETURN
+       END IF
+
+       ! Now create an Orbit instance.
+       CALL NEW(orb_arr_in(j),                                 &
+            elements(1:6),                                 &
+            element_type,                                  &
+            "ecliptic",                                    &
+            copy(t))
+       CALL NULLIFY(t)
+
+       ! Covariance. We do not need to re-compute it since we already have 
+       ! it.
+       cov_arr_in(j,:,:) = in_covariance(:,:)
+    END DO
+
+    ! Initialize stochasticorbits if uncertainty information available:
+    IF (norb > 1 .AND. &
+         ALL(pdf_arr_in > 0.0_bp) .AND. &
+         ALL(jac_arr_in > 0.0_bp)) THEN
+       CALL NULLIFY(storb)
+       CALL NEW(storb, orb_arr_in, pdf_arr_in, &
+            element_type_pdf_arr_in(1), jac_arr=jac_arr_in, &
+            reg_apr_arr=reg_apr_arr_in, &
+            rchi2_arr=rchi2_arr_in)
+       id = id_arr_in(1)
+       DEALLOCATE(id_arr_in)
+       ALLOCATE(id_arr_in(1))
+       id_arr_in(1) = id
+    ELSE IF (norb == 1 .AND. ALL(cov_arr_in(:,1,1) > 0.0_bp)) THEN
+       CALL NEW(storb, orb_arr_in(1), cov_arr_in(1,:,:), &
+            cov_type=element_type, element_type=element_type)
+    ELSE
+       ! Error in StochasticOrbit instantiation
+       errorCode = 34
+       RETURN
+    END IF
+
+    ! Cleanup.
+    DO j=1,norb
+       CALL NULLIFY(orb_arr_in(j))
+    END DO
+    DEALLOCATE(orb_arr_in, pdf_arr_in, rchi2_arr_in, jac_arr_in, &
+         reg_apr_arr_in, element_type_pdf_arr_in)
+
+  END SUBROUTINE lslOrbitToStochasticOrbit
+
+
+
+  SUBROUTINE readObsFile(fileName, stdev, obss, errorCode)
+    ! Input/output vars
+    CHARACTER(len=*), INTENT(in)                            :: fileName
+    ! This most likely comes from a config file. If not, remember that all
+    ! angles are in radians and that stdev(2) = RAErr and stdev(3) = DecErr.
+    REAL(bp), DIMENSION(6), OPTIONAL, INTENT(in)            :: stdev
+    ! Remember pointers need to be intent(inout), which is the default.
+    TYPE (Observations), DIMENSION(:), POINTER              :: obss
+    INTEGER, INTENT(out)                                    :: errorCode
+
+    ! Internal vars
+    REAL(bp), DIMENSION(6)                                  :: stdevArray
+    TYPE(File)                                              :: obs_file
+    TYPE(Observations)                                      :: rawObss
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+    stdevArray = 0.3_bp * rad_asec
+    IF(PRESENT(stdev)) THEN
+       stdevArray = stdev
+    END IF
+
+    ! Open the file.
+    CALL NEW(obs_file, TRIM(fileName))
+    CALL setStatusOld(obs_file)
+    CALL OPEN(obs_file)
+    IF (error) THEN
+       ! Error in opening observation file.
+       errorCode = 46
+       RETURN
+    END IF
+    CALL NEW(rawObss, obs_file, stdev=stdevArray)
+    CALL NULLIFY(obs_file)
+
+    ! Split the raw observations into sets.
+    obss => getSeparatedSets(rawObss)
+    CALL NULLIFY(rawObss)
+
+  END SUBROUTINE readObsFile
+
+
+  SUBROUTINE obssFromCoords(trackId, n, coords, mjds, mags, filters, &
+       obscodes, obss, errorCode)
+    ! obssFromCoords
+    ! 
+    ! Create a list of Observations instances from the input coordinate 
+    ! array.
+    ! @param trackId: object ID. IDs are used to group observations of the 
+    !        same object together (equivalent to track IDs in PS-MOPS). IDs 
+    !        are numbers.
+    ! @param n: number of coordinates to process.
+    ! @param coords: array of [(ra, ra_err, dec, dec_err), ] coordinates in
+    !        radians.
+    ! @param mjds: array of MJDs (TAI), one per coords element. These are
+    !        the MJDs of the input observations/DiaSources/Detections.
+    ! @param mags: array of observed magnitudes, one per coords element.
+    !        mags are floats.
+    ! @param filters: array of filter names, one per coords element.
+    !        Filters are (usually 1 or 2-letter) strings
+    ! @param obscodes: array of MPC observatory codes, one per coords 
+    !        element. Observatory codes are (up to 4 letter) strings.
+    ! 
+    ! @param obss: array of Observations instances, one element per unique 
+    !        input ID.
+    ! @param errorCode: error code. Anything other than 0 signals an error.
+    INTEGER, INTENT(in)                                     :: trackId
+    INTEGER, INTENT(in)                                     :: n
+    REAL(bp), DIMENSION(n,4), INTENT(in)                    :: coords
+    REAL(bp), DIMENSION(n), INTENT(in)                      :: mjds
+    REAL(bp), DIMENSION(n), INTENT(in)                      :: mags
+    CHARACTER(len=*), DIMENSION(n), INTENT(in)              :: filters
+    CHARACTER(len=OBSY_CODE_LEN), DIMENSION(n),INTENT(in)   :: obscodes
+    ! Pointers have to be intent(inout)!
+    TYPE (Observations), DIMENSION(:), POINTER              :: obss
+    INTEGER, INTENT(out)                                    :: errorCode
+
+    ! Internal variables.
+    TYPE(Observations)                                      :: rawObss
+    LOGICAL, DIMENSION(6)                                   :: obs_mask
+    INTEGER                                                 :: i = 0
+    TYPE(Time)                                              :: t
+    TYPE (SphericalCoordinates)                             :: obs_scoord
+    REAL(bp), DIMENSION(6,6)                                :: covariance
+    REAL(bp)                                                :: ra = 0.0_bp
+    REAL(bp)                                                :: dec = 0.0_bp
+    REAL(bp)                                                :: raErr=0.0_bp
+    REAL(bp)                                                :: decErr=0.0_bp
+    TYPE (Observatory)                                      :: obsy
+    TYPE (CartesianCoordinates)                             :: obsy_ccoord
+    TYPE(Observation)                                       :: obs
+    CHARACTER(len=255)                                      :: designation
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+    designation = " "
+    ! We only have RA and Dec and obs_mask is
+    ! (radial distance, longitude, latitude + their time derivatives), so:
+    obs_mask = (/ .FALSE., .TRUE., .TRUE., .FALSE., .FALSE., .FALSE. /)
+    CALL NEW(rawObss)
+    IF(n .LE. 0) THEN
+       ! Now enough data!
+       errorCode = 50
+       RETURN
+    END IF
+
+    ! Loop through the input arrays and create Observations!
+    DO i=1,n
+       ! Extract RA/Dec etc from coords.
+       ra = coords(i, 1)
+       raErr = coords(i, 2)
+       dec = coords(i, 3)
+       decErr = coords(i, 4)
+
+       ! Create a Time instance using the input mjd.
+       CALL NEW(t, mjds(i), internal_timescale)
+       IF(error) THEN
+          ! Error in creating Time instnce.
+          errorCode = 51
+          RETURN
+       END IF
+
+       ! Create SphericalCoordinates object containing R.A. Dec. epoch.
+       CALL NEW(obs_scoord, ra, dec, t)
+       IF (error) THEN
+          ! Error in creating a neSphericalCoordinates instance.
+          errorCode = 52
+          RETURN
+       END IF
+
+       ! Now set the covariance matrix.
+       covariance = 0.0_bp
+       covariance(2,2) = raErr**2.0_bp
+       covariance(3,3) = decErr**2.0_bp
+
+       !             write(*, *) "cov: ", covariance
+
+       ! Compute the heliocentric position of the observer at epoch t:
+       obsy = getObservatory(obsies, TRIM(obscodes(i)))
+       IF (error) THEN
+          ! Error in deriving the observatory location!
+          errorCode = 48
+          RETURN
+       END IF
+       obsy_ccoord = getObservatoryCCoord(obsies, obsy, t)
+
+       ! Create observation object:
+       CALL NULLIFY(obs)
+       WRITE(designation, fmt="(A,I10.10)") "TRK", trackId
+       CALL NEW(obs, &
+            number=trackId, &
+            designation=TRIM(designation), &
+            discovery=.FALSE., &
+            note1=" ", &
+            note2=" ", &
+            obs_scoord=obs_scoord, &
+            covariance=covariance, &
+            obs_mask=obs_mask, &
+            mag=mags(i), &
+            filter=TRIM(filters(i)), &
+            obsy=obsy, &
+            obsy_ccoord=obsy_ccoord)
+       IF (error) THEN
+          ! Error in creating a new Observation instance.
+          errorCode = 49
+          RETURN
+       END IF
+
+       CALL addObservation(rawObss, obs, sort=.TRUE.)
+       IF(error) THEN
+          ! Error in adding a new observation.
+          errorCode = 53
+          RETURN
+       END IF
+
+       CALL NULLIFY(obs)
+       CALL NULLIFY(obs_scoord)
+       CALL NULLIFY(t)
+       CALL NULLIFY(obsy)
+       CALL NULLIFY(obsy_ccoord)
+    END DO
+
+    ! Split the raw observatikons into one list per ID.
+    obss => getSeparatedSets(rawObss)
+    CALL NULLIFY(rawObss)
+
+  END SUBROUTINE obssFromCoords
+
+
+  SUBROUTINE exportRangingOrbits(storb, element_type, track_id, outOrbits, &
+       errorCode)
+    TYPE (StochasticOrbit), INTENT(in)              :: storb
+    CHARACTER(len=*), OPTIONAL, INTENT(in)          :: element_type
+    INTEGER, INTENT(in)                             :: track_id
+    ! outOrbits has the form ((id, elements(1:6), epoch, Un-normalized pdf,
+    ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+    REAL(bp),DIMENSION(:,:),INTENT(out)             :: outOrbits
+    INTEGER, INTENT(out)                            :: errorCode
+
+    ! Internal variables.
+    REAL(bp), DIMENSION(2,2)                    :: sor_rho_cmp
+    TYPE (Orbit), DIMENSION(:), POINTER         :: orb_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: pdf_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: rchi2_arr_cmp
+    REAL(bp), DIMENSION(:), POINTER             :: reg_apr_arr_cmp
+    REAL(bp), DIMENSION(:,:), POINTER           :: jac_arr_cmp
+    INTEGER                                     :: numOutOrbits
+    REAL(bp), DIMENSION(6)                      :: elements
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    TYPE (Time)                                 :: t0
+    REAL(bp)                                    :: orbMjd
+    INTEGER                                     :: j = 0
+    INTEGER                                     :: err = 0
+    INTEGER                                     :: element_type_index = -1
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+    ! Figure out the element_type_index
+    DO j=1,SIZE(ORBITAL_ELEMENTS)
+       IF(elementType == ORBITAL_ELEMENTS(j)) THEN
+          element_type_index = j
+          EXIT
+       END IF
+    END DO
+    IF(element_type_index .LE. 0) THEN
+       ! Error: unsupported element type!
+       errorCode = 58
+       RETURN
+    END IF
+
+    CALL getResults(storb, sor_rho_cmp=sor_rho_cmp)
+    IF (error) THEN
+       ! write(*, *) "Error in getResults()"
+       errorCode = 15
+       RETURN
+    END IF
+    ! Get ORBITAL-ELEMENT PDF
+    orb_arr_cmp => getSampleOrbits(storb)
+    IF (error) THEN
+       ! write(*, *) "Error in getSampleOrbits()"
+       errorCode = 16
+       RETURN
+    END IF
+    pdf_arr_cmp => getPDFValues(storb)
+    IF (error) THEN
+       ! write(*, *) "Error in getPDFValues()"
+       errorCode = 17
+       RETURN
+    END IF
+    rchi2_arr_cmp => getReducedChi2Distribution(storb)
+    IF (error) THEN
+       ! write(*, *) "Error in getReducedChi2Distribution()"
+       errorCode = 17
+       RETURN
+    END IF
+    CALL getResults(storb, &
+         reg_apr_arr=reg_apr_arr_cmp, &
+         jac_arr=jac_arr_cmp)
+    IF (error) THEN
+       ! write(*, *) "Error in getResults()"
+       numOutOrbits = 0
+       errorCode = 18
+       RETURN
+    END IF
+
+    ! This is where we wrere originally writing the .orb file(s) out.
+    numOutOrbits = SIZE(orb_arr_cmp,dim=1)
+    !        if(.not. allocated(outOrbits)) then
+    !            allocate(outOrbits(numOutOrbits, 14), stat=err)
+    !        end if
+    !        if(err /= 0) then
+    !            ! Error in allocating memory.
+    !            errorCode = 54
+    !            return
+    !        end if
+    DO j=1,numOutOrbits
+       elements = getElements(orb_arr_cmp(j), &
+            elementType, &
+            frame="ecliptic")
+       IF (error) THEN
+          ! write(*, *) "Error in fetching the orbit"
+          errorCode = 19
+          RETURN
+       END IF
+       IF (elementType == "keplerian") THEN
+          elements(3:6) = elements(3:6)/rad_deg
+       ELSE IF (elementType == "delaunay") THEN
+          elements(1:3) = elements(1:3)/rad_deg
+       ELSE IF (elementType == "poincare") THEN
+          elements(4) = elements(4)/rad_deg
+       ELSE IF (elementType == "equinoctial") THEN
+          elements(6) = elements(6)/rad_deg
+       END IF
+
+       t0 = getTime(orb_arr_cmp(j))
+       orbMjd = getMjd(t0, internal_timescale)
+       CALL NULLIFY(t0)
+       IF (error) THEN
+          ! write(*, *) "Error in getTime/getMjd"
+          errorCode = 5
+          RETURN
+       END IF
+
+       ! Add the values to outOrbits.
+       ! outOrbits has the form (elements(1:6), epoch, Un-normalized p.d.f.,
+       ! Reduced chi2, Regularized apr, Jacobian det(1:3))
+       outOrbits(j, 1) = track_id
+       outOrbits(j, 2:7) = elements(1:6)
+       outOrbits(j, 8) = orbMjd
+       outOrbits(j, 9) = pdf_arr_cmp(j)
+       outOrbits(j, 10) = rchi2_arr_cmp(j)
+       outOrbits(j, 11) = reg_apr_arr_cmp(j)
+       outOrbits(j, 12:14) = jac_arr_cmp(j, 1:3)
+       outOrbits(j, 15) = element_type_index
+
+       !           write(*, *) "elements:             ", elements(1:6)
+       !           write(*, *) "epoch:                ", orbMjd
+       !           write(*, *) "Un-normalized p.d.f.: ", pdf_arr_cmp(j)
+       !           write(*, *) "Reduced chi2:         ", rchi2_arr_cmp(j)
+       !           write(*, *) "Regularized apr:      ", reg_apr_arr_cmp(j)
+       !           write(*, *) "Jacobian det:         ", jac_arr_cmp(j, 1:3)
+    END DO
+
+    ! Cleanup everything
+    DO j=1,numOutOrbits
+       CALL NULLIFY(orb_arr_cmp(j))
+    END DO
+    DEALLOCATE(orb_arr_cmp, stat=err)
+    DEALLOCATE(pdf_arr_cmp, stat=err)
+    DEALLOCATE(rchi2_arr_cmp, stat=err)
+    DEALLOCATE(reg_apr_arr_cmp, stat=err)
+    DEALLOCATE(jac_arr_cmp, stat=err)
+    IF (err /= 0) THEN
+       ! write(*, *) "Error: Could not deallocate memory"
+       errorCode = 19
+       RETURN
+    END IF
+
+  END SUBROUTINE exportRangingOrbits
+
+
+  SUBROUTINE exportLslOrbit(storb, element_type, track_id, outOrbit,      &
+       outCovariance, outSigmas, outCorrelation,     &
+       errorCode)
+    TYPE (StochasticOrbit), INTENT(in)          :: storb
+    CHARACTER(len=*), OPTIONAL, INTENT(in)      :: element_type
+    INTEGER, INTENT(in)                         :: track_id
+    ! outOrbit has the form (track_id, elements(1:6), epoch, H, G)
+    REAL(bp), DIMENSION(11), INTENT(out)        :: outOrbit
+    REAL(bp), DIMENSION(6,6), INTENT(out)       :: outCovariance
+    REAL(bp), DIMENSION(6)                      :: outSigmas
+    REAL(bp), DIMENSION(6,6)                    :: outCorrelation
+    INTEGER, INTENT(out)                        :: errorCode
+
+    ! Internal variables.
+    REAL(bp), DIMENSION(6)                      :: elements
+    CHARACTER(len=ELEMENT_TYPE_LEN)             :: elementType = "keplerian"
+    TYPE (Time)                                 :: t0
+    REAL(bp)                                    :: orbMjd
+    INTEGER                                     :: j = 0
+    INTEGER                                     :: k = 0
+    TYPE (Orbit)                                :: orb
+    INTEGER                                     :: element_type_index = -1
+
+
+    ! Init
+    errorCode = 0
+    error = .FALSE.
+    IF(PRESENT(element_type)) THEN
+       elementType = element_type
+    END IF
+    ! Figure out the element_type_index
+    DO j=1,SIZE(ORBITAL_ELEMENTS)
+       IF(elementType == ORBITAL_ELEMENTS(j)) THEN
+          element_type_index = j
+          EXIT
+       END IF
+    END DO
+    IF(element_type_index .LE. 0) THEN
+       ! Error: unsupported element type!
+       errorCode = 58
+       RETURN
+    END IF
+
+    ! Get the nominal orbit out.
+    orb = getNominalOrbit(storb)
+    IF (error) THEN
+       ! write(*, *) "Error in getNominalOrbit()"
+       errorCode = 28
+       RETURN
+    END IF
+
+    ! Get the orbital elements.
+    elements = getElements(orb, elementType, frame="ecliptic")
+    IF (error) THEN
+       ! write(*, *) "Error in fetching the orbit"
+       errorCode = 19
+       RETURN
+    END IF
+    IF (elementType == "keplerian") THEN
+       elements(3:6) = elements(3:6)/rad_deg
+    ELSE IF (elementType == "delaunay") THEN
+       elements(1:3) = elements(1:3)/rad_deg
+    ELSE IF (elementType == "poincare") THEN
+       elements(4) = elements(4)/rad_deg
+    ELSE IF (elementType == "equinoctial") THEN
+       elements(6) = elements(6)/rad_deg
+    END IF
+
+    ! Get orbit epoch.
+    t0 = getTime(orb)
+    orbMjd = getMjd(t0, internal_timescale)
+    CALL NULLIFY(t0)
+    IF (error) THEN
+       ! write(*, *) "Error in getTime/getMjd"
+       errorCode = 5
+       RETURN
+    END IF
+
+    ! FIXME: compute H and G.
+    outOrbit(1) = track_id
+    outOrbit(2:7) = elements(1:6)
+    outOrbit(8) = orbMjd
+    outOrbit(9) = 99.0_bp                               ! FIXME: compute H
+    outOrbit(10) = 9.9_bp                               ! FIXME: compute G
+    outOrbit(11) = element_type_index
+
+    ! Covariance matrix.
+    outCovariance = getCovarianceMatrix(storb, elementType, "ecliptic")
+    IF (error) THEN
+       ! write(*, *) "Error in getCovarianceMatrix"
+       errorCode = 29
+       RETURN
+    END IF
+    DO j=1,6
+       outSigmas(j) = SQRT(outCovariance(j, j))
+       IF (elementType == "keplerian" .AND. j >= 3) THEN
+          outSigmas(j) = outSigmas(j) / rad_deg
+       END IF
+    END DO
+
+    ! Correlations.
+    DO j=1,6
+       DO k=1,6
+          outCorrelation(j,k) = outCovariance(j,k) /                &
+               (outSigmas(j) * outSigmas(k))
+       END DO
+    END DO
+
+    !        write(*, *) "elements:             ", elements(1:6)
+    !        write(*, *) "epoch:                ", orbMjd
+    !        write(*, *) "Covariance:           ", outCovariance
+    !        write(*, *) "Sigmas:               ", outSigmas
+    !        write(*, *) "Correlation:          ", outCorrelation
+
+    ! Cleanup everything
+    CALL NULLIFY(orb)
+
+  END SUBROUTINE exportLslOrbit
+
+
+  SUBROUTINE exportEphemeris(storb, ephemerides, cov, observers, &
+       outEphems, errorCode)
+    ! Input/Output variables.
+    TYPE(StochasticOrbit), INTENT(inout)                :: storb
+    ! Output ephem array (intent(inout)).
+    TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephemerides
+    ! Ephem uncertainty matrices (intent(inout)).
+    REAL(bp), DIMENSION(:,:,:), POINTER                 :: cov
+    ! observatory coordinates and ephem time array (intent(inout)).
+    TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+    ! Output ephems:
+    !   ((dist, ra, dec, mag, mjd, raErr, decErr, smia, smaa, pa), )
+    REAL(bp), DIMENSION(SIZE(observers),10),INTENT(out) :: outEphems
+    ! Output error code
+    INTEGER, INTENT(out)                                :: errorCode
+
+    ! Internal vars.
+    TYPE (Time)                                         :: t
+    INTEGER                                             :: j = 0
+    INTEGER                                             :: k = 0
+    INTEGER                                             :: l = 0
+    REAL(bp)                                            :: mjd = 0.0_bp
+    REAL(bp), DIMENSION(6)                              :: coordinates
+    REAL(bp), DIMENSION(6)                              :: stdev
+    REAL(bp), DIMENSION(6,6)                            :: corr
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+
+
+    DO j=1,SIZE(observers)
+       t = getTime(observers(j))
+       mjd = getMJD(t, internal_timescale)
+       CALL NULLIFY(t)
+       IF (containsSampledPDF(storb)) THEN
+          ! We do not support exporting ephems from ranging orbits yet.
+          ! FIXME: support ephems from ranging orbits?
+          errorCode = 59
+          RETURN
+       END IF
+
+       ! Input orbits correspond to one or more single-point estimates of the pdf.
+       ! Make sure that the ephemeris is equatorial:
+       CALL rotateToEquatorial(ephemerides(1,j))
+       coordinates = getCoordinates(ephemerides(1,j))
+       DO k=1,6
+          stdev(k) = SQRT(cov(k,k,j)) 
+       END DO
+       DO k=1,6
+          DO l=1,6
+             corr(k,l) = cov(k,l,j) / &
+                  (stdev(k)*stdev(l))
+          END DO
+       END DO
+
+       ! Write the output ephem array.
+       outEphems(j, 1) = coordinates(1)                ! distance
+       outEphems(j, 2:3) = coordinates(2:3)/rad_deg    ! ra/dec
+       ! FIXME: compute predicted magnitude!
+       outEphems(j, 4) = 99.0_bp                       ! mag
+       outEphems(j, 5) = mjd                           ! ephem mjd
+       ! FIXME: compute positional uncertainties.
+       outEphems(j, 6) = 99.0_bp                       ! raErr
+       outEphems(j, 7) = 99.0_bp                       ! decErr
+       outEphems(j, 8) = 99.0_bp                       ! semi-major axis
+       outEphems(j, 9) = 99.0_bp                       ! semi-minor axis
+       outEphems(j, 10) = 99.0_bp                      ! position angle
+    END DO
+
+  END SUBROUTINE exportEphemeris
+
+
+
+  SUBROUTINE calendarDateToMjd(year, month, day, mjd, timescale, errorCode)
+    INTEGER, INTENT(in)                             :: year
+    INTEGER, INTENT(in)                             :: month
+    ! day + time in fractional days.
+    REAL(bp), INTENT(in)                            :: day
+    CHARACTER(len=*), INTENT(in)                    :: timescale
+    REAL(bp), INTENT(out)                           :: mjd
+    INTEGER, INTENT(out)                            :: errorCode
+
+    ! Internal vars.
+    TYPE(Time)                                      :: t
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+
+    ! Create a Time instance.
+    CALL NEW(t, year, month, day, TRIM(timescale))
+    IF(error) THEN
+       ! Error in creating a Time object.
+       errorCode = 55
+       RETURN
+    END IF
+
+    ! Convert to MJD TAI
+    mjd = getMjd(t, internal_timescale)
+    IF(error) THEN
+       ! Error in converting to MJD.
+       errorCode = 56
+       RETURN
+    END IF
+
+    ! Cleanup.
+    CALL NULLIFY(t)
+
+  END SUBROUTINE calendarDateToMjd
+
+
+  SUBROUTINE mjdConvert(mjdIn, timescaleIn, mjdOut, timescaleOut, errorCode)
+    ! Input variables
+    REAL(bp), INTENT(in)                            :: mjdIn
+    CHARACTER(len=*), INTENT(in)                    :: timescaleIn
+    REAL(bp), INTENT(out)                           :: mjdOut
+    CHARACTER(len=*), INTENT(in)                    :: timescaleOut
+    INTEGER, INTENT(out)                            :: errorCode
+
+    ! Internal vars.
+    TYPE(Time)                                      :: t
+
+
+    ! Init
+    error = .FALSE.
+    errorCode = 0
+    mjdOut = -1.0_bp
+
+    ! Create a Time instance.
+    CALL NEW(t, mjdIn, TRIM(timescaleIn))
+    IF(error) THEN
+       ! Error in creating a Time object.
+       errorCode = 55
+       RETURN
+    END IF
+
+    ! Convert to the desired timescale.
+    mjdOut = getMjd(t, TRIM(timescaleOut))
+    IF(error) THEN
+       ! Error in converting to MJD.
+       errorCode = 56
+       RETURN
+    END IF
+
+    ! Cleanup.
+    CALL NULLIFY(t)
+
+  END SUBROUTINE mjdConvert
+
+END MODULE liboorb
Index: trunk/mops/oorb/python/pyoorb.f90
===================================================================
--- trunk/mops/oorb/python/pyoorb.f90	(revision 34646)
+++ trunk/mops/oorb/python/pyoorb.f90	(revision 34646)
@@ -0,0 +1,918 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! Module for which f2py builds Python wrappers.
+!!
+!! @author  MG, FP
+!! @version 2009-12-11
+!!
+MODULE pyoorb
+
+  USE planetary_data
+  USE Base_cl
+  USE Time_cl
+  USE SphericalCoordinates_cl
+  USE Observatories_cl
+  USE Orbit_cl
+  USE StochasticOrbit_cl
+  USE PhysicalParameters_cl
+  IMPLICIT NONE
+  TYPE (Observatories), SAVE, PRIVATE :: obsies
+  CHARACTER(len=11), DIMENSION(6), PUBLIC :: element_types = (/ &
+       "cartesian  ",&
+       "cometary   ",&
+       "keplerian  ",&
+       "delaunay   ",&
+       "poincare   ",&
+       "equinoctial" &
+       /)
+  CHARACTER(len=3), DIMENSION(4), PUBLIC :: timescales = (/     &
+       "UTC",&
+       "UT1",&
+       "TT ",&
+       "TAI" &
+       /)
+
+CONTAINS
+
+
+
+  SUBROUTINE oorb_init(ephemeris_fname, error_verbosity, &
+       info_verbosity, error_code)
+
+    IMPLICIT NONE
+    CHARACTER(len=*), INTENT(in), OPTIONAL :: ephemeris_fname
+    INTEGER, INTENT(in), OPTIONAL :: error_verbosity
+    INTEGER, INTENT(in), OPTIONAL :: info_verbosity
+    INTEGER, INTENT(out) :: error_code
+
+    TYPE (Time) :: t
+
+    ! Set path to data files by reading env parameter OORB_DATA_DIR:
+    CALL setAccessToDataFiles()
+
+    ! Read OBSCODE.dat
+    CALL NEW(obsies)
+    IF (error) THEN
+       error_code = 1
+       error = .FALSE.
+       RETURN       
+    END IF
+
+    ! Read TAI-UTC.dat and ET-UT.dat
+    CALL NEW(t)
+    IF (error) THEN
+       error_code = 2
+       error = .FALSE.
+       RETURN       
+    END IF
+
+    ! Read de405.dat
+    IF (PRESENT(ephemeris_fname)) THEN
+       CALL JPL_ephemeris_init(error, ephemeris_fname)
+       IF (error) THEN
+          error_code = 3
+          error = .FALSE.
+          RETURN
+       END IF
+    ELSE
+       CALL JPL_ephemeris_init(error, &
+            filename=TRIM(OORB_DATA_DIR) // "/" // TRIM(EPH_FNAME)) 
+       IF (error) THEN
+          error_code = 4
+          error = .FALSE.
+          RETURN
+       END IF
+    END IF
+
+    ! Set verbosity of error messages (0=nothing,5=everything,1=default)
+    IF (PRESENT(error_verbosity)) THEN
+       err_verb = error_verbosity
+    ELSE
+       err_verb = 1
+    END IF
+
+    ! Set verbosity of info messages (0=nothing,5=everything,1=default)
+    IF (PRESENT(info_verbosity)) THEN
+       info_verb = info_verbosity
+    ELSE
+       info_verb = 1
+    END IF
+
+  END SUBROUTINE oorb_init
+
+
+
+
+
+  SUBROUTINE oorb_memfree()
+
+    IMPLICIT NONE
+
+    CALL nullifyTime()
+    CALL NULLIFY(obsies)
+    CALL JPL_ephemeris_nullify()
+
+  END SUBROUTINE oorb_memfree
+
+
+
+
+
+  SUBROUTINE oorb_element_transformation(in_norb, &
+       in_orbits,       &
+       in_element_type, &
+       out_orbits,      &
+       error_code)
+
+    ! Input/Output variables.
+    INTEGER, INTENT(in)                                 :: in_norb
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(in)           :: in_orbits ! (1:norb,1:12)
+    ! Type of output elements
+    INTEGER, INTENT(in)                                 :: in_element_type
+    ! Output flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(out)          :: out_orbits ! (1:norb,1:12)
+    ! Output error code
+    INTEGER, INTENT(out)                                :: error_code
+
+    TYPE (Time) :: t
+    TYPE (Orbit) :: orb
+    INTEGER :: i
+
+    ! Loop over orbits:
+    DO i=1,SIZE(in_orbits,dim=1)
+
+       ! Get the element type from the input flattened orbit.
+       IF(NINT(in_orbits(i,8)) < 0 .OR.                                       &
+            NINT(in_orbits(i,8)) > SIZE(element_types)) THEN
+          ! Error: unsupported orbital elements.
+          error_code = 58
+          RETURN
+       END IF
+
+       ! Get each flattened orbit and create an Orbit instance. First
+       ! create a Time instance:
+       CALL NEW(t, in_orbits(i,9), timescales(NINT(in_orbits(i,10))))
+       IF (error) THEN
+          ! Error in creating a Time instance.
+          error_code = 57
+          RETURN
+       END IF
+
+       ! Now create an Orbit instance:
+       CALL NEW(orb, &
+            in_orbits(i,2:7), &
+            element_types(NINT(in_orbits(i,8))), &
+            "ecliptic", &
+            copy(t))
+       CALL NULLIFY(t)
+
+       out_orbits(i,1) = in_orbits(i,1)
+       out_orbits(i,2:7) = getElements(orb, element_types(in_element_type), &
+            "ecliptic")
+       IF (error) THEN
+          ! Error in transformation
+          error_code = 58
+          RETURN
+       END IF
+       out_orbits(i,8) = REAL(in_element_type,8)
+       out_orbits(i,9:) = in_orbits(i,9:)
+       CALL NULLIFY(orb)
+
+    END DO
+
+  END SUBROUTINE oorb_element_transformation
+
+
+
+
+
+  SUBROUTINE oorb_propagation_2b(in_norb, &
+       in_orbits,       &
+       in_epoch,        &
+       out_orbits,      &
+       error_code)
+
+    ! Input/Output variables.
+    INTEGER, INTENT(in)                                 :: in_norb
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(in)           :: in_orbits ! (1:norb,1:12)
+    ! Epoch and timescale of output orbits
+    REAL(8), DIMENSION(2), INTENT(in)                   :: in_epoch
+    ! Output flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(out)          :: out_orbits ! (1:norb,1:12)
+    ! Output error code
+    INTEGER, INTENT(out)                                :: error_code
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t0, t1
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator
+    CHARACTER(len=6) :: dyn_model
+    REAL(8) :: integration_step
+    INTEGER :: i
+    LOGICAL, DIMENSION(10) :: perturbers
+
+    ! Init
+    errstr = ""
+    error_code = 0
+    dyn_model = "2-body"
+    integrator = "bulirsch-stoer"
+    integration_step = 5.0_8
+    perturbers = .TRUE.
+
+    ! Loop over orbits:
+    DO i=1,SIZE(in_orbits,dim=1)
+
+       ! Get the element type from the input flattened orbit.
+       IF(NINT(in_orbits(i,8)) < 0 .OR. &
+            NINT(in_orbits(i,8)) > SIZE(element_types)) THEN
+          ! Error: unsupported orbital elements.
+          error_code = 58
+          RETURN
+       END IF
+
+       ! Get each flattened orbit and create an Orbit instance.
+       ! First create a Time instance corresponding to the orbit epoch.
+       CALL NEW(t0, in_orbits(i,9), timescales(NINT(in_orbits(i,10))))
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          error_code = 57
+          RETURN
+       END IF
+
+       ! Now create an Orbit instance.
+       CALL NEW(orb, &
+            in_orbits(i,2:7), &
+            element_types(NINT(in_orbits(i,8))), &
+            "ecliptic", &
+            copy(t0))
+       CALL NULLIFY(t0)
+       CALL setParameters(orb, &
+            dyn_model=dyn_model, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          error_code = 37
+          RETURN
+       END IF
+       ! Create a Time instance based on the requested output epoch
+       CALL NEW(t1, in_epoch(1), timescales(NINT(in_epoch(2))))
+       IF (error) THEN
+          ! Error in transformation
+          error_code = 58
+          RETURN
+       END IF
+       ! Compute topocentric ephemerides
+       CALL propagate(orb, &
+            t1)
+       IF (error) THEN
+          ! Error in getEphemerides()
+          error_code = 40
+          RETURN
+       END IF
+       out_orbits(i,1) = in_orbits(i,1)
+       out_orbits(i,2:7) = getElements(orb, element_types(NINT(in_orbits(i,8))), &
+            "ecliptic")
+       IF (error) THEN
+          ! Error in transformation
+          error_code = 58
+          RETURN
+       END IF
+       out_orbits(i,8:) = in_orbits(i,8:)
+       CALL NULLIFY(orb)
+    END DO
+
+  END SUBROUTINE oorb_propagation_2b
+
+
+
+
+
+  SUBROUTINE oorb_propagation_nb(in_norb, &
+       in_orbits,       &
+       in_epoch,        &
+       out_orbits,      &
+       error_code)
+
+    ! Input/Output variables.
+    INTEGER, INTENT(in)                                 :: in_norb
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(in)           :: in_orbits ! (1:norb,1:12)
+    ! Epoch and timescale of output orbits
+    REAL(8), DIMENSION(2), INTENT(in)                   :: in_epoch
+    ! Output flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(out)          :: out_orbits ! (1:norb,1:12)
+    ! Output error code
+    INTEGER, INTENT(out)                                :: error_code
+
+    TYPE (Orbit) :: orb
+    TYPE (Time) :: t0, t1
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator
+    CHARACTER(len=6) :: dyn_model
+    REAL(8) :: integration_step
+    INTEGER :: i
+    LOGICAL, DIMENSION(10) :: perturbers
+
+    ! Init
+    errstr = ""
+    error_code = 0
+    dyn_model = "n-body"
+    integrator = "bulirsch-stoer"
+    integration_step = 5.0_8
+    perturbers = .TRUE.
+
+    ! Loop over orbits:
+    DO i=1,SIZE(in_orbits,dim=1)
+
+       ! Get the element type from the input flattened orbit.
+       IF(NINT(in_orbits(i,8)) < 0 .OR. &
+            NINT(in_orbits(i,8)) > SIZE(element_types)) THEN
+          ! Error: unsupported orbital elements.
+          error_code = 58
+          RETURN
+       END IF
+
+       ! Get each flattened orbit and create an Orbit instance.
+       ! First create a Time instance corresponding to the orbit epoch.
+       CALL NEW(t0, in_orbits(i,9), timescales(NINT(in_orbits(i,10))))
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          error_code = 57
+          RETURN
+       END IF
+
+       ! Now create an Orbit instance.
+       CALL NEW(orb, &
+            in_orbits(i,2:7), &
+            element_types(NINT(in_orbits(i,8))), &
+            "ecliptic", &
+            copy(t0))
+       CALL NULLIFY(t0)
+       CALL setParameters(orb, &
+            dyn_model=dyn_model, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          error_code = 37
+          RETURN
+       END IF
+       ! Create a Time instance based on the requested output epoch
+       CALL NEW(t1, in_epoch(1), timescales(NINT(in_epoch(2))))
+       IF (error) THEN
+          ! Error in transformation
+          error_code = 58
+          RETURN
+       END IF
+       ! Compute topocentric ephemerides
+       CALL propagate(orb, &
+            t1)
+       IF (error) THEN
+          ! Error in getEphemerides()
+          error_code = 40
+          RETURN
+       END IF
+       out_orbits(i,1) = in_orbits(i,1)
+       out_orbits(i,2:7) = getElements(orb, element_types(NINT(in_orbits(i,8))), &
+            "ecliptic")
+       IF (error) THEN
+          ! Error in transformation
+          error_code = 58
+          RETURN
+       END IF
+       out_orbits(i,8:) = in_orbits(i,8:)
+       CALL NULLIFY(orb)
+    END DO
+
+  END SUBROUTINE oorb_propagation_nb
+
+
+
+
+
+  SUBROUTINE oorb_ephemeris(in_norb, &
+       in_orbits,                    &
+       in_obscode,                   &
+       in_ndate,                     &
+       in_date_ephems,               &
+       out_ephems,                   &
+       error_code)
+
+    ! Input/Output variables.
+    INTEGER, INTENT(in)                                 :: in_norb
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(in)           :: in_orbits ! (1:norb,1:12)
+    ! Observatory code as defined by the Minor Planet Center
+    CHARACTER(len=*), INTENT(in)                        :: in_obscode
+    INTEGER, INTENT(in)                                 :: in_ndate
+    ! Ephemeris dates.
+    ! (mjd, timescale)
+    REAL(8), DIMENSION(in_ndate,2), INTENT(in)          :: in_date_ephems ! (1:ndate,1:2)
+    ! Output ephemeris
+    ! out_ephems = ((dist, ra, dec, mag, mjd, timescale, dra/dt, ddec/dt), )
+    REAL(8), DIMENSION(in_norb,in_ndate,8), INTENT(out) :: out_ephems ! (1:norb,1:ndate,1:8)
+    ! Output error code
+    INTEGER, INTENT(out)                                :: error_code
+
+    ! Internal variables.  
+    TYPE (Orbit), DIMENSION(:,:), POINTER :: orb_lt_corr_arr
+    TYPE (Orbit), DIMENSION(1) :: orb_arr
+    TYPE (CartesianCoordinates), DIMENSION(:), ALLOCATABLE :: observers
+    TYPE (CartesianCoordinates) :: ccoord
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: ephemerides
+    TYPE (Time) :: t
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator
+    CHARACTER(len=6) :: dyn_model
+    REAL(8), DIMENSION(6) :: coordinates, &
+         elements
+    REAL(8), DIMENSION(3) :: obsy_obj, &
+         obsy_pos, &
+         pos
+    REAL(8) :: cos_phase, &
+         ephemeris_r2, &
+         heliocentric_r2, &
+         integration_step, &
+         mjd, &
+         observer_r2, &
+         phase, &
+         vmag
+    INTEGER :: i, &
+         j
+    LOGICAL, DIMENSION(10) :: perturbers
+
+    ! Init
+    errstr = ""
+    error_code = 0
+    dyn_model = "n-body"
+    integrator = "bulirsch-stoer"
+    integration_step = 5.0_8
+    perturbers = .TRUE.
+    ALLOCATE(observers(SIZE(in_date_ephems,dim=1)))
+    DO i=1,SIZE(in_date_ephems,dim=1)
+       CALL NEW(t, in_date_ephems(i,1), timescales(NINT(in_date_ephems(i,2))))
+       IF (error) THEN
+          ! Error in creating a new Time object.
+          error_code = 35
+          RETURN
+       END IF
+       ! Compute heliocentric observatory coordinates
+       observers(i) = getObservatoryCCoord(obsies, in_obscode, t)
+       IF (error) THEN
+          ! Error in getObservatoryCCoord()
+          error_code = 36
+          RETURN
+       END IF
+       CALL rotateToEquatorial(observers(i))
+       CALL NULLIFY(t)
+    END DO
+
+    ! Loop over orbits:
+    DO i=1,SIZE(in_orbits,dim=1)
+
+       ! Get the element type from the input flattened orbit.
+       IF(NINT(in_orbits(i,8)) < 0 .OR.                                       &
+            NINT(in_orbits(i,8)) > SIZE(element_types)) THEN
+          ! Error: unsupported orbital elements.
+          error_code = 58
+          RETURN
+       END IF
+
+       ! Get each flattened orbit and create an Orbit instance.
+       elements(1:6) = in_orbits(i,2:7)
+       ! Create a Time instance.
+       CALL NEW(t, in_orbits(i,9), timescales(NINT(in_orbits(i,10))))
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          error_code = 57
+          RETURN
+       END IF
+
+       ! Now create an instant of StochasticOrbit via an Orbit instance.
+       CALL NEW(orb_arr(1), &
+            elements(1:6), &
+            element_types(NINT(in_orbits(i,8))), &
+            "ecliptic", &
+            copy(t))
+       CALL NULLIFY(t)
+       CALL setParameters(orb_arr(1), &
+            dyn_model=dyn_model, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          error_code = 37
+          RETURN
+       END IF
+       ! Use cartesian equatorial coordinates:
+       CALL toCartesian(orb_arr(1), "equatorial")
+       !CALL toCometary(orb_arr(1))
+       IF (error) THEN
+          ! Error in setParameters()
+          error_code = 39
+          RETURN
+       END IF
+       ! Compute topocentric ephemerides
+       CALL getEphemerides(orb_arr, &
+            observers, &
+            ephemerides, &
+            this_lt_corr_arr=orb_lt_corr_arr)
+       IF (error) THEN
+          ! Error in getEphemerides()
+          error_code = 40
+          RETURN
+       END IF
+       CALL NULLIFY(orb_arr(1))
+
+       ! Now export the ephem_arr to a flat array.
+       DO j=1,SIZE(observers)
+
+          ! Make sure that the ephemeris is equatorial:
+          CALL rotateToEquatorial(ephemerides(1,j))
+          ! Extract RA & Dec
+          coordinates = getCoordinates(ephemerides(1,j))
+
+          ! Calculate apparent brightness
+          CALL NEW(ccoord, ephemerides(1,j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (50)',1)
+             STOP
+          END IF
+          CALL rotateToEquatorial(ccoord)
+          obsy_obj = getPosition(ccoord)
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (55)',1)
+             STOP
+          END IF
+          CALL NULLIFY(ccoord)
+          ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+          CALL toCartesian(orb_lt_corr_arr(1,j), frame='equatorial')
+          pos = getPosition(orb_lt_corr_arr(1,j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (60)',1)
+             STOP
+          END IF
+          heliocentric_r2 = DOT_PRODUCT(pos,pos)
+          obsy_pos = getPosition(observers(j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (65)',1)
+             STOP
+          END IF
+          observer_r2 = DOT_PRODUCT(obsy_pos,obsy_pos)
+          cos_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+               observer_r2) / (SQRT(heliocentric_r2) * &
+               SQRT(ephemeris_r2))
+          phase = ACOS(cos_phase)
+          vmag = getApparentMagnitude(H=in_orbits(i,11), &
+               G=in_orbits(i,12), r=SQRT(heliocentric_r2), &
+               Delta=coordinates(1), phase_angle=phase)
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (70)',1)
+             STOP
+          END IF
+
+          ! ephem date
+          t = getTime(observers(j))
+          mjd = getMJD(t, timescales(NINT(in_date_ephems(j,2))))
+          CALL NULLIFY(t)
+
+          ! Write the output ephem array.
+          out_ephems(i,j,1) = coordinates(1)                             ! distance
+          out_ephems(i,j,2) = coordinates(2)/rad_deg                     ! ra
+          out_ephems(i,j,3) = coordinates(3)/rad_deg                     ! dec
+          out_ephems(i,j,4) = vmag                                       ! mag
+          out_ephems(i,j,5) = mjd                                        ! ephem mjd
+          out_ephems(i,j,6) = NINT(in_date_ephems(j,2))                  ! ephem mjd timescale
+          out_ephems(i,j,7) = coordinates(5)*COS(coordinates(3))/rad_deg ! dra/dt  sky-motion
+          out_ephems(i,j,8) = coordinates(6)/rad_deg                     ! ddec/dt sky-motion
+
+          CALL NULLIFY(ephemerides(1,j))
+          CALL NULLIFY(orb_lt_corr_arr(1,j))
+
+       END DO
+
+       DEALLOCATE(ephemerides, orb_lt_corr_arr)
+
+    END DO
+    DO i=1,SIZE(observers)
+       CALL NULLIFY(observers(i))
+    END DO
+    DEALLOCATE(observers)
+
+  END SUBROUTINE oorb_ephemeris
+
+
+
+
+
+  SUBROUTINE oorb_ephemeris_covariance(in_norb, &
+       in_orbits,                    &
+       in_covariances,               &
+       in_obscode,                   &
+       in_ndate,                     &
+       in_date_ephems,               &
+       out_ephems,                   &
+       error_code)
+
+    ! Input/Output variables.
+    INTEGER, INTENT(in)                                   :: in_norb
+    ! Input flattened orbit:
+    !  (track_id, elements(1:6), element_type_index, epoch, timescale, H, G)
+    REAL(8),DIMENSION(in_norb,12), INTENT(in)             :: in_orbits ! (1:norb,1:12)
+    ! Covariance matrices:
+    REAL(8), DIMENSION(in_norb,6,6), INTENT(in)           :: in_covariances ! (1:norb,1:6,1:6)
+    ! Observatory code as defined by the Minor Planet Center
+    CHARACTER(len=*), INTENT(in)                          :: in_obscode
+    INTEGER, INTENT(in)                                   :: in_ndate
+    ! Ephemeris dates.
+    ! (mjd, timescale)
+    REAL(8), DIMENSION(in_ndate,2), INTENT(in)            :: in_date_ephems ! (1:ndate,1:2)
+    ! Output ephemeris
+    ! out_ephems = ((dist, ra, dec, mag, mjd, timescale, dra/dt, ddec/dt, raErr, decErr, smaa, smia, pa), )
+    REAL(8), DIMENSION(in_norb,in_ndate,13), INTENT(out)  :: out_ephems ! (1:norb,1:ndate,1:13)
+    ! Output error code
+    INTEGER, INTENT(out)                                  :: error_code
+
+    ! Internal variables.  
+    TYPE (StochasticOrbit) :: storb
+    TYPE (Orbit), DIMENSION(:,:), POINTER :: orb_lt_corr_arr
+    TYPE (Orbit), DIMENSION(1) :: orb_arr
+    TYPE (CartesianCoordinates), DIMENSION(:), ALLOCATABLE :: observers
+    TYPE (CartesianCoordinates) :: ccoord
+    TYPE (SphericalCoordinates), DIMENSION(:,:), POINTER :: ephemerides
+    TYPE (Time) :: t
+    CHARACTER(len=INTEGRATOR_LEN) :: integrator
+    CHARACTER(len=6) :: dyn_model
+    REAL(8), DIMENSION(:,:,:), POINTER :: cov_arr
+    REAL(8), DIMENSION(6,6) :: eigenvec
+    REAL(8), DIMENSION(6) :: coordinates, &
+         eigenval, &
+         elements
+    REAL(8), DIMENSION(3) :: obsy_obj, &
+         obsy_pos, &
+         pos
+    REAL(8) :: cos_phase, &
+         ephemeris_r2, &
+         heliocentric_r2, &
+         integration_step, &
+         mjd, &
+         observer_r2, &
+         pa, &
+         phase, &
+         sigma_dec, &
+         sigma_ra, &
+         smaa, &
+         smia, &
+         vmag
+    INTEGER :: ismaa, &
+         ismia, &
+         i, &
+         j, &
+         nrot
+    LOGICAL, DIMENSION(10) :: perturbers
+
+    ! Init
+    errstr = ""
+    error_code = 0
+    eigenval = 0.0_8
+    eigenvec = 0.0_8
+    dyn_model = "n-body"
+    integrator = "bulirsch-stoer"
+    integration_step = 5.0_8
+    perturbers = .TRUE.
+    ALLOCATE(observers(SIZE(in_date_ephems,dim=1)))
+    DO i=1,SIZE(in_date_ephems,dim=1)
+       CALL NEW(t, in_date_ephems(i,1), timescales(NINT(in_date_ephems(i,2))))
+       IF (error) THEN
+          ! Error in creating a new Time object.
+          error_code = 35
+          RETURN
+       END IF
+       ! Compute heliocentric observatory coordinates
+       observers(i) = getObservatoryCCoord(obsies, in_obscode, t)
+       IF (error) THEN
+          ! Error in getObservatoryCCoord()
+          error_code = 36
+          RETURN
+       END IF
+       CALL rotateToEquatorial(observers(i))
+       CALL NULLIFY(t)
+    END DO
+
+    ! Loop over orbits:
+    DO i=1,SIZE(in_orbits,dim=1)
+
+       ! Get the element type from the input flattened orbit.
+       IF(NINT(in_orbits(i,8)) < 0 .OR.                                       &
+            NINT(in_orbits(i,8)) > SIZE(element_types)) THEN
+          ! Error: unsupported orbital elements.
+          error_code = 58
+          RETURN
+       END IF
+
+       ! Get each flattened orbit and create an Orbit instance.
+       elements(1:6) = in_orbits(i,2:7)
+       ! Create a Time instance.
+       CALL NEW(t, in_orbits(i,9), timescales(NINT(in_orbits(i,10))))
+       IF(error) THEN
+          ! Error in creating a Time instance.
+          error_code = 57
+          RETURN
+       END IF
+
+       ! Now create an instant of StochasticOrbit via an Orbit instance.
+       CALL NEW(orb_arr(1), &
+            elements(1:6), &
+            element_types(NINT(in_orbits(i,8))), &
+            "ecliptic", &
+            copy(t))
+       CALL NULLIFY(t)
+       CALL setParameters(orb_arr(1), &
+            dyn_model=dyn_model, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          error_code = 37
+          RETURN
+       END IF
+       CALL NEW(storb, orb_arr(1), in_covariances(i,:,:), &
+            cov_type=element_types(NINT(in_orbits(i,8))), &
+            element_type=element_types(NINT(in_orbits(i,8))))
+       IF (error) THEN
+          error_code = 34
+          RETURN
+       END IF
+       ! Use cartesian equatorial coordinates:
+       CALL toCartesian(storb, "equatorial")
+       !CALL toCometary(storb)
+       IF (error) THEN
+          ! Error in setParameters()
+          error_code = 36
+          RETURN
+       END IF
+
+       ! Set integration parameters
+       CALL setParameters(storb, &
+            dyn_model=dyn_model, &
+            perturbers=perturbers, &
+            integrator=integrator, &
+            integration_step=integration_step)
+       IF (error) THEN
+          ! Error in setParameters()
+          error_code = 37
+          RETURN
+       END IF
+
+       ! Compute topocentric ephemerides
+       CALL getEphemerides(storb, &
+            observers, &
+            ephemerides, &
+            cov_arr=cov_arr, &
+            this_lt_corr_arr=orb_lt_corr_arr)
+       IF (error) THEN
+          ! Error in getEphemerides()
+          error_code = 38
+          RETURN
+       END IF
+       CALL NULLIFY(storb)
+       CALL NULLIFY(orb_arr(1))
+
+       ! Now export the ephem_arr to a flat array.
+       DO j=1,SIZE(observers)
+
+          ! Make sure that the ephemeris is equatorial:
+          CALL rotateToEquatorial(ephemerides(1,j))
+          ! Extract RA & Dec
+          coordinates = getCoordinates(ephemerides(1,j))
+
+          ! Calculate apparent brightness
+          CALL NEW(ccoord, ephemerides(1,j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (50)',1)
+             STOP
+          END IF
+          CALL rotateToEquatorial(ccoord)
+          obsy_obj = getPosition(ccoord)
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (55)',1)
+             STOP
+          END IF
+          CALL NULLIFY(ccoord)
+          ephemeris_r2 = DOT_PRODUCT(obsy_obj,obsy_obj)
+          CALL toCartesian(orb_lt_corr_arr(1,j), frame='equatorial')
+          pos = getPosition(orb_lt_corr_arr(1,j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (60)',1)
+             STOP
+          END IF
+          heliocentric_r2 = DOT_PRODUCT(pos,pos)
+          obsy_pos = getPosition(observers(j))
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (65)',1)
+             STOP
+          END IF
+          observer_r2 = DOT_PRODUCT(obsy_pos,obsy_pos)
+          cos_phase = 0.5_bp * (heliocentric_r2 + ephemeris_r2 - &
+               observer_r2) / (SQRT(heliocentric_r2) * &
+               SQRT(ephemeris_r2))
+          phase = ACOS(cos_phase)
+          vmag = getApparentMagnitude(H=in_orbits(i,11), &
+               G=in_orbits(i,12), r=SQRT(heliocentric_r2), &
+               Delta=coordinates(1), phase_angle=phase)
+          IF (error) THEN
+             CALL errorMessage('oorb / ephemeris', &
+                  'TRACE BACK (70)',1)
+             STOP
+          END IF
+
+          ! ephem date
+          t = getTime(observers(j))
+          mjd = getMJD(t, timescales(NINT(in_date_ephems(j,2))))
+          CALL NULLIFY(t)
+
+          cov_arr(:,:,j) = SIGN(SQRT(ABS(cov_arr(:,:,j))),cov_arr(:,:,j))
+          sigma_ra = cov_arr(2,2,j)/rad_asec
+          sigma_dec = cov_arr(3,3,j)/rad_asec
+          CALL eigen_decomposition_jacobi(cov_arr(2:3,2:3,j), &
+               eigenval(2:3), eigenvec(2:3,2:3), nrot, errstr)
+          IF (LEN_TRIM(errstr) /= 0) THEN
+             error_code = 7
+             WRITE(*,*) TRIM(errstr)
+             RETURN
+          END IF
+          ismaa = 1 + MAXLOC(ABS(eigenval(2:3)),dim=1)
+          ismia = 1 + MINLOC(ABS(eigenval(2:3)),dim=1)
+          smaa = ABS(eigenval(ismaa))/rad_amin
+          smia = ABS(eigenval(ismia))/rad_amin
+          pa = ATAN2(eigenvec(3,ismaa),eigenvec(2,ismaa))/rad_deg
+          ! Write the output ephem array.
+          out_ephems(i,j,1) = coordinates(1)                             ! distance
+          out_ephems(i,j,2) = coordinates(2)/rad_deg                     ! ra
+          out_ephems(i,j,3) = coordinates(3)/rad_deg                     ! dec
+          out_ephems(i,j,4) = vmag                                       ! mag
+          out_ephems(i,j,5) = mjd                                        ! ephem mjd
+          out_ephems(i,j,6) = NINT(in_date_ephems(j,2))                  ! ephem mjd timescale
+          out_ephems(i,j,7) = coordinates(5)*COS(coordinates(3))/rad_deg ! dra/dt  sky-motion
+          out_ephems(i,j,8) = coordinates(6)/rad_deg                     ! ddec/dt sky-motion
+          out_ephems(i,j,9) = sigma_ra                                   ! raErr
+          out_ephems(i,j,10) = sigma_dec                                 ! decErr
+          out_ephems(i,j,11) = smaa                                      ! semi-major axis
+          out_ephems(i,j,12) = smia                                      ! semi-minor axis
+          out_ephems(i,j,13) = pa                                        ! position angle
+
+          CALL NULLIFY(ephemerides(1,j))
+          CALL NULLIFY(orb_lt_corr_arr(1,j))
+
+       END DO
+
+       DEALLOCATE(ephemerides, orb_lt_corr_arr, cov_arr)
+
+    END DO
+    DO i=1,SIZE(observers)
+       CALL NULLIFY(observers(i))
+    END DO
+    DEALLOCATE(observers)
+
+  END SUBROUTINE oorb_ephemeris_covariance
+
+
+
+END MODULE pyoorb
Index: trunk/mops/oorb/python/setup.py
===================================================================
--- trunk/mops/oorb/python/setup.py	(revision 34646)
+++ trunk/mops/oorb/python/setup.py	(revision 34646)
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+from distutils.core import setup
+
+
+
+if __name__ == "__main__": 
+    setup(name = 'oorb', 
+          description = "OpenOrb module", 
+          author = "Francesco Pierfederici", 
+          author_email = "fpierfed@lsst.org",
+          version='1.0a1',
+          package_dir={'oorb': '.'},
+          packages=['oorb', ],
+) 
Index: trunk/mops/oorb/python/test.f90
===================================================================
--- trunk/mops/oorb/python/test.f90	(revision 34646)
+++ trunk/mops/oorb/python/test.f90	(revision 34646)
@@ -0,0 +1,167 @@
+!====================================================================!
+!                                                                    !
+! Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  !
+! Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      !
+! Dagmara Oszkiewicz                                                 !
+!                                                                    !
+! This file is part of OpenOrb.                                      !
+!                                                                    !
+! OpenOrb 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.                                !
+!                                                                    !
+! OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    !
+!                                                                    !
+!====================================================================!
+!
+!! Test program for pyoorb module.
+!!
+!! @author  MG, JM
+!! @version 2009-12-08
+!!
+PROGRAM test
+
+  USE pyoorb
+  IMPLICIT NONE
+  CHARACTER(len=4) :: in_obscode
+  INTEGER, PARAMETER :: in_norb = 3
+  INTEGER, PARAMETER :: in_ndate = 2
+  REAL(8), DIMENSION(in_norb,6,6) :: in_covariances
+  REAL(8), DIMENSION(in_norb,12) :: in_orbits
+  REAL(8), DIMENSION(in_norb,in_ndate,13) :: out_ephems
+  REAL(8), DIMENSION(in_ndate,2) :: in_date_ephems
+  INTEGER :: error_code, i, j
+
+  ! Initialize 
+  error_code = 0
+  CALL oorb_init(error_code=error_code, info_verbosity=1)
+  IF (error_code /= 0) THEN
+     WRITE(stderr,*) "Error in oorb_init. Code: ", error_code
+     STOP
+  END IF
+
+  ! 2009 TL4 on 2009-11-12 (74 obs in 2009) from (Horizons & AstDyS)
+  in_orbits(1,1) = 1.0_8
+  in_orbits(1,2:7) = (/ &
+       1.853233422926951E+00_8, &
+       3.871022198610788E-01_8, &
+       6.474397461946572E+00_8, &
+       2.122138159851688E+02_8, &
+       1.602711715213041E+02_8, &
+       3.372535412461616E+01_8 /)
+  in_orbits(1,4:7) = in_orbits(1,4:7)*rad_deg
+  in_orbits(1,8) = 3.0_8
+  in_orbits(1,9) = 55200.0_8
+  in_orbits(1,10) = 3.0_8
+  in_orbits(1,11:12) = (/ 21.541_8, 0.15_8 /)
+  ! Copy the same orbit for testing purposes
+  in_orbits(2,:) = in_orbits(1,:)
+  in_orbits(2,1) = 2.0_8
+  in_orbits(3,:) = in_orbits(1,:)
+  in_orbits(3,1) = 3.0_8
+
+  ! From AstDyS
+  in_covariances(1,1,1:6) = (/ 1.59357530E-06_8, 4.54646999E-07_8, 5.59222797E-06_8, &
+       -3.87304158E-06_8, -3.54135866E-07_8, -4.31574921E-05_8 /)
+  in_covariances(1,2,1:6) = (/ 4.54646999E-07_8, 1.29710940E-07_8, 1.59544037E-06_8, &
+       -1.10495903E-06_8, -1.00707885E-07_8, -1.23129696E-05_8 /)
+  in_covariances(1,3,1:6) = (/ 5.59222797E-06_8, 1.59544037E-06_8, 1.96320645E-05_8, &
+       -1.36008250E-05_8, -1.34577989E-06_8, -1.51404682E-04_8 /)
+  in_covariances(1,4,1:6) = (/ -3.87304158E-06_8, -1.10495903E-06_8, -1.36008250E-05_8, &
+       9.42766927E-06_8, 9.60529697E-07_8, 1.04844563E-04_8 /)
+  in_covariances(1,5,1:6) = (/ -3.54135866E-07_8, -1.00707885E-07_8, -1.34577989E-06_8, &
+       9.60529697E-07_8, 2.72099434E-06_8, 8.49016456E-06_8 /)
+  in_covariances(1,6,1:6) = (/ -4.31574921E-05_8, -1.23129696E-05_8, -1.51404682E-04_8, &
+       1.04844563E-04_8, 8.49016456E-06_8, 1.16925907E-03_8 /)
+  DO i=1,6
+     IF (i >= 3) THEN
+        in_covariances(1,i,:) = in_covariances(1,i,:)*rad_deg
+        in_covariances(1,:,i) = in_covariances(1,:,i)*rad_deg
+     END IF
+  END DO
+  ! Copy the covariance matrix for testing purposes
+  DO i=2,3
+     in_covariances(i,:,:) = in_covariances(1,:,:)
+  END DO
+
+  ! Observatory code
+  in_obscode = "500"
+
+  ! Dates for output ephemerides
+  in_date_ephems(1,1:2) = (/ 55148.0_8, 1.0_8 /)
+  in_date_ephems(2,1:2) = (/ 55150.0_8, 1.0_8 /)
+
+  ! Compute ephemerides with covariance
+  CALL oorb_ephemeris_covariance(in_norb, &
+       in_orbits,                         &
+       in_covariances,                    &
+       in_obscode,                        &
+       in_ndate,                          & 
+       in_date_ephems,                    &
+       out_ephems,                        &
+       error_code)
+  IF (error_code /= 0) THEN
+     WRITE(stderr,*) "Error in oorb_ephemeris. Code: ", error_code
+     STOP
+  END IF
+  WRITE(stdout,"(14(2X,A12))") "ID", "Delta", "RA", "Dec", &
+       "Mag", "MJD", "Timescale", "dRA/dt", "dDec/dt", &
+       "sigma_RA", "sigma_Dec", "Uncert smaa", "Uncert smia", &
+       "Uncert PA"
+  DO i=1,SIZE(out_ephems,dim=1)
+     DO j=1,SIZE(out_ephems,dim=2)
+        WRITE(stdout,"(14(2X,E12.5))") in_orbits(i,1), out_ephems(i,j,:)
+     END DO
+  END DO
+
+  ! Compute ephemerides without covariance
+  out_ephems = -1.0_8
+  CALL oorb_ephemeris(in_norb, &
+       in_orbits,              &
+       in_obscode,             &
+       in_ndate,               & 
+       in_date_ephems,         &
+       out_ephems(:,:,1:8),    &
+       error_code)
+  IF (error_code /= 0) THEN
+     WRITE(stderr,*) "Error in oorb_ephemeris. Code: ", error_code
+     STOP
+  END IF
+  WRITE(stdout,"(9(2X,A12))") "ID", "Delta", "RA", "Dec", &
+       "Mag", "MJD", "Timescale", "dRA/dt", "dDec/dt"
+  DO i=1,SIZE(out_ephems,dim=1)
+     DO j=1,SIZE(out_ephems,dim=2)
+        WRITE(stdout,"(9(2X,E12.5))") in_orbits(i,1), out_ephems(i,j,1:8)
+     END DO
+  END DO
+
+!!$ Ephemeris for 2009 TL4 at epoch 55148 MJD (from AstDyS)
+!!$ Right Ascension:      17.801   deg
+!!$ Declination:          -0.08723 deg
+!!$ V Magnitude:          19.98    mag
+!!$ Solar Elongation:   -145.14    deg
+!!$ Phase:                28.48    deg
+!!$ Galactic Latitude:   -62.54    deg
+!!$ Distance from Earth:   0.23    AU
+!!$ Distance from Sun:     1.186   AU
+!!$ Apparent motion 
+!!$ Rate:                  0.848   deg/day
+!!$ Direction:            95.121   deg
+!!$ Uncertainty Ellipse 
+!!$ Semimajor axis:        0.021   arcmin
+!!$ Semiminor axis:        0.017   arcmin
+!!$ Orientation:        -161.75    deg
+!!$ From JPL:
+!!$ RA  3sigma unc:        3.097   arcsec
+!!$ Dec 3sigma unc:        3.672   arcsec 
+
+  CALL oorb_memfree()
+
+END PROGRAM test
Index: trunk/mops/oorb/python/test.py
===================================================================
--- trunk/mops/oorb/python/test.py	(revision 34646)
+++ trunk/mops/oorb/python/test.py	(revision 34646)
@@ -0,0 +1,117 @@
+#====================================================================#
+#                                                                    #
+# Copyright 2002,2003,2004,2005,2006,2007,2008,2009                  #
+# Mikael Granvik, Jenni Virtanen, Karri Muinonen, Teemu Laakso,      #
+# Dagmara Oszkiewicz                                                 #
+#                                                                    #
+# This file is part of OpenOrb.                                      #
+#                                                                    #
+# OpenOrb 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.                                #
+#                                                                    #
+# OpenOrb 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 OpenOrb. If not, see <http://www.gnu.org/licenses/>.    #
+#                                                                    #
+#====================================================================#
+#
+# Script for testing pyoorb library using Python. The results should
+# be identical to the results by test.f90 if everything is okay.
+#
+# @author  MG, JM
+# @version 2009-12-01
+#
+
+#!/usr/bin/env python
+
+import pyoorb
+import numpy
+
+if __name__ == "__main__":
+    print "starting..."
+    print "calling oorb_init():"
+    pyoorb.pyoorb.oorb_init(error_verbosity=5, info_verbosity=5)
+    #orb is id, 6 elements, epoch_mjd, H, G, element type index
+    #keplerian appears to be element type index 3
+    #orbits = numpy.array([0.,1.,2.,3.,4.,5.,6.,5373.,1.,1.,3.])
+    #using the first item in PS-SSM, 1/100th density, s1.01 file.
+    orbits = numpy.zeros([3,12], dtype=numpy.double, order='F')
+    orbits[0][0] = 1.0
+    orbits[0][1] = 1.853233422926951E+00
+    orbits[0][2] = 3.871022198610788E-01
+    orbits[0][3] = 6.474397461946572E+00
+    orbits[0][4] = 2.122138159851688E+02
+    orbits[0][5] = 1.602711715213041E+02
+    orbits[0][6] = 3.372535412461616E+01
+    for i in range(3,7):
+        orbits[0][i] = numpy.radians(orbits[0][i])
+    orbits[0][7] = 3.0
+    orbits[0][8] = 55200.0
+    orbits[0][9] = 3.0
+    orbits[0][10]= 21.541
+    orbits[0][11]= .15
+
+    orbits[1][0] = 2.0
+    orbits[2][0] = 3.0
+    for i in range(1,12):
+        orbits[1][i] = orbits[0][i]
+        orbits[2][i] = orbits[0][i]
+    print orbits[0]
+    print orbits[1]
+    print orbits[2]
+
+    covariances = numpy.zeros([3,6,6], order='F') #zero covariance is okay for now...
+
+    covariances[0][0][:] = [ 1.59357530E-06, 4.54646999E-07, 5.59222797E-06, \
+                              -3.87304158E-06, -3.54135866E-07, -4.31574921E-05 ]
+
+    covariances[0][1][:] = [ 4.54646999E-07, 1.29710940E-07, 1.59544037E-06, \
+                              -1.10495903E-06, -1.00707885E-07, -1.23129696E-05 ]
+
+    covariances[0][2][:] = [ 5.59222797E-06, 1.59544037E-06, 1.96320645E-05, \
+                                 -1.36008250E-05, -1.34577989E-06, -1.51404682E-04 ]
+
+    covariances[0][3][:] = [ -3.87304158E-06, -1.10495903E-06, -1.36008250E-05, \
+                                9.42766927E-06, 9.60529697E-07, 1.04844563E-04 ]
+
+    covariances[0][4][:] = [ -3.54135866E-07, -1.00707885E-07, -1.34577989E-06, \
+                                9.60529697E-07, 2.72099434E-06, 8.49016456E-06 ]
+
+    covariances[0][5][:] = [ -4.31574921E-05, -1.23129696E-05, -1.51404682E-04, \
+                                1.04844563E-04, 8.49016456E-06, 1.16925907E-03 ]
+
+    for i in range(0,6):
+        for j in range(0,6):
+            covariances[1][i][j] = covariances[0][i][j]
+            covariances[2][i][j] = covariances[0][i][j]
+    
+    
+    obscode = "500"
+    ephem_dates=numpy.zeros([2,2], dtype=numpy.double, order='F')
+    ephem_dates[0][:] = [ 55148.0, 1.0 ]
+    ephem_dates[1][:] = [ 55150.0, 1.0 ]
+
+    print "calling oorb_ephemeris_covariance"
+    eph, err = pyoorb.pyoorb.oorb_ephemeris_covariance(orbits, \
+                                                covariances, \
+                                                obscode, \
+                                                ephem_dates)
+    print "error code:", err
+    for i in range(0,3):
+        for j in range(0,2):
+            print eph[i][j]
+
+    print "calling oorb_ephemeris"
+    eph, err = pyoorb.pyoorb.oorb_ephemeris(in_orbits=orbits, \
+                                                in_obscode=obscode, \
+                                                in_date_ephems=ephem_dates)
+    print "error code:", err
+    for i in range(0,3):
+        for j in range(0,2):
+            print eph[i][j]
Index: trunk/mops/oorb/python/utils.py
===================================================================
--- trunk/mops/oorb/python/utils.py	(revision 34646)
+++ trunk/mops/oorb/python/utils.py	(revision 34646)
@@ -0,0 +1,274 @@
+#
+# LSST Data Management System
+# Copyright 2008, 2009 LSST Corporation.
+#
+# This product includes software developed by the
+# LSST Project (http://www.lsst.org/).
+#
+# 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 LSST License Statement and
+# the GNU General Public License along with this program.  If not,
+# see <http://www.lsstcorp.org/LegalNotices/>.
+#
+# F. Pierfederici <fpierfed@gmail.com>
+from constants import *
+# from api import *
+
+
+
+
+def findLibrary(root):
+    import ctypes
+    import os
+    import sys
+    
+    
+    # ctypes.util.find_library works just fine on OSX.
+    if(sys.platform.startswith('darwin')):
+        return(ctypes.util.find_library(root))
+    
+    # It does not on Linux/Solaris etc. (IMHO).
+    libPath = ctypes.util.find_library(root)
+    if(libPath):
+        return(libPath)
+    
+    # Now we are in trouble. Try and see if we find it somewhere in the user
+    # LD_LIBRARY_PATH.
+    if(sys.platform.startswith('linux')):
+        dirPaths = os.environ.get('LD_LIBRARY_PATH', '').split(':')
+        for dirPath in dirPaths:
+            path = os.path.join(dirPath, 'lib%s.so' %(root))
+            if(os.path.exists(path)):
+                return(path)
+    return(None)
+
+
+def sexagesimalHoursToDecimalDegrees(h, m, s):
+    """
+    Convert an angle given in sexagesimal hour form to decimal degrees.
+    """
+    return(15. * sexagesimalDegreesToDecimalDegrees(h, m, s))
+
+
+def sexagesimalDegreesToDecimalDegrees(d, m, s):
+    """
+    Convert an angle given in sexagesimal degree form to decimal degrees.
+    """
+    if(d >= 0.):
+        return(float(d) + float(m) / 60. + float(s) / 3600.)
+    return(float(d) - float(m) / 60. - float(s) / 3600.)
+
+
+def _updateConfig(config, var, val):
+    if(config.has_key(var) and not isinstance(config[var], list)):
+        config[var] = [config[var], val]
+    elif(config.has_key(var)):
+        config[var].append(val)
+    else:
+        config[var] = val
+    return(config)
+
+
+def _guessType(val):
+    # remove any comments.
+    val = val.split('#', 1)[0]
+    val = val.strip()
+    if(not val):
+        return(None)
+    
+    # Is it an array or a simple type (including strings)? Arrays are space 
+    # separated and are homogeneus collections.
+    tokens = val.split()
+    if(len(tokens) == 1):
+        # Nope: single value.
+        return(_guessSingleType(val))
+    # Either a string with spaces of an array of int/float/Bool.
+    # Guess the type of the first token and assume that if it is not a string, 
+    # we have an array (not that safe, actually).
+    # TODO: Improve array parsing.
+    typedToken = _guessSingleType(tokens[0])
+    if(isinstance(typedToken, str)):
+        return(val)
+    # We have an array!
+    typedVal = [_guessSingleType(t) for t in tokens]
+    # Simple sanity check.
+    for v in typedVal:
+        if(not isinstance(v, typedToken.__class__)):
+            # Ops! We made a mistake in assuming that val was an array.
+            return(val)
+    return(typedVal)
+
+
+def _guessSingleType(val):
+    if(not val):
+        return(None)
+    if(val.upper() == 'T'):
+        return(True)
+    elif(val.upper() == 'F'):
+        return(False)
+    
+    try:
+        return(float(val))
+    except:
+        pass
+    try:
+        return(int(val))
+    except:
+        pass
+    return(val)
+
+
+def readConfigurationFile(fileName):
+    config = {}
+    
+    f = open(fileName)
+    for line in f:
+        line = line.split('#', 1)[0]
+        line = line.strip()
+        if(not line):
+            continue
+        
+        try:
+            (var, val) = line.split(':', 1)
+        except:
+            raise(SyntaxError('Unable to parse line "%s"' %(line)))
+        val = _guessType(val)
+        config = _updateConfig(config, var, val)
+    f.close()
+    return(config)
+
+
+def _parseMPCLine(line, defaultStdDev):
+    # Remove comments and leading/trailing blank spaces.
+    line = line.split('#', 1)[0]
+    line = line.strip()
+    if(not line or line.startswith("#")):
+        return
+    
+    tokens = line.split()
+    # FIXME: Improve MPC format parsing.
+    if(len(tokens) not in (13, 11)):
+        raise(NotImplementedError("FIXME: Improve MPC format parsing."))
+    
+    objName = tokens[0]
+    if(objName.endswith('*')):
+        objName = objName[:-1]
+    
+    obsTypeYear = tokens[1]
+    if(len(obsTypeYear) >= 5):
+        obsType = obsTypeYear[0]
+        year = obsTypeYear[1:]
+    else:
+        year = obsTypeYear
+    year = int(year)
+    
+    month = int(tokens[2])
+    day = float(tokens[3])
+    
+    # The timescale used by MPC prior to year 1972 is UT1 and since then UTC has
+    # been used.
+    if(year < 1972):
+        timescale = "UT1"
+    else:
+        timescale = "UTC"
+    mjd = calendardate_to_mjd(year, month, day, timescale)
+    
+    h = int(tokens[4])
+    m = int(tokens[5])
+    s = float(tokens[6])
+    ra = sexagesimalHoursToDecimalDegrees(h, m, s)
+    raErr = defaultStdDev[1]
+    
+    d = int(tokens[7])
+    m = int(tokens[8])
+    s = float(tokens[9])
+    dec = sexagesimalDegreesToDecimalDegrees(d, m, s)
+    decErr = defaultStdDev[2]
+    
+    # Filters need to be 1-character long.
+    if(len(tokens) == 13):
+        # We have mag and filter info.
+        mag = float(tokens[10])
+        filter = tokens[11]
+    else:
+        # No mag/filter info.
+        mag = 99.9
+        filter = ' '
+
+    # The obscode are the last 3 characters from the last token. We need to pad
+    # them to 4 character lomg.
+    obscode = tokens[-1][-3:] + ' '
+    return((objName, mjd, ra, raErr, dec, decErr, mag, filter, obscode))
+    
+    
+
+def readObsFile(fileName, defaultStdDev):
+    """
+    Parse a detection file in the (old) MPC format. If no coordinate uncertainty
+    is profided use the input defaultStdDev values.
+    
+    @param fileName: full path of the file to parse.
+    @param defaultStdDev: 6 element array with uncertainties on distance, ra, 
+           dec and their time derivatives. Since we typically only measure ra 
+           and dec, defaultStdDev has the form:
+                [None, raErr, decErr, None, None, None]
+    Return
+        [(objectName, MJD, RA, RAErr, Dec, DecErr, mag, filterName, obscode), ]
+    
+    Angles in decimal degrees. Times in TT.
+    """
+    data = []
+    
+    f = open(fileName)
+    for line in f:
+        values = _parseMPCLine(line, defaultStdDev)
+        if(not values):
+            continue
+        data.append(values)
+    f.close()
+    return(data)
+
+
+def splitObservations(obs):
+    """
+    Group observations per object name.
+    
+    @param obs: list of the form [(objectName, MJD, RA, Dec, mag, filterName), ]
+    
+    Return
+        [obs1, obs2, ...]
+    Where
+        obsi = [(objectNamei, MJD, RA, Dec, mag, filterName), ]
+    """
+    if(not obs):
+        return(obs)
+    
+    refName = obs[0][0]
+    currentObs = []
+    separatedObs = []
+    for o in obs:
+        name = o[0]
+        if(name == refName):
+            # Another observation from the current group.
+            currentObs.append(o)
+            continue
+        else:
+            # Another group.
+            separatedObs.append(currentObs)
+            refName = name
+            currentObs = [o, ]
+    # Make sure that we got all groups.
+    if(currentObs not in separatedObs):
+        separatedObs.append(currentObs)
+    return(separatedObs)
+
+
Index: trunk/mops/oorb/python/wrapper.f90
===================================================================
--- trunk/mops/oorb/python/wrapper.f90	(revision 34646)
+++ trunk/mops/oorb/python/wrapper.f90	(revision 34646)
@@ -0,0 +1,1598 @@
+!
+! LSST Data Management System
+! Copyright 2008, 2009 LSST Corporation.
+!
+! This product includes software developed by the
+! LSST Project (http://www.lsst.org/).
+!
+! 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 LSST License Statement and
+! the GNU General Public License along with this program.  If not,
+! see <http://www.lsstcorp.org/LegalNotices/>.
+!
+! 
+! OpenOrb library
+! F. Pierfederici <fpierfed@gmail.com>
+! 
+! Description
+! 
+! Notes
+! error is a boolean global and is defined somewhere in liboorb.so!
+! 
+! 
+! Implementation notes:
+!   1. both oorb_ranging_fast and oorb_lsl_fast have a useless loop in them:
+!      either clean them up or make them useful!
+! 
+! 
+
+! Orbital elements that we support.
+! ORBITAL_ELEMENTS = (/ "keplerian",  "delaunay", "poincare", "equinoctial" /)
+
+
+
+
+
+subroutine oorb_init(ephemFileName, verbosity, error_code)
+  ! Initialize the OpenOrb module.
+  !
+  ! @param ephemFileName: full path of the JPL ephem file (usually 
+  !        $OORB_DATA/JPL_ephemeris/de405.dat).
+  ! @param verbosity: verbosity level for OpenOrb calls [0, 5] (default 0)
+  ! @return error_code: int error code. 0 = success, otherwise, failure.
+  use liboorb, only: init
+  ! Input/Output variables.
+  character(len=*), intent(IN)    :: ephemFileName
+  integer, intent(in)             :: verbosity
+  integer, intent(OUT)            :: error_code
+
+
+  call init(trim(ephemFileName), verbosity, error_code)
+  return
+end subroutine oorb_init
+
+
+
+subroutine oorb_ranging_fast(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     element_type,                              &
+     num_orbits,                                &
+     out_orbits,                                &
+     error_code)
+  use liboorb
+  use Observations_cl
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  ! Element type used in the orbit computation (default keplerian)
+  CHARACTER(len=11), intent(in)                       :: element_type
+  ! How may orbits do we want out?
+  integer, intent(in)                                 :: num_orbits
+  ! Output flattened orbits.
+  ! out_orbits has the form (id, (elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), element_type_index), )
+  real(8),dimension(num_orbits,15),intent(out)        :: out_orbits
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  real(8)                                             :: apriori_a_max
+  real(8)                                             :: apriori_a_min
+  real(8)                                             :: apriori_rho_max
+  real(8)                                             :: apriori_rho_min
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  integer                                             :: sor_type_prm
+  character(len=80)                                   :: sor_2point_method
+  character(len=80)                                   :: sor_2point_method_sw
+  integer                                             :: sor_norb
+  integer                                             :: sor_norb_sw
+  integer                                             :: sor_ntrial
+  integer                                             :: sor_ntrial_sw
+  integer                                             :: sor_niter
+  REAL(8), DIMENSION(4)                               :: sor_rho_init
+  real(8)                                             :: sor_genwin_multiplier
+  REAL(8), DIMENSION(4)                               :: sor_genwin_offset
+  real(8)                                             :: accwin_multiplier
+  logical                                             :: gaussian_rho
+  real(8)                                             :: pdf_ml_init
+  logical                                             :: uniform
+  logical                                             :: regularized
+  logical                                             :: random_obs
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j
+  integer                                             :: element_type_index
+
+  !    REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_matrices
+  !    integer                                             :: nobs = 0
+  !    integer                                             :: i = 0
+  !    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: scoords
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes: ", obscodes(j)
+  !    end do
+
+
+
+  !    write(*, *) "obscodes(1) ", obscodes(1)
+  !    write(*, *) "obscodes(2) ", obscodes(2)
+  !    write(*, *) "obscodes(3) ", obscodes(3)
+  !    write(*, *) "filters(1) ", filters(1)
+  !    write(*, *) "filters(2) ", filters(2)
+  !    write(*, *) "filters(3) ", filters(3)
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    write(*, *) "coords(1) ", coords(1, :)
+  !    write(*, *) "coords(2) ", coords(2, :)
+  !    write(*, *) "coords(3) ", coords(3, :)
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "element_type '", element_type, "'"
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init (these values come from best practices and default OpenOrb values).
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  apriori_a_max = 1000.0_8
+  apriori_a_min = 4.65423999999999959E-003_8
+  apriori_rho_max = -1.0_8
+  apriori_rho_min = -1.0_8
+  outlier_rejection = .false.
+  outlier_multiplier = 4.0_8
+  sor_type_prm = 2
+  sor_2point_method = "continued fraction"
+  sor_2point_method_sw = "continued fraction"
+  sor_norb = num_orbits
+  sor_norb_sw = sor_norb / 10
+  sor_ntrial = sor_norb * 2000
+  sor_ntrial_sw = sor_norb_sw * 400
+  sor_niter = 3
+  sor_rho_init = huge(sor_rho_init)
+  sor_rho_init(1) = 0.0_8
+  sor_rho_init(2) = 100.0_8
+  sor_genwin_multiplier = 3.0_8
+  sor_genwin_offset = 0.0_8
+  accwin_multiplier = 3.0_8
+  gaussian_rho = .false.
+  pdf_ml_init = -1.0_8
+  uniform = .false.
+  regularized = .true.
+  random_obs = .false.
+  obss => null()
+  call nullify(storb)
+  j = 0
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Figure out the element_type_index
+  element_type_index = -1
+  do j=1,size(ORBITAL_ELEMENTS)
+     if(trim(element_type) == trim(ORBITAL_ELEMENTS(j))) then
+        element_type_index = j
+        exit
+        !        else
+        !            write(*, *) "'" // trim(element_type) // "' =/ '" // trim(ORBITAL_ELEMENTS(j)) // "'"
+        !            write(*, *) " ", len(trim(element_type)), " =/ ", len(trim(ORBITAL_ELEMENTS(j)))
+     end if
+  end do
+  if(element_type_index .le. 0) then
+     ! Error: unsupported element type!
+     error_code = 58
+     return
+  end if
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Now that we have a set of Observations, pass them to the ranging routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  ! We clearly expect one track only, so this loop is here only so that we can
+  ! support multiple track processing later on. But it could just as well be
+  ! eliminated...
+  do j=1,size(obss)
+     call nullify(storb)
+
+     !        scoords => getObservationSCoords(obss(j))
+     !        do i=1,size(scoords)
+     !            write(*, *) "RA:  ", getLongitude(scoords(i))
+     !            write(*, *) "Dec: ", getLatitude(scoords(i))
+     !        end do
+
+
+     call ranging(obs_in=obss(j), element_type=trim(element_type), &
+          dyn_model=trim(dyn_model), &
+          integration_step=integration_step, &
+          perturbers=perturbers, apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_rho_max=apriori_rho_max, &
+          apriori_rho_min=apriori_rho_min, &
+          outlier_rejection=outlier_rejection, &
+          outlier_multiplier=outlier_multiplier, &
+          sor_type_prm=sor_type_prm, &
+          sor_2point_method=trim(sor_2point_method), &
+          sor_2point_method_sw=trim(sor_2point_method_sw), &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          sor_genwin_multiplier=sor_genwin_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          accwin_multiplier=accwin_multiplier, &
+          gaussian_rho=gaussian_rho, &
+          pdf_ml_init=pdf_ml_init, uniform=uniform, &
+          regularized=regularized, random_obs=random_obs, &
+          outOrbit=storb, errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Dump the storb orbit.
+     ! call dumpRangingOrbits(storb, errorCode=error_code)
+
+     ! Now flatten the ranging orbits.
+     call exportRangingOrbits(storb, element_type, track_id, out_orbits, &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+
+  deallocate(perturbers)
+  return
+end subroutine oorb_ranging_fast
+
+
+
+subroutine oorb_ranging(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     element_type,                              &
+     num_orbits,                                &
+     out_orbits,                                &
+     error_code)
+  use liboorb
+  use Observations_cl
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  ! Element type used in the orbit computation (default keplerian)
+  CHARACTER(len=11), intent(in)                       :: element_type
+  ! How may orbits do we want out?
+  integer, intent(in)                                 :: num_orbits
+  ! Output flattened orbits.
+  ! out_orbits has the form (id, (elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), element_type_index), )
+  real(8),dimension(num_orbits,15),intent(out)        :: out_orbits
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  real(8)                                             :: apriori_a_max
+  real(8)                                             :: apriori_a_min
+  real(8)                                             :: apriori_rho_max
+  real(8)                                             :: apriori_rho_min
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  integer                                             :: sor_type_prm
+  character(len=80)                                   :: sor_2point_method
+  character(len=80)                                   :: sor_2point_method_sw
+  integer                                             :: sor_norb
+  integer                                             :: sor_norb_sw
+  integer                                             :: sor_ntrial
+  integer                                             :: sor_ntrial_sw
+  integer                                             :: sor_niter
+  REAL(8), DIMENSION(4)                               :: sor_rho_init
+  real(8)                                             :: sor_genwin_multiplier
+  REAL(8), DIMENSION(4)                               :: sor_genwin_offset
+  real(8)                                             :: accwin_multiplier
+  logical                                             :: gaussian_rho
+  real(8)                                             :: pdf_ml_init
+  logical                                             :: uniform
+  logical                                             :: regularized
+  logical                                             :: random_obs
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j
+  integer                                             :: element_type_index
+
+  !    REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_matrices
+  !    integer                                             :: nobs = 0
+  !    integer                                             :: i = 0
+  !    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: scoords
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes: ", obscodes(j)
+  !    end do
+
+
+
+  !    write(*, *) "obscodes(1) ", obscodes(1)
+  !    write(*, *) "obscodes(2) ", obscodes(2)
+  !    write(*, *) "obscodes(3) ", obscodes(3)
+  !    write(*, *) "filters(1) ", filters(1)
+  !    write(*, *) "filters(2) ", filters(2)
+  !    write(*, *) "filters(3) ", filters(3)
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    write(*, *) "coords(1) ", coords(1, :)
+  !    write(*, *) "coords(2) ", coords(2, :)
+  !    write(*, *) "coords(3) ", coords(3, :)
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "element_type '", element_type, "'"
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init (these values come from best practices and default OpenOrb values).
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  apriori_a_max = 1000.0_8
+  apriori_a_min = 4.65423999999999959E-003_8
+  apriori_rho_max = -1.0_8
+  apriori_rho_min = -1.0_8
+  outlier_rejection = .false.
+  outlier_multiplier = 4.0_8
+  sor_type_prm = 2
+  sor_2point_method = "continued fraction"
+  sor_2point_method_sw = "continued fraction"
+  sor_norb = num_orbits
+  sor_norb_sw = sor_norb / 10
+  sor_ntrial = sor_norb * 2000
+  sor_ntrial_sw = sor_norb_sw * 400
+  sor_niter = 3
+  sor_rho_init = huge(sor_rho_init)
+  sor_rho_init(1) = 0.0_8
+  sor_rho_init(2) = 100.0_8
+  sor_genwin_multiplier = 3.0_8
+  sor_genwin_offset = 0.0_8
+  accwin_multiplier = 3.0_8
+  gaussian_rho = .false.
+  pdf_ml_init = -1.0_8
+  uniform = .false.
+  regularized = .true.
+  random_obs = .false.
+  obss => null()
+  call nullify(storb)
+  j = 0
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Figure out the element_type_index
+  element_type_index = -1
+  do j=1,size(ORBITAL_ELEMENTS)
+     if(trim(element_type) == trim(ORBITAL_ELEMENTS(j))) then
+        element_type_index = j
+        exit
+        !        else
+        !            write(*, *) "'" // trim(element_type) // "' =/ '" // trim(ORBITAL_ELEMENTS(j)) // "'"
+        !            write(*, *) " ", len(trim(element_type)), " =/ ", len(trim(ORBITAL_ELEMENTS(j)))
+     end if
+  end do
+  if(element_type_index .le. 0) then
+     ! Error: unsupported element type!
+     error_code = 58
+     return
+  end if
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Now that we have a set of Observations, pass them to the ranging routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  ! We clearly expect one track only, so this loop is here only so that we can
+  ! support multiple track processing later on. But it could just as well be
+  ! eliminated...
+  do j=1,size(obss)
+     call nullify(storb)
+
+     !        scoords => getObservationSCoords(obss(j))
+     !        do i=1,size(scoords)
+     !            write(*, *) "RA:  ", getLongitude(scoords(i))
+     !            write(*, *) "Dec: ", getLatitude(scoords(i))
+     !        end do
+
+
+     call ranging(obs_in=obss(j), element_type=trim(element_type), &
+          dyn_model=trim(dyn_model), &
+          integration_step=integration_step, &
+          perturbers=perturbers, apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_rho_max=apriori_rho_max, &
+          apriori_rho_min=apriori_rho_min, &
+          outlier_rejection=outlier_rejection, &
+          outlier_multiplier=outlier_multiplier, &
+          sor_type_prm=sor_type_prm, &
+          sor_2point_method=trim(sor_2point_method), &
+          sor_2point_method_sw=trim(sor_2point_method_sw), &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          sor_genwin_multiplier=sor_genwin_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          accwin_multiplier=accwin_multiplier, &
+          gaussian_rho=gaussian_rho, &
+          pdf_ml_init=pdf_ml_init, uniform=uniform, &
+          regularized=regularized, random_obs=random_obs, &
+          outOrbit=storb, errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Dump the storb orbit.
+     ! call dumpRangingOrbits(storb, errorCode=error_code)
+
+     ! Now flatten the ranging orbits.
+     call exportRangingOrbits(storb, element_type, track_id, out_orbits, &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+
+  deallocate(perturbers)
+  return
+end subroutine oorb_ranging
+
+
+
+subroutine oorb_lsl_fast(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     in_orbits,                                 &
+     num_orbits,                                &
+     out_orbit,                                 &
+     out_covariance,                            &
+     out_sigmas,                                &
+     out_correlation,                           &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, el_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  character(len=6)                                    :: dyn_model_init
+  real(8)                                             :: integration_step
+  real(8)                                             :: integration_step_init
+  real(8)                                             :: ls_correction_factor
+  LOGICAL, DIMENSION(6)                               :: ls_element_mask
+  integer                                             :: ls_niter_major_max
+  integer                                             :: ls_niter_major_min
+  integer                                             :: ls_niter_minor
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  real(8)                                             :: accwin_multiplier
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  TYPE (StochasticOrbit)                              :: in_storb
+  integer                                             :: j
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes(", j, ") ", obscodes(j)
+  !    end do
+  !    do j=1,num_coords
+  !        write(*, *) "filters(", j, ") ", filters(j)
+  !    end do
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    do j=1,num_coords
+  !        write(*, *) "coords(", j, ") ", coords(j,:)
+  !    end do
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init variables (from OpenOrb config file and best practices).
+  error_code = 0
+  dyn_model = "2-body"
+  dyn_model_init = "2-body"
+  integration_step = 5.0_8
+  integration_step_init = 5.0_8
+  ls_correction_factor = 0.2_8
+  ls_element_mask = .true.
+  ls_niter_major_max = 20
+  ls_niter_major_min = 2
+  ls_niter_minor = 10
+  outlier_rejection = .false.
+  outlier_multiplier = 3.0_8
+  accwin_multiplier = 3.0_8
+
+  ! Quick sanity check.
+  if(size(in_orbits) .le. 0) then
+     ! Nothing to do.
+     return
+  end if
+
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbits (the are supposed to 
+  ! be all the same).
+  element_type_index = in_orbits(1, 15)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Convert the input orbits (which come from the ranging routine) into a 
+  ! StochasticOrbit instance.
+  call nullify(in_storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       in_storb,                           &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+
+  ! Now that we have a set of Observations, pass them to the lsl routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  do j=1,size(obss)
+     call nullify(storb)
+
+     ! Do the LSL thing!
+     call lsl(obs_in=obss(j),                                            &
+          element_type=element_type,                                 &
+          dyn_model=dyn_model,                                       &
+          dyn_model_init=dyn_model_init,                             &
+          integration_step=integration_step,                         &
+          integration_step_init=integration_step_init,               &
+          perturbers=perturbers,                                     &
+          ls_correction_factor=ls_correction_factor,                 &
+          ls_element_mask=ls_element_mask,                           &
+          ls_niter_major_max=ls_niter_major_max,                     &
+          ls_niter_major_min=ls_niter_major_min,                     &
+          ls_niter_minor=ls_niter_minor,                             &
+          outlier_rejection=outlier_rejection,                       &
+          outlier_multiplier=outlier_multiplier,                     &
+          accwin_multiplier=accwin_multiplier,                       &
+          inStochOrbit=in_storb,                                     &
+          outStochOrbit=storb,                                       &
+          errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Now flatten the lsl orbit.
+     call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+          out_covariance, out_sigmas, out_correlation,    &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+  deallocate(perturbers)
+end subroutine oorb_lsl_fast
+
+
+
+subroutine oorb_lsl(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     in_orbits,                                 &
+     num_orbits,                                &
+     out_orbit,                                 &
+     out_covariance,                            &
+     out_sigmas,                                &
+     out_correlation,                           &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, el_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  character(len=6)                                    :: dyn_model_init
+  real(8)                                             :: integration_step
+  real(8)                                             :: integration_step_init
+  real(8)                                             :: ls_correction_factor
+  LOGICAL, DIMENSION(6)                               :: ls_element_mask
+  integer                                             :: ls_niter_major_max
+  integer                                             :: ls_niter_major_min
+  integer                                             :: ls_niter_minor
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  real(8)                                             :: accwin_multiplier
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  TYPE (StochasticOrbit)                              :: in_storb
+  integer                                             :: j
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes(", j, ") ", obscodes(j)
+  !    end do
+  !    do j=1,num_coords
+  !        write(*, *) "filters(", j, ") ", filters(j)
+  !    end do
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    do j=1,num_coords
+  !        write(*, *) "coords(", j, ") ", coords(j,:)
+  !    end do
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init variables (from OpenOrb config file and best practices).
+  error_code = 0
+  dyn_model = "n-body"
+  dyn_model_init = "2-body"
+  integration_step = 5.0_8
+  integration_step_init = 5.0_8
+  ls_correction_factor = 0.2_8
+  ls_element_mask = .true.
+  ls_niter_major_max = 20
+  ls_niter_major_min = 2
+  ls_niter_minor = 10
+  outlier_rejection = .false.
+  outlier_multiplier = 3.0_8
+  accwin_multiplier = 3.0_8
+
+  ! Quick sanity check.
+  if(size(in_orbits) .le. 0) then
+     ! Nothing to do.
+     return
+  end if
+
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbits (the are supposed to 
+  ! be all the same).
+  element_type_index = in_orbits(1, 15)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Convert the input orbits (which come from the ranging routine) into a 
+  ! StochasticOrbit instance.
+  call nullify(in_storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       in_storb,                           &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+
+  ! Now that we have a set of Observations, pass them to the lsl routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  do j=1,size(obss)
+     call nullify(storb)
+
+     ! Do the LSL thing!
+     call lsl(obs_in=obss(j),                                            &
+          element_type=element_type,                                 &
+          dyn_model=dyn_model,                                       &
+          dyn_model_init=dyn_model_init,                             &
+          integration_step=integration_step,                         &
+          integration_step_init=integration_step_init,               &
+          perturbers=perturbers,                                     &
+          ls_correction_factor=ls_correction_factor,                 &
+          ls_element_mask=ls_element_mask,                           &
+          ls_niter_major_max=ls_niter_major_max,                     &
+          ls_niter_major_min=ls_niter_major_min,                     &
+          ls_niter_minor=ls_niter_minor,                             &
+          outlier_rejection=outlier_rejection,                       &
+          outlier_multiplier=outlier_multiplier,                     &
+          accwin_multiplier=accwin_multiplier,                       &
+          inStochOrbit=in_storb,                                     &
+          outStochOrbit=storb,                                       &
+          errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Now flatten the lsl orbit.
+     call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+          out_covariance, out_sigmas, out_correlation,    &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+  deallocate(perturbers)
+end subroutine oorb_lsl
+
+
+
+subroutine oorb_propagate_orbit_fast(in_orbit, in_covariance, in_mjd,       &
+     out_orbit, out_covariance, out_sigmas, &
+     out_correlation, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! The epoch (MJD TAI) we want to propagate to.
+  real(8), intent(in)                                 :: in_mjd
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  integer                                             :: track_id
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call propagateOrbit(storb, dyn_model, integration_step, perturbers,  &
+       in_mjd, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! And now re-flatten the StochasticOrbit.
+  track_id = IDINT(in_orbit(1))
+  call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+       out_covariance, out_sigmas, out_correlation,    &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+  deallocate(perturbers)
+  return
+end subroutine oorb_propagate_orbit_fast
+
+
+
+subroutine oorb_propagate_orbit(in_orbit, in_covariance, in_mjd, out_orbit, &
+     out_covariance, out_sigmas,                 &
+     out_correlation, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! The epoch (MJD TAI) we want to propagate to.
+  real(8), intent(in)                                 :: in_mjd
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  integer                                             :: track_id
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call propagateOrbit(storb, dyn_model, integration_step, perturbers,  &
+       in_mjd, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! And now re-flatten the StochasticOrbit.
+  track_id = IDINT(in_orbit(1))
+  call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+       out_covariance, out_sigmas, out_correlation,    &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+  deallocate(perturbers)
+  return
+end subroutine oorb_propagate_orbit
+
+
+
+subroutine oorb_ephemeris_fast(in_orbit,                                &
+     in_covariance,                           &
+     in_obscode,                              &
+     in_num_ephems,                           &
+     in_step,                                 &
+     out_ephems,                              &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  character(len=4), intent(in)                        :: in_obscode
+  ! Compute epehemeris from the orbit epoch to epoch+in_step*in_num_ephems
+  ! Number of ephemeris to compute.
+  integer, intent(in)                                 :: in_num_ephems
+  ! Ephemeris step in fractional days.
+  real(8), intent(in)                                 :: in_step
+  ! Output ephemeris
+  ! out_ephems = ((dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa), )
+  real(8), dimension(in_num_ephems,10), intent(out)   :: out_ephems
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+  TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephem_arr
+  REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_arr
+  REAL(8), DIMENSION(:,:), POINTER                    :: pdfs_arr
+  TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+  real(8)                                             :: timespan
+  real(8)                                             :: step
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Compute timespan given step and num_ephems.
+  timespan = in_step * in_num_ephems
+  step = in_step          ! Might be modified by the code below.
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call ephemeris(storb,                                                   &
+       element_type,                                            &
+       dyn_model,                                               &
+       integration_step,                                        &
+       perturbers,                                              &
+       in_obscode,                                              &
+       timespan,                                                &
+       step,                                                    &
+       ephem_arr,                                               &
+       cov_arr,                                                 &
+       pdfs_arr,                                                &
+       observers,                                               &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now Export the ephem_arr to a flar array.
+  call exportEphemeris(storb, ephem_arr, cov_arr, observers, out_ephems,  &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  return
+end subroutine oorb_ephemeris_fast
+
+
+
+subroutine oorb_ephemeris(in_orbit,                                         &
+     in_covariance,                                    &
+     in_obscode,                                       &
+     in_num_ephems,                                    &
+     in_step,                                          &
+     out_ephems,                                       &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  character(len=4), intent(in)                        :: in_obscode
+  ! Compute epehemeris from the orbit epoch to epoch+in_step*in_num_ephems
+  ! Number of ephemeris to compute.
+  integer, intent(in)                                 :: in_num_ephems
+  ! Ephemeris step in fractional days.
+  real(8), intent(in)                                 :: in_step
+  ! Output ephemeris
+  ! out_ephems = ((dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa), )
+  real(8), dimension(in_num_ephems,10), intent(out)   :: out_ephems
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+  TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephem_arr
+  REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_arr
+  REAL(8), DIMENSION(:,:), POINTER                    :: pdfs_arr
+  TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+  real(8)                                             :: timespan
+  real(8)                                             :: step
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Compute timespan given step and num_ephems.
+  timespan = in_step * in_num_ephems
+  step = in_step          ! Might be modified by the code below.
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call ephemeris(storb,                                                   &
+       element_type,                                            &
+       dyn_model,                                               &
+       integration_step,                                        &
+       perturbers,                                              &
+       in_obscode,                                              &
+       timespan,                                                &
+       step,                                                    &
+       ephem_arr,                                               &
+       cov_arr,                                                 &
+       pdfs_arr,                                                &
+       observers,                                               &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now Export the ephem_arr to a flar array.
+  call exportEphemeris(storb, ephem_arr, cov_arr, observers, out_ephems,  &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  return
+end subroutine oorb_ephemeris
+
+
+
+subroutine oorb_moid(in_orbit, in_covariance, moid, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! Output MOID
+  real(8), intent(out)                                :: moid
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal vars
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call computeMoid(storb, moid, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  return
+end subroutine oorb_moid
+
+
+
+subroutine priv_classification(in_orbits, num_orbits, weights, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Class names and probability arrays.
+  ! CHARACTER(len=16), DIMENSION(17), intent(out)       :: classes
+  REAL(8), DIMENSION(17), intent(out)                 :: weights
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal vars
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j = 0
+  REAL(bp), DIMENSION(:), POINTER                     :: weight_arr
+  CHARACTER(len=16), DIMENSION(:), POINTER            :: group_name_arr
+
+
+  ! Init
+  error_code = 0
+
+  ! Create a StochastisOrbit instance form the flattened input orbits.
+  call nullify(storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       storb,                              &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call classification(storb, group_name_arr, weight_arr, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+
+  ! Copy values from the pointers to the regular arrays.
+  do j=1,min(size(weights), size(weight_arr))
+     !        classes(j) = group_name_arr(j)
+     weights(j) = weight_arr(j)
+     !        write(*, *) "classes(j): ", classes(j)
+     !        write(*, *) "weights(j): ", weights(j)
+  end do
+  deallocate(group_name_arr)
+  deallocate(weight_arr)
+  return
+end subroutine priv_classification
+
+
+
+subroutine oorb_calendardate_to_mjd(year, month, day, mjd, timescale, &
+     error_code)
+  use liboorb, only: calendarDateToMjd
+
+  ! Input: year, month, fractional days in whatever timescale they are 
+  ! (usually UTC or UT1). Output MJD TAI.
+
+  integer, intent(in)                             :: year
+  integer, intent(in)                             :: month
+  ! day + time in fractional days.
+  real(8), intent(in)                             :: day
+  CHARACTER(len=*), intent(in)                    :: timescale
+  real(8), intent(out)                            :: mjd
+  integer, intent(out)                            :: error_code
+
+
+  call calendarDateToMjd(year, month, day, mjd, trim(timescale), error_code)
+  return
+end subroutine oorb_calendardate_to_mjd
+
+
+
+subroutine oorb_mjdutc_to_mjdtai(mjd_utc, mjd_tai, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD UTC
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_utc
+  real(8), intent(out)                            :: mjd_tai
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_utc, "UTC", mjd_tai, "TAI", error_code)
+  return
+end subroutine oorb_mjdutc_to_mjdtai
+
+
+
+subroutine oorb_mjdtai_to_mjdutc(mjd_tai, mjd_utc, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD UTC
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_tai
+  real(8), intent(out)                            :: mjd_utc
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tai, "TAI", mjd_utc, "UTC", error_code)
+  return
+end subroutine oorb_mjdtai_to_mjdutc
+
+
+
+subroutine oorb_mjdtt_to_mjdtai(mjd_tt, mjd_tai, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD TT = MJD TAI + 32.184 seconds
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_tt
+  real(8), intent(out)                            :: mjd_tai
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tt, "TT", mjd_tai, "TAI", error_code)
+  return
+end subroutine oorb_mjdtt_to_mjdtai
+
+
+
+subroutine oorb_mjdtai_to_mjdtt(mjd_tai, mjd_tt, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD TAI
+  ! Output: MJD TT = MJD TAI + 32.184 seconds
+  real(8), intent(in)                             :: mjd_tai
+  real(8), intent(out)                            :: mjd_tt
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tai, "TAI", mjd_tt, "TT", error_code)
+  return
+end subroutine oorb_mjdtai_to_mjdtt
+
+
+
+subroutine sexagesimal_hours_to_deci_deg(h, m, s, deg, error_code)
+  integer, intent(in)                             :: h
+  integer, intent(in)                             :: m
+  real(8), intent(in)                             :: s
+  real(8), intent(out)                            :: deg
+  integer, intent(out)                            :: error_code
+
+
+  error_code = 0
+  call sexagesimal_deg_to_deci_deg(h, m, s, deg, error_code)
+  deg = deg * 15.0_8
+  return
+end subroutine sexagesimal_hours_to_deci_deg
+
+
+
+subroutine sexagesimal_deg_to_deci_deg(d, m, s, deg, error_code)
+  integer, intent(in)                             :: d
+  integer, intent(in)                             :: m
+  real(8), intent(in)                             :: s
+  real(8), intent(out)                            :: deg
+  integer, intent(out)                            :: error_code
+
+
+  error_code = 0
+  if(d .ge. 0.0_8) then
+     deg = d + m / 60.0_8 + s / 3600.0_8
+  else
+     deg = d - m / 60.0_8 - s / 3600.0_8
+  end if
+  return
+end subroutine sexagesimal_deg_to_deci_deg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: trunk/mops/oorb/python/wrapper4mops.f90
===================================================================
--- trunk/mops/oorb/python/wrapper4mops.f90	(revision 34646)
+++ trunk/mops/oorb/python/wrapper4mops.f90	(revision 34646)
@@ -0,0 +1,1564 @@
+!
+! LSST Data Management System
+! Copyright 2008, 2009 LSST Corporation.
+!
+! This product includes software developed by the
+! LSST Project (http://www.lsst.org/).
+!
+! 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 LSST License Statement and
+! the GNU General Public License along with this program.  If not,
+! see <http://www.lsstcorp.org/LegalNotices/>.
+!
+! 
+! OpenOrb library
+! F. Pierfederici <fpierfed@gmail.com>
+! 
+! Description
+! 
+! Notes
+! error is a boolean global and is defined somewhere in liboorb.so!
+! 
+! 
+! Implementation notes:
+!   1. both oorb_ranging_fast and oorb_lsl_fast have a useless loop in them:
+!      either clean them up or make them useful!
+! 
+! 
+
+! Orbital elements that we support.
+! ORBITAL_ELEMENTS = (/ "keplerian",  "delaunay", "poincare", "equinoctial" /)
+
+
+
+
+
+subroutine oorb_init(ephemFileName, verbosity, error_code)
+  ! Initialize the OpenOrb module.
+  !
+  ! @param ephemFileName: full path of the JPL ephem file (usually 
+  !        $OORB_DATA/JPL_ephemeris/de405.dat).
+  ! @param verbosity: verbosity level for OpenOrb calls [0, 5] (default 0)
+  ! @return error_code: int error code. 0 = success, otherwise, failure.
+  use liboorb, only: init
+  ! Input/Output variables.
+  character(len=*), intent(IN)    :: ephemFileName
+  integer, intent(in)             :: verbosity
+  integer, intent(OUT)            :: error_code
+
+
+  call init(trim(ephemFileName), verbosity, error_code)
+
+end subroutine oorb_init
+
+
+
+subroutine oorb_ranging_fast(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     element_type,                              &
+     num_orbits,                                &
+     out_orbits,                                &
+     error_code)
+  use liboorb
+  use Observations_cl
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  ! Element type used in the orbit computation (default keplerian)
+  CHARACTER(len=11), intent(in)                       :: element_type
+  ! How may orbits do we want out?
+  integer, intent(in)                                 :: num_orbits
+  ! Output flattened orbits.
+  ! out_orbits has the form (id, (elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), element_type_index), )
+  real(8),dimension(num_orbits,15),intent(out)        :: out_orbits
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  real(8)                                             :: apriori_a_max
+  real(8)                                             :: apriori_a_min
+  real(8)                                             :: apriori_rho_max
+  real(8)                                             :: apriori_rho_min
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  integer                                             :: sor_type_prm
+  character(len=80)                                   :: sor_2point_method
+  character(len=80)                                   :: sor_2point_method_sw
+  integer                                             :: sor_norb
+  integer                                             :: sor_norb_sw
+  integer                                             :: sor_ntrial
+  integer                                             :: sor_ntrial_sw
+  integer                                             :: sor_niter
+  REAL(8), DIMENSION(4)                               :: sor_rho_init
+  real(8)                                             :: sor_genwin_multiplier
+  REAL(8), DIMENSION(4)                               :: sor_genwin_offset
+  real(8)                                             :: accwin_multiplier
+  logical                                             :: gaussian_rho
+  real(8)                                             :: pdf_ml_init
+  logical                                             :: uniform
+  logical                                             :: regularized
+  logical                                             :: random_obs
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j
+  integer                                             :: element_type_index
+
+  !    REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_matrices
+  !    integer                                             :: nobs = 0
+  !    integer                                             :: i = 0
+  !    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: scoords
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes: ", obscodes(j)
+  !    end do
+
+
+
+  !    write(*, *) "obscodes(1) ", obscodes(1)
+  !    write(*, *) "obscodes(2) ", obscodes(2)
+  !    write(*, *) "obscodes(3) ", obscodes(3)
+  !    write(*, *) "filters(1) ", filters(1)
+  !    write(*, *) "filters(2) ", filters(2)
+  !    write(*, *) "filters(3) ", filters(3)
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    write(*, *) "coords(1) ", coords(1, :)
+  !    write(*, *) "coords(2) ", coords(2, :)
+  !    write(*, *) "coords(3) ", coords(3, :)
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "element_type '", element_type, "'"
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init (these values come from best practices and default OpenOrb values).
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  apriori_a_max = 1000.0_8
+  apriori_a_min = 4.65423999999999959E-003_8
+  apriori_rho_max = -1.0_8
+  apriori_rho_min = -1.0_8
+  outlier_rejection = .false.
+  outlier_multiplier = 4.0_8
+  sor_type_prm = 2
+  sor_2point_method = "continued fraction"
+  sor_2point_method_sw = "continued fraction"
+  sor_norb = num_orbits
+  sor_norb_sw = sor_norb / 10
+  sor_ntrial = sor_norb * 2000
+  sor_ntrial_sw = sor_norb_sw * 400
+  sor_niter = 3
+  sor_rho_init = huge(sor_rho_init)
+  sor_rho_init(1) = 0.0_8
+  sor_rho_init(2) = 100.0_8
+  sor_genwin_multiplier = 3.0_8
+  sor_genwin_offset = 0.0_8
+  accwin_multiplier = 3.0_8
+  gaussian_rho = .false.
+  pdf_ml_init = -1.0_8
+  uniform = .false.
+  regularized = .true.
+  random_obs = .false.
+  obss => null()
+  call nullify(storb)
+  j = 0
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Figure out the element_type_index
+  element_type_index = -1
+  do j=1,size(ORBITAL_ELEMENTS)
+     if(trim(element_type) == trim(ORBITAL_ELEMENTS(j))) then
+        element_type_index = j
+        exit
+        !        else
+        !            write(*, *) "'" // trim(element_type) // "' =/ '" // trim(ORBITAL_ELEMENTS(j)) // "'"
+        !            write(*, *) " ", len(trim(element_type)), " =/ ", len(trim(ORBITAL_ELEMENTS(j)))
+     end if
+  end do
+  if(element_type_index .le. 0) then
+     ! Error: unsupported element type!
+     error_code = 58
+     return
+  end if
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Now that we have a set of Observations, pass them to the ranging routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  ! We clearly expect one track only, so this loop is here only so that we can
+  ! support multiple track processing later on. But it could just as well be
+  ! eliminated...
+  do j=1,size(obss)
+     call nullify(storb)
+
+     !        scoords => getObservationSCoords(obss(j))
+     !        do i=1,size(scoords)
+     !            write(*, *) "RA:  ", getLongitude(scoords(i))
+     !            write(*, *) "Dec: ", getLatitude(scoords(i))
+     !        end do
+
+
+     call ranging(obs_in=obss(j), element_type=trim(element_type), &
+          dyn_model=trim(dyn_model), &
+          integration_step=integration_step, &
+          perturbers=perturbers, apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_rho_max=apriori_rho_max, &
+          apriori_rho_min=apriori_rho_min, &
+          outlier_rejection=outlier_rejection, &
+          outlier_multiplier=outlier_multiplier, &
+          sor_type_prm=sor_type_prm, &
+          sor_2point_method=trim(sor_2point_method), &
+          sor_2point_method_sw=trim(sor_2point_method_sw), &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          sor_genwin_multiplier=sor_genwin_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          accwin_multiplier=accwin_multiplier, &
+          gaussian_rho=gaussian_rho, &
+          pdf_ml_init=pdf_ml_init, uniform=uniform, &
+          regularized=regularized, random_obs=random_obs, &
+          outOrbit=storb, errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Dump the storb orbit.
+     ! call dumpRangingOrbits(storb, errorCode=error_code)
+
+     ! Now flatten the ranging orbits.
+     call exportRangingOrbits(storb, element_type, track_id, out_orbits, &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+
+  deallocate(perturbers)
+
+end subroutine oorb_ranging_fast
+
+
+
+subroutine oorb_ranging(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     element_type,                              &
+     num_orbits,                                &
+     out_orbits,                                &
+     error_code)
+  use liboorb
+  use Observations_cl
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  ! Element type used in the orbit computation (default keplerian)
+  CHARACTER(len=11), intent(in)                       :: element_type
+  ! How may orbits do we want out?
+  integer, intent(in)                                 :: num_orbits
+  ! Output flattened orbits.
+  ! out_orbits has the form (id, (elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), element_type_index), )
+  real(8),dimension(num_orbits,15),intent(out)        :: out_orbits
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  real(8)                                             :: apriori_a_max
+  real(8)                                             :: apriori_a_min
+  real(8)                                             :: apriori_rho_max
+  real(8)                                             :: apriori_rho_min
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  integer                                             :: sor_type_prm
+  character(len=80)                                   :: sor_2point_method
+  character(len=80)                                   :: sor_2point_method_sw
+  integer                                             :: sor_norb
+  integer                                             :: sor_norb_sw
+  integer                                             :: sor_ntrial
+  integer                                             :: sor_ntrial_sw
+  integer                                             :: sor_niter
+  REAL(8), DIMENSION(4)                               :: sor_rho_init
+  real(8)                                             :: sor_genwin_multiplier
+  REAL(8), DIMENSION(4)                               :: sor_genwin_offset
+  real(8)                                             :: accwin_multiplier
+  logical                                             :: gaussian_rho
+  real(8)                                             :: pdf_ml_init
+  logical                                             :: uniform
+  logical                                             :: regularized
+  logical                                             :: random_obs
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j
+  integer                                             :: element_type_index
+
+  !    REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_matrices
+  !    integer                                             :: nobs = 0
+  !    integer                                             :: i = 0
+  !    TYPE (SphericalCoordinates), DIMENSION(:), POINTER  :: scoords
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes: ", obscodes(j)
+  !    end do
+
+
+
+  !    write(*, *) "obscodes(1) ", obscodes(1)
+  !    write(*, *) "obscodes(2) ", obscodes(2)
+  !    write(*, *) "obscodes(3) ", obscodes(3)
+  !    write(*, *) "filters(1) ", filters(1)
+  !    write(*, *) "filters(2) ", filters(2)
+  !    write(*, *) "filters(3) ", filters(3)
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    write(*, *) "coords(1) ", coords(1, :)
+  !    write(*, *) "coords(2) ", coords(2, :)
+  !    write(*, *) "coords(3) ", coords(3, :)
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "element_type '", element_type, "'"
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init (these values come from best practices and default OpenOrb values).
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  apriori_a_max = 1000.0_8
+  apriori_a_min = 4.65423999999999959E-003_8
+  apriori_rho_max = -1.0_8
+  apriori_rho_min = -1.0_8
+  outlier_rejection = .false.
+  outlier_multiplier = 4.0_8
+  sor_type_prm = 2
+  sor_2point_method = "continued fraction"
+  sor_2point_method_sw = "continued fraction"
+  sor_norb = num_orbits
+  sor_norb_sw = sor_norb / 10
+  sor_ntrial = sor_norb * 2000
+  sor_ntrial_sw = sor_norb_sw * 400
+  sor_niter = 3
+  sor_rho_init = huge(sor_rho_init)
+  sor_rho_init(1) = 0.0_8
+  sor_rho_init(2) = 100.0_8
+  sor_genwin_multiplier = 3.0_8
+  sor_genwin_offset = 0.0_8
+  accwin_multiplier = 3.0_8
+  gaussian_rho = .false.
+  pdf_ml_init = -1.0_8
+  uniform = .false.
+  regularized = .true.
+  random_obs = .false.
+  obss => null()
+  call nullify(storb)
+  j = 0
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Figure out the element_type_index
+  element_type_index = -1
+  do j=1,size(ORBITAL_ELEMENTS)
+     if(trim(element_type) == trim(ORBITAL_ELEMENTS(j))) then
+        element_type_index = j
+        exit
+        !        else
+        !            write(*, *) "'" // trim(element_type) // "' =/ '" // trim(ORBITAL_ELEMENTS(j)) // "'"
+        !            write(*, *) " ", len(trim(element_type)), " =/ ", len(trim(ORBITAL_ELEMENTS(j)))
+     end if
+  end do
+  if(element_type_index .le. 0) then
+     ! Error: unsupported element type!
+     error_code = 58
+     return
+  end if
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Now that we have a set of Observations, pass them to the ranging routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  ! We clearly expect one track only, so this loop is here only so that we can
+  ! support multiple track processing later on. But it could just as well be
+  ! eliminated...
+  do j=1,size(obss)
+     call nullify(storb)
+
+     !        scoords => getObservationSCoords(obss(j))
+     !        do i=1,size(scoords)
+     !            write(*, *) "RA:  ", getLongitude(scoords(i))
+     !            write(*, *) "Dec: ", getLatitude(scoords(i))
+     !        end do
+
+
+     call ranging(obs_in=obss(j), element_type=trim(element_type), &
+          dyn_model=trim(dyn_model), &
+          integration_step=integration_step, &
+          perturbers=perturbers, apriori_a_max=apriori_a_max, &
+          apriori_a_min=apriori_a_min, &
+          apriori_rho_max=apriori_rho_max, &
+          apriori_rho_min=apriori_rho_min, &
+          outlier_rejection=outlier_rejection, &
+          outlier_multiplier=outlier_multiplier, &
+          sor_type_prm=sor_type_prm, &
+          sor_2point_method=trim(sor_2point_method), &
+          sor_2point_method_sw=trim(sor_2point_method_sw), &
+          sor_norb=sor_norb, sor_norb_sw=sor_norb_sw, &
+          sor_ntrial=sor_ntrial, sor_ntrial_sw=sor_ntrial_sw, &
+          sor_niter=sor_niter, sor_rho_init=sor_rho_init, &
+          sor_genwin_multiplier=sor_genwin_multiplier, &
+          sor_genwin_offset=sor_genwin_offset, &
+          accwin_multiplier=accwin_multiplier, &
+          gaussian_rho=gaussian_rho, &
+          pdf_ml_init=pdf_ml_init, uniform=uniform, &
+          regularized=regularized, random_obs=random_obs, &
+          outOrbit=storb, errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Dump the storb orbit.
+     ! call dumpRangingOrbits(storb, errorCode=error_code)
+
+     ! Now flatten the ranging orbits.
+     call exportRangingOrbits(storb, element_type, track_id, out_orbits, &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+
+  deallocate(perturbers)
+
+end subroutine oorb_ranging
+
+
+
+subroutine oorb_lsl_fast(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     in_orbits,                                 &
+     num_orbits,                                &
+     out_orbit,                                 &
+     out_covariance,                            &
+     out_sigmas,                                &
+     out_correlation,                           &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, el_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  character(len=6)                                    :: dyn_model_init
+  real(8)                                             :: integration_step
+  real(8)                                             :: integration_step_init
+  real(8)                                             :: ls_correction_factor
+  LOGICAL, DIMENSION(6)                               :: ls_element_mask
+  integer                                             :: ls_niter_major_max
+  integer                                             :: ls_niter_major_min
+  integer                                             :: ls_niter_minor
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  real(8)                                             :: accwin_multiplier
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  TYPE (StochasticOrbit)                              :: in_storb
+  integer                                             :: j
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes(", j, ") ", obscodes(j)
+  !    end do
+  !    do j=1,num_coords
+  !        write(*, *) "filters(", j, ") ", filters(j)
+  !    end do
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    do j=1,num_coords
+  !        write(*, *) "coords(", j, ") ", coords(j,:)
+  !    end do
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init variables (from OpenOrb config file and best practices).
+  error_code = 0
+  dyn_model = "2-body"
+  dyn_model_init = "2-body"
+  integration_step = 5.0_8
+  integration_step_init = 5.0_8
+  ls_correction_factor = 0.2_8
+  ls_element_mask = .true.
+  ls_niter_major_max = 20
+  ls_niter_major_min = 2
+  ls_niter_minor = 10
+  outlier_rejection = .false.
+  outlier_multiplier = 3.0_8
+  accwin_multiplier = 3.0_8
+
+  ! Quick sanity check.
+  if(size(in_orbits) .le. 0) then
+     ! Nothing to do.
+     return
+  end if
+
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbits (the are supposed to 
+  ! be all the same).
+  element_type_index = in_orbits(1, 15)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Convert the input orbits (which come from the ranging routine) into a 
+  ! StochasticOrbit instance.
+  call nullify(in_storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       in_storb,                           &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+
+  ! Now that we have a set of Observations, pass them to the lsl routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  do j=1,size(obss)
+     call nullify(storb)
+
+     ! Do the LSL thing!
+     call lsl(obs_in=obss(j),                                            &
+          element_type=element_type,                                 &
+          dyn_model=dyn_model,                                       &
+          dyn_model_init=dyn_model_init,                             &
+          integration_step=integration_step,                         &
+          integration_step_init=integration_step_init,               &
+          perturbers=perturbers,                                     &
+          ls_correction_factor=ls_correction_factor,                 &
+          ls_element_mask=ls_element_mask,                           &
+          ls_niter_major_max=ls_niter_major_max,                     &
+          ls_niter_major_min=ls_niter_major_min,                     &
+          ls_niter_minor=ls_niter_minor,                             &
+          outlier_rejection=outlier_rejection,                       &
+          outlier_multiplier=outlier_multiplier,                     &
+          accwin_multiplier=accwin_multiplier,                       &
+          inStochOrbit=in_storb,                                     &
+          outStochOrbit=storb,                                       &
+          errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Now flatten the lsl orbit.
+     call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+          out_covariance, out_sigmas, out_correlation,    &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+  deallocate(perturbers)
+end subroutine oorb_lsl_fast
+
+
+
+subroutine oorb_lsl(obscodes,                                  &
+     filters,                                   &
+     track_id,                                  &
+     num_coords,                                &
+     coords,                                    &
+     mjds,                                      &
+     mags,                                      &
+     in_orbits,                                 &
+     num_orbits,                                &
+     out_orbit,                                 &
+     out_covariance,                            &
+     out_sigmas,                                &
+     out_correlation,                           &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+  ! Orbital inversion using statistical orbital ranging, that is,
+  ! without making any assumptions on the shape of the resulting
+  ! orbital-element pdf.
+
+  ! All angles coming in are in decimal degrees. All times in MJD TAI.
+
+  ! Input/Output variables.
+  ! Observations (i.e. DiASources) to be used as input. It is assumed that 
+  ! they all belong to the same track.
+  ! We have to use separate arrays since they are of different type.
+  integer, intent(in)                                 :: track_id
+  integer, intent(in)                                 :: num_coords
+  real(8), dimension(num_coords), intent(in)          :: mjds
+  real(8), dimension(num_coords, 4), intent(in)       :: coords
+  real(8), dimension(num_coords), intent(in)          :: mags
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=1), dimension(num_coords), intent(in) :: filters
+  ! FIXME: f2py bug that only passes the first char of element of an array of
+  ! strings.
+  character(len=4), dimension(num_coords), intent(in) :: obscodes
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, el_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  character(len=6)                                    :: dyn_model
+  character(len=6)                                    :: dyn_model_init
+  real(8)                                             :: integration_step
+  real(8)                                             :: integration_step_init
+  real(8)                                             :: ls_correction_factor
+  LOGICAL, DIMENSION(6)                               :: ls_element_mask
+  integer                                             :: ls_niter_major_max
+  integer                                             :: ls_niter_major_min
+  integer                                             :: ls_niter_minor
+  logical                                             :: outlier_rejection
+  real(8)                                             :: outlier_multiplier
+  real(8)                                             :: accwin_multiplier
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  TYPE (Observations), DIMENSION(:), POINTER          :: obss
+  TYPE (StochasticOrbit)                              :: storb
+  TYPE (StochasticOrbit)                              :: in_storb
+  integer                                             :: j
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+
+
+  !    do j=1,num_coords
+  !        write(*, *) "obscodes(", j, ") ", obscodes(j)
+  !    end do
+  !    do j=1,num_coords
+  !        write(*, *) "filters(", j, ") ", filters(j)
+  !    end do
+  !    write(*, *) "track_id ", track_id
+  !    write(*, *) "num_coords ", num_coords
+  !    do j=1,num_coords
+  !        write(*, *) "coords(", j, ") ", coords(j,:)
+  !    end do
+  !    write(*, *) "mjds ", mjds
+  !    write(*, *) "mags ", mags
+  !    write(*, *) "num_orbits ", num_orbits
+
+  ! Init variables (from OpenOrb config file and best practices).
+  error_code = 0
+  dyn_model = "n-body"
+  dyn_model_init = "2-body"
+  integration_step = 5.0_8
+  integration_step_init = 5.0_8
+  ls_correction_factor = 0.2_8
+  ls_element_mask = .true.
+  ls_niter_major_max = 20
+  ls_niter_major_min = 2
+  ls_niter_minor = 10
+  outlier_rejection = .false.
+  outlier_multiplier = 3.0_8
+  accwin_multiplier = 3.0_8
+
+  ! Quick sanity check.
+  if(size(in_orbits) .le. 0) then
+     ! Nothing to do.
+     return
+  end if
+
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbits (the are supposed to 
+  ! be all the same).
+  element_type_index = in_orbits(1, 15)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Convert the input observation array into a list of Observations instances.
+  ! Input coordinates (and their uncertainties) are in decimal degrees.
+  ! We need them in radians.
+  call obssFromCoords(track_id, num_coords, coords*rad_deg, mjds, mags,   &
+       filters, obscodes, obss, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  !    do j=1,size(obss)
+  !        cov_matrices => getCovarianceMatrices(obss(j))
+  !        nobs = getNrOfObservations(obss(j))
+  !        DO i=1,nobs
+  !            write(*, *) "COV: ", cov_matrices(i,:,:)
+  !        END DO
+  !    end do
+
+  ! Convert the input orbits (which come from the ranging routine) into a 
+  ! StochasticOrbit instance.
+  call nullify(in_storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       in_storb,                           &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+
+  ! Now that we have a set of Observations, pass them to the lsl routine.
+  ! obss has already been separated into tracks, pass one track at the time.
+  do j=1,size(obss)
+     call nullify(storb)
+
+     ! Do the LSL thing!
+     call lsl(obs_in=obss(j),                                            &
+          element_type=element_type,                                 &
+          dyn_model=dyn_model,                                       &
+          dyn_model_init=dyn_model_init,                             &
+          integration_step=integration_step,                         &
+          integration_step_init=integration_step_init,               &
+          perturbers=perturbers,                                     &
+          ls_correction_factor=ls_correction_factor,                 &
+          ls_element_mask=ls_element_mask,                           &
+          ls_niter_major_max=ls_niter_major_max,                     &
+          ls_niter_major_min=ls_niter_major_min,                     &
+          ls_niter_minor=ls_niter_minor,                             &
+          outlier_rejection=outlier_rejection,                       &
+          outlier_multiplier=outlier_multiplier,                     &
+          accwin_multiplier=accwin_multiplier,                       &
+          inStochOrbit=in_storb,                                     &
+          outStochOrbit=storb,                                       &
+          errorCode=error_code)
+     if(error_code /= 0) then
+        return
+     end if
+
+     ! Now flatten the lsl orbit.
+     call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+          out_covariance, out_sigmas, out_correlation,    &
+          error_code)
+     call nullify(storb)
+     if(error_code /= 0) then
+        return
+     end if
+  end do
+  deallocate(perturbers)
+end subroutine oorb_lsl
+
+
+
+subroutine oorb_propagate_orbit_fast(in_orbit, in_covariance, in_mjd,       &
+     out_orbit, out_covariance, out_sigmas, &
+     out_correlation, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! The epoch (MJD TAI) we want to propagate to.
+  real(8), intent(in)                                 :: in_mjd
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  integer                                             :: track_id
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call propagateOrbit(storb, dyn_model, integration_step, perturbers,  &
+       in_mjd, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! And now re-flatten the StochasticOrbit.
+  track_id = IDINT(in_orbit(1))
+  call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+       out_covariance, out_sigmas, out_correlation,    &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+  deallocate(perturbers)
+  return
+end subroutine oorb_propagate_orbit_fast
+
+
+
+subroutine oorb_propagate_orbit(in_orbit, in_covariance, in_mjd, out_orbit, &
+     out_covariance, out_sigmas,                 &
+     out_correlation, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! The epoch (MJD TAI) we want to propagate to.
+  real(8), intent(in)                                 :: in_mjd
+  ! Output flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(out)                  :: out_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_covariance
+  REAL(8), DIMENSION(6), intent(out)                  :: out_sigmas
+  REAL(8), DIMENSION(6,6), intent(out)                :: out_correlation
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  integer                                             :: track_id
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call propagateOrbit(storb, dyn_model, integration_step, perturbers,  &
+       in_mjd, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! And now re-flatten the StochasticOrbit.
+  track_id = IDINT(in_orbit(1))
+  call exportLslOrbit(storb, element_type, track_id, out_orbit,       &
+       out_covariance, out_sigmas, out_correlation,    &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+  deallocate(perturbers)
+  return
+end subroutine oorb_propagate_orbit
+
+
+
+subroutine oorb_ephemeris_fast(in_orbit,                                &
+     in_covariance,                           &
+     in_obscode,                              &
+     in_num_ephems,                           &
+     in_step,                                 &
+     out_ephems,                              &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  character(len=4), intent(in)                        :: in_obscode
+  ! Compute epehemeris from the orbit epoch to epoch+in_step*in_num_ephems
+  ! Number of ephemeris to compute.
+  integer, intent(in)                                 :: in_num_ephems
+  ! Ephemeris step in fractional days.
+  real(8), intent(in)                                 :: in_step
+  ! Output ephemeris
+  ! out_ephems = ((dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa), )
+  real(8), dimension(in_num_ephems,10), intent(out)   :: out_ephems
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+  TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephem_arr
+  REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_arr
+  REAL(8), DIMENSION(:,:), POINTER                    :: pdfs_arr
+  TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+  real(8)                                             :: timespan
+  real(8)                                             :: step
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "2-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Compute timespan given step and num_ephems.
+  timespan = in_step * in_num_ephems
+  step = in_step          ! Might be modified by the code below.
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call ephemeris(storb,                                                   &
+       element_type,                                            &
+       dyn_model,                                               &
+       integration_step,                                        &
+       perturbers,                                              &
+       in_obscode,                                              &
+       timespan,                                                &
+       step,                                                    &
+       ephem_arr,                                               &
+       cov_arr,                                                 &
+       pdfs_arr,                                                &
+       observers,                                               &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now Export the ephem_arr to a flar array.
+  call exportEphemeris(storb, ephem_arr, cov_arr, observers, out_ephems,  &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+end subroutine oorb_ephemeris_fast
+
+
+subroutine oorb_ephemeris(in_orbit,                                         &
+     in_covariance,                                    &
+     in_obscode,                                       &
+     in_num_ephems,                                    &
+     in_step,                                          &
+     out_ephems,                                       &
+     error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  character(len=4), intent(in)                        :: in_obscode
+  ! Compute epehemeris from the orbit epoch to epoch+in_step*in_num_ephems
+  ! Number of ephemeris to compute.
+  integer, intent(in)                                 :: in_num_ephems
+  ! Ephemeris step in fractional days.
+  real(8), intent(in)                                 :: in_step
+  ! Output ephemeris
+  ! out_ephems = ((dist, ra, dec, mag, mjd, raErr, decErr, smaa, smia, pa), )
+  real(8), dimension(in_num_ephems,10), intent(out)   :: out_ephems
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal variables.
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=6)                                    :: dyn_model
+  real(8)                                             :: integration_step
+  LOGICAL, DIMENSION(:), pointer                      :: perturbers
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+  TYPE (SphericalCoordinates), DIMENSION(:,:),POINTER :: ephem_arr
+  REAL(8), DIMENSION(:,:,:), POINTER                  :: cov_arr
+  REAL(8), DIMENSION(:,:), POINTER                    :: pdfs_arr
+  TYPE (CartesianCoordinates), DIMENSION(:), POINTER  :: observers
+  real(8)                                             :: timespan
+  real(8)                                             :: step
+
+
+  ! Init
+  error_code = 0
+  dyn_model = "n-body"
+  integration_step = 5.0_8
+  allocate(perturbers(10), stat=error_code)
+  if(error_code /= 0) then
+     ! Error in allocating memory!
+     error_code = 57
+     return
+  end if
+  perturbers = .true.
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Compute timespan given step and num_ephems.
+  timespan = in_step * in_num_ephems
+  step = in_step          ! Might be modified by the code below.
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call ephemeris(storb,                                                   &
+       element_type,                                            &
+       dyn_model,                                               &
+       integration_step,                                        &
+       perturbers,                                              &
+       in_obscode,                                              &
+       timespan,                                                &
+       step,                                                    &
+       ephem_arr,                                               &
+       cov_arr,                                                 &
+       pdfs_arr,                                                &
+       observers,                                               &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now Export the ephem_arr to a flar array.
+  call exportEphemeris(storb, ephem_arr, cov_arr, observers, out_ephems,  &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+end subroutine oorb_ephemeris
+
+
+
+subroutine oorb_moid(in_orbit, in_covariance, moid, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  real(8),dimension(11), intent(in)                   :: in_orbit
+  ! Uncertainty matrices:
+  REAL(8), DIMENSION(6,6), intent(in)                 :: in_covariance
+  ! Output MOID
+  real(8), intent(out)                                :: moid
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal vars
+  TYPE (StochasticOrbit)                              :: storb
+  character(len=11)                                   :: element_type
+  integer                                             :: element_type_index
+
+
+  ! Init
+  error_code = 0
+
+  ! Get the element type from the input flattened orbit.
+  element_type_index = in_orbit(11)
+  if(element_type_index .le. 0 .or.                                       &
+       element_type_index .gt. size(ORBITAL_ELEMENTS)) then
+     ! Error: unsupported orbital elements.
+     error_code = 58
+     return
+  end if
+  element_type = ORBITAL_ELEMENTS(element_type_index)
+
+  ! Create a StochastisOrbit instance form the flattened input orbit.
+  call lslOrbitToStochasticOrbit(in_orbit,                                &
+       in_covariance,                           &
+       storb,                                   &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call computeMoid(storb, moid, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+end subroutine oorb_moid
+
+
+
+subroutine priv_classification(in_orbits, num_orbits, weights, error_code)
+  use liboorb
+  use StochasticOrbit_cl
+
+  ! Input/Output variables.
+  ! Input flattened orbit:
+  !  (track_id, elements(1:6), epoch, H, G, element_type_index)
+  ! FIXME: H and G are not currently computed.
+  integer, intent(in)                                 :: num_orbits
+  ! Input flattened orbits.
+  ! in_orbits has the form ((id, elements(1:6), epoch, Un-normalized p.d.f.,
+  ! Reduced chi2, Regularized apr, Jacobian det(1:3), el_type_index), )
+  real(8),dimension(num_orbits,15),intent(in)         :: in_orbits
+  ! Class names and probability arrays.
+  ! CHARACTER(len=16), DIMENSION(17), intent(out)       :: classes
+  REAL(8), DIMENSION(17), intent(out)                 :: weights
+  ! Output error code
+  integer, intent(out)                                :: error_code
+
+  ! Internal vars
+  TYPE (StochasticOrbit)                              :: storb
+  integer                                             :: j = 0
+  REAL(bp), DIMENSION(:), POINTER                     :: weight_arr
+  CHARACTER(len=16), DIMENSION(:), POINTER            :: group_name_arr
+
+
+  ! Init
+  error_code = 0
+
+  ! Create a StochastisOrbit instance form the flattened input orbits.
+  call nullify(storb)
+  call rangingOrbitsToStochasticOrbit(in_orbits,                          &
+       num_orbits,                         &
+       storb,                              &
+       error_code)
+  if(error_code /= 0) then
+     return
+  end if
+
+  ! Now call the orbit propagation routine.
+  call classification(storb, group_name_arr, weight_arr, error_code)
+  if(error_code /= 0) then
+     return
+  end if
+  call nullify(storb)
+
+  ! Copy values from the pointers to the regular arrays.
+  do j=1,min(size(weights), size(weight_arr))
+     !        classes(j) = group_name_arr(j)
+     weights(j) = weight_arr(j)
+     !        write(*, *) "classes(j): ", classes(j)
+     !        write(*, *) "weights(j): ", weights(j)
+  end do
+  deallocate(group_name_arr)
+  deallocate(weight_arr)
+
+end subroutine priv_classification
+
+
+
+subroutine oorb_calendardate_to_mjd(year, month, day, mjd, timescale, &
+     error_code)
+  use liboorb, only: calendarDateToMjd
+
+  ! Input: year, month, fractional days in whatever timescale they are 
+  ! (usually UTC or UT1). Output MJD TAI.
+
+  integer, intent(in)                             :: year
+  integer, intent(in)                             :: month
+  ! day + time in fractional days.
+  real(8), intent(in)                             :: day
+  CHARACTER(len=*), intent(in)                    :: timescale
+  real(8), intent(out)                            :: mjd
+  integer, intent(out)                            :: error_code
+
+
+  call calendarDateToMjd(year, month, day, mjd, timescale, error_code)
+
+end subroutine oorb_calendardate_to_mjd
+
+
+
+subroutine oorb_mjdutc_to_mjdtai(mjd_utc, mjd_tai, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD UTC
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_utc
+  real(8), intent(out)                            :: mjd_tai
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_utc, "UTC", mjd_tai, "TAI", error_code)
+
+end subroutine oorb_mjdutc_to_mjdtai
+
+
+
+subroutine oorb_mjdtai_to_mjdutc(mjd_tai, mjd_utc, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD UTC
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_tai
+  real(8), intent(out)                            :: mjd_utc
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tai, "TAI", mjd_utc, "UTC", error_code)
+
+end subroutine oorb_mjdtai_to_mjdutc
+
+
+
+subroutine oorb_mjdtt_to_mjdtai(mjd_tt, mjd_tai, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD TT = MJD TAI + 32.184 seconds
+  ! Output: MJD TAI
+  real(8), intent(in)                             :: mjd_tt
+  real(8), intent(out)                            :: mjd_tai
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tt, "TT", mjd_tai, "TAI", error_code)
+
+end subroutine oorb_mjdtt_to_mjdtai
+
+
+
+subroutine oorb_mjdtai_to_mjdtt(mjd_tai, mjd_tt, error_code)
+  use liboorb, only: mjdConvert
+
+  ! Input:  MJD TAI
+  ! Output: MJD TT = MJD TAI + 32.184 seconds
+  real(8), intent(in)                             :: mjd_tai
+  real(8), intent(out)                            :: mjd_tt
+  integer, intent(out)                            :: error_code
+
+
+  call mjdConvert(mjd_tai, "TAI", mjd_tt, "TT", error_code)
+
+end subroutine oorb_mjdtai_to_mjdtt
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: trunk/mops/oorb/test/K08K42V_lsl.mpc
===================================================================
--- trunk/mops/oorb/test/K08K42V_lsl.mpc	(revision 34646)
+++ trunk/mops/oorb/test/K08K42V_lsl.mpc	(revision 34646)
@@ -0,0 +1,16 @@
+     K08K42V* C2008 05 31.35234 16 54 34.36 +19 22 53.0          23.7 r EO002568
+     K08K42V  C2008 05 31.39302 16 54 34.02 +19 22 54.6          23.7 r EO002568
+     K08K42V  C2008 05 31.43442 16 54 33.68 +19 22 56.0          23.8 r EO002568
+     K08K42V  C2008 06 08.21175 16 53 30.53 +19 26 59.1                 EO002807
+     K08K42V  C2008 06 08.25591 16 53 30.18 +19 27 00.6                 EO002807
+     K08K42V  C2008 06 09.18104 16 53 22.68 +19 27 24.4                 EO002807
+     K08K42V  C2008 06 23.36633 16 51 29.67 +19 31 06.1                 EO002696
+     K08K42V  C2008 06 23.41398 16 51 29.31 +19 31 06.2                 EO002696
+     K08K42V  C2008 06 24.35315 16 51 22.08 +19 31 11.5                 EO002696
+     K08K42V  C2008 06 24.40592 16 51 21.67 +19 31 11.8                 EO002696
+     K08K42V  C2008 07 08.12345 16 49 41.23 +19 30 25.7                 EO002807
+     K08K42V  C2008 07 08.13106 16 49 41.18 +19 30 25.6                 EO002807
+     K08K42V  C2008 07 08.14480 16 49 41.10 +19 30 25.4                 EO002807
+     K08K42V  C2008 07 08.14961 16 49 41.06 +19 30 25.4                 EO002807
+     K08K42V  C2008 07 08.15439 16 49 41.02 +19 30 25.3                 EO002807
+
Index: trunk/mops/oorb/test/K08K42V_ranging.mpc
===================================================================
--- trunk/mops/oorb/test/K08K42V_ranging.mpc	(revision 34646)
+++ trunk/mops/oorb/test/K08K42V_ranging.mpc	(revision 34646)
@@ -0,0 +1,16 @@
+     K08K42V* C2008 05 31.35234 16 54 34.36 +19 22 53.0          23.7 r EO002568
+     K08K42V  C2008 05 31.39302 16 54 34.02 +19 22 54.6          23.7 r EO002568
+     K08K42V  C2008 05 31.43442 16 54 33.68 +19 22 56.0          23.8 r EO002568
+#     K08K42V  C2008 06 08.21175 16 53 30.53 +19 26 59.1                 EO002807
+#     K08K42V  C2008 06 08.25591 16 53 30.18 +19 27 00.6                 EO002807
+#     K08K42V  C2008 06 09.18104 16 53 22.68 +19 27 24.4                 EO002807
+#     K08K42V  C2008 06 23.36633 16 51 29.67 +19 31 06.1                 EO002696
+#     K08K42V  C2008 06 23.41398 16 51 29.31 +19 31 06.2                 EO002696
+#     K08K42V  C2008 06 24.35315 16 51 22.08 +19 31 11.5                 EO002696
+#     K08K42V  C2008 06 24.40592 16 51 21.67 +19 31 11.8                 EO002696
+#     K08K42V  C2008 07 08.12345 16 49 41.23 +19 30 25.7                 EO002807
+#     K08K42V  C2008 07 08.13106 16 49 41.18 +19 30 25.6                 EO002807
+#     K08K42V  C2008 07 08.14480 16 49 41.10 +19 30 25.4                 EO002807
+#     K08K42V  C2008 07 08.14961 16 49 41.06 +19 30 25.4                 EO002807
+#     K08K42V  C2008 07 08.15439 16 49 41.02 +19 30 25.3                 EO002807
+
