diff --git a/include/lookup/.cproject b/include/lookup/.cproject deleted file mode 100644 index fadcdf6..0000000 --- a/include/lookup/.cproject +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/include/lookup/.project b/include/lookup/.project deleted file mode 100644 index 2b9148d..0000000 --- a/include/lookup/.project +++ /dev/null @@ -1,27 +0,0 @@ - - - lookup - - - - - - org.eclipse.cdt.managedbuilder.core.genmakebuilder - clean, - - - - - org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder - full,incremental, - - - - - - org.eclipse.cdt.core.cnature - org.eclipse.cdt.core.ccnature - org.eclipse.cdt.managedbuilder.core.managedBuildNature - org.eclipse.cdt.managedbuilder.core.ScannerConfigNature - - diff --git a/include/lookup/.settings/language.settings.xml b/include/lookup/.settings/language.settings.xml deleted file mode 100644 index 397ef46..0000000 --- a/include/lookup/.settings/language.settings.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/include/lookup/Makefile b/include/lookup/Makefile deleted file mode 100755 index f73db0c..0000000 --- a/include/lookup/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# Load the common Makefile definitions... -include $(GLOBALINC)/setup.mk - -LOOKUPSVC = $(OBJ)/lookup_svc.o $(OBJ)/lookup_xdr.o $(TCPUTIL) - -GENHEADERS = $(RPC)/lookup.h - -LDFLAGS += -lm $(RPCFLAGS) - -# Top level make targets... -all: $(BIN)/lookup $(BIN)/lookupd - -.PHONY: lookup -lookup: $(BIN)/lookup - -$(BIN)/lookup : LDFLAGS += -lpopt -$(BIN)/lookup : $(OBJ)/lookupClient.o $(OBJ)/lookup.o $(SMASH) $(SIMPLE_ASTROMETRY) $(RPC_LOOKUP) - -.PHONY: lookupd -lookupd: $(BIN)/lookupd - -$(BIN)/lookupd : LDFLAGS += -lsystemd $(THREADS) -$(BIN)/lookupd : $(OBJ)/lookupService.o $(OBJ)/lookup.o $(PROCLOCK) $(LOOKUPSVC) $(EPHEM_ASTROMETRY) - - -# Default targets / rules / and dependencies... -include $(GLOBALINC)/recipes.mk - - - - - diff --git a/include/lookup/include/lookup.h b/include/lookup/include/lookup.h deleted file mode 100644 index 0e80cd9..0000000 --- a/include/lookup/include/lookup.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * lookup.h - * - * Created on: Aug 14, 2018 - * Author: Attila Kovacs - */ - -#ifndef INCLUDE_LOOKUP_H_ -#define INCLUDE_LOOKUP_H_ - -#include - -#include "astrometry.h" -#include "rpc/lookup.h" - -#define LOOKUP_HOST "lookup" - -CLIENT *createLookupClient(const char *serverName); -char *setSourceProperties(LQTargetProperties *p, TargetDefinition *source); -char *lookupSource(const char *name, LQTargetProperties *p); -void setUserSource(const char *sourceName, const EquatorialCoordinates *eq, double pmra, double pmdec, TargetDefinition *source); -EquatorialCoordinates *lookupICRS(const char *serverName, const char *name, LQSite *site, double tjd, boolean *isSolarSystem); - - -int isMPCNovasID(short id); - -#endif /* INCLUDE_LOOKUP_H_ */ diff --git a/include/lookup/jpl/README.md b/include/lookup/jpl/README.md deleted file mode 100644 index 81f6581..0000000 --- a/include/lookup/jpl/README.md +++ /dev/null @@ -1,224 +0,0 @@ -# Using JPL Horizons Ephemeris data at the SMA - -Attila Kovacs - -2020 June 17 - - - -## Introduction - -JPL Horizons, and the corresponding CSPICE library, are the most widely used -tools to track the orbits of Solar System objects, such as planets, moons, -asteroids, and comets. - -By default the Haystack tracking system (really, the 'lookupd' server) uses -CSPICE and a set of default SPICE kernels for observing planets, their -moons, and 300 major asteroids. However, it does not stop there. Haysatck -allows to add JPL ephemeris data beyond its standard set of Solar System -objects. This document describes how such data may be generated and used -with the SMA. - - -## Obtaining JPL/Horizons Ephemeris data - - 1. Connect to Horizons via telnet: - - ``` - > telnet horizons.jpl.nasa.gov 6775 - ``` - - Refer to the instructions at: https://ssd.jpl.nasa.gov/?horizons#telnet - - - 2. Search for you object, by name or NAIF id (`DES=`). Your - search may return multiple matches, you must select the correct entry. - - Once your object is identified, you'll see an object summary. You may - want to note the physical radius of the object ("`RAD=`"), and the - solution number (e.g. `sol ref.= JPL#41`). Sometimes the same object - (especially comets) will have multiple JPL records, each with a different - solution number. You should find and proceed with the most up-to-date - one... - - - 3. At the bottom of the object summary you must select '__S__' (for - `[S]PK`). This is the ephemeris data format that will feed into the - CSPICE library that supports Horizons object tracking at the SMA. - - Note the NAIF ID (a.k.a `SPK object ID`) reported back to you on the line - immediately after your selection, e.g. as: - - ``` - Assigned SPK object ID: 02000001 - ``` - - This is the ID that the JPL SPICE library will use internally to refer - to this object. You will need it later... - - - 4. Next you answer a series of questions. Horizons tends to evolve their - service, so the order and exact form of questions may vary over time. - When it asks: - - ``` - SPK file format [Binary, ASCII, 1, ?] : - ``` - - enter __binary__. You may add more than one object into a binary SPK - file (if you want to) or keep separate files for each object. Once done, - you will get a temporary FTP download link shown to you, e.g.: - - ``` - You have 10 minutes to retrieve the following by anonymous FTP: - ``` - - and further below it the link: - - ``` - Full path : ftp://ssd.jpl.nasa.gov/pub/ssd/wld23961.15 - ``` - - - 5. Log into with your SMA account into one of the summit machines (e.g. - obscon), and type: - - ``` - wget - ``` - - with the JPL supplied FTP path (see above) in place of `` to - download the ephemeris data file into your home directory. - - - -## Activating JPL/Horizons Ephemeris data at the SMA - - - 1. Copy/move your binary SPK ephemeris file into an accesible location for - the lookupd server. The recommended location is in: - - ``` - /ephem/ - ``` - - Please name you file in a way that allows easy identification of its - contents. The recommended naming scheme for user-added ephemeris - files is: - - ``` - ...bsp - ``` - - Where `` is the SMA object name (see more on that below), followed - by the start and end dates for the ephemeris data. `.bsp` is the - standard extension for JPL/Horizons binary ephemeris data. - - When you obtain the ephemeris from JPL, do take note of the NAIF id - number of your object (you will need it later) and the physical radius - (not really needed, but may be useful). - - - 2. Register your file with the Haystack 'lookup' server by editing: - - ``` - /etc/lookup/spiceKernels.conf - ``` - - Simply add the full path to your `.bsp` file as a new line in this - file. This will enable loading the ephemeris data in the future. - - - 3. Assign an SMA object name to your source. Haystack names should have only - lowercase letters and numbers and/or hypens and underscores. No spaces - or special characters are allowed. The name you choose is how the - SMA realtime system (and the observing scripts) will refer to your - object. Once you decided on the name, edit: - - ``` - /etc/lookup/solarSystemIDs.dat - ``` - - This file simply contains name/NAIF id associations. So, add a line - with your chosen SMA name (case insensitive) and the NAIF ID number of - your object. This step will associate a object's data in your `.bsp` - file with your chosen name. - - If you don't know what's the NAIF ID of object, you can find it out - using the `brief` tool of cspice (installed in `/usr/local/bin/cspice` - on the lookupd server), e.g.: - - ``` - brief /ephem/phaethon.bsp - ``` - - The result will show a line: - - ``` - Body: 2003200 - ``` - - i.e., Phaeton's NAIF ID is 2003200. - - - 4. (Optional) If you know the approximate size of your object, you may - enter it into - - ``` - /etc/lookup/solarSystemRadii.dat - ``` - - using your chosen source name followed by the radius in km in a new - line. Specifying a raduis is not at all necessary, but if you do, you - may use `lookup` with the `-F` option to get estimated fluxes for your - object at the specified frequency (GHz). - - - 5. Now you can load your ephemeris into the system by typing: - - ``` - > lookup -c - ``` - - on a Haystack operataing console or the lookup server machine. - - - 6. Verify that you ephemeris has been loaded. Try - - ``` - > lookup -s -P -T - ``` - - With your chosen object name in place of ``. You should see a - summary of your object's properties, followed by a its current tracking - information (instantaneous position and movement). - - - -## Cleaning up - - Please do not let your JPL ephemerides linger longer than necessary. Once - you are done using them, please remove (or comment out) any entries you - generated in: - - ``` - /etc/lookup/spiceKernels.conf - ``` - - or in: - - ``` - /etc/lookup/solarSystemRadii.dat - ``` - - and move the ephemeris data to: - - ``` - /ephem/old/ - ``` - - (they are useless outside of their time range anyway...). - - ----------------------------------------------------------------------------- -(C)2020 Attila Kovács diff --git a/include/lookup/lookupd.service b/include/lookup/lookupd.service deleted file mode 100644 index 8396707..0000000 --- a/include/lookup/lookupd.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Haystack catalog and ephemeris source lookup service. -Requires=rpcbind.service -After=network-online.target rpcbind.service - -[Service] -Type=notify -ExecStart=/usr/local/bin/lookupd - -[Install] -WantedBy=multi-user.target diff --git a/include/lookup/mpc/README.md b/include/lookup/mpc/README.md deleted file mode 100644 index 9d65ea0..0000000 --- a/include/lookup/mpc/README.md +++ /dev/null @@ -1,172 +0,0 @@ -# Minor Planet Center Ephemerides - -Attila Kovacs - -2020 June 17 - - - -## Introduction - - This document describes how to generate and use ephemerides from the Minor - Planet Center at . - - - -## Getting ephemerides from the Minor Planet Center - - Start by filling out the form query form for the Minor Planets & Comet - Ephemeris Service site at: - - https://minorplanetcenter.net//iau/MPEph/MPEph.html - - Please follow the following instructions: - - 1. Check _Return ephemerides_ - - 2. Enter object name or designation, e.g. `C/2017 K2` or `CK17020`, in the - search box below. Do __NOT__ enter more than one object per query (we - require single-object ephemeris files). - - 3. Ephemeris Options: - - * Enter _start date_, e.g. `2020 07 01`, and _Number of dates to - output_. This is the total number of data points returned. So if you - want data for 100 days at 1 hour resolution (see below), then you - would enter `2400` here. - - * Select _Ephemeris interval_: __3__ _hours_ is generally recommended. - You may use shorter intervals for near-Earth object, or longer ones - in the outer Solar-system. (Our software will apply cubic spline - interpolation in-between data points, so it is expected to be accurate - even if the ephemeris sampling is relatively sparse -- E.g. for a belt - asteroid 1 day interval is accurate to a few tens of milliarcseconds.) - - * Enter _Observatory code_: __254__ (Haystack, Westford). - - * __IMPORTANT!__: For _Display R.A./Decl. positions_ select: - _heliocentric position/velocity vector_. Below it select _Total motion - and direction_. (The _Display motions as_ selection below will not be - used, and is therefore irrelevant). - - * Do not check the boxes below (i.e. don't suppress output). - - * Finally, for _Format for elements output_, select _none_. - - - 4. Press the __[Get ephemerides/HTML page]__ button. - - 5. Select the output table lines starting from: - - ``` - VECTORS: Heliocentric vectors/AU - ``` - - and below, and copy/paste them to a file. This will be the file that the - SMA will use for tracking your object. The recommended naming scheme is: - - ``` - ...mpc - ``` - - where `` is the simplified name of the object (numbers and - letters only, no symbols or punctuation, underscores and dashes are OK), - followed by the start date in `YYYY-MM-DD` format, followed by the - number of days the ephemeris was generated for. E.g.: - - ``` - C2017K2.2020-07-01.90.mpc - ``` - - -## Activating MPC ephemerides at Haystack - - 1. Copy the ephemeris file you obtained from the Minor Planet Center - Ephemeris Service to the lookup server machone, such as into - (may: - - ``` - /ephem/ - ``` - - 2. Edit the file: - - ``` - /etc/lookup/mpc-ephem.cat - ``` - - Add a new line in the following format - - ``` - - ``` - - Where `` is how you want this object referred to in the Haystack - system (prefer all lowercase, letters and numbers only, no spaces or - special characters, hyphens and underscores OK), and `` - is the fully qualified path name to the ephemeris file on the - Haystack lookup server. E.g. - - ``` - c2017k2 /ephem/C2017K2.2020-07-01.90.mpc - ``` - - 3. (Optional) If you want to enter a radius for this object, you - can add a line to: - - ``` - /etc/lookup/solarSystemRadii.dat - ``` - - With the same name as above (case insensitive), and radius in - km. The only reason to add radius is if you want lookup to be - able to estimate apparent size and approximate brighness. - - - 4. To load the information type: - - ``` - > lookup -c - ``` - - on a summit realtime machine (e.g. `obscon` or `hal9000`). - - 5. Check that your new Minor Planet ephemeris is now - available: - - ``` - > lookup -s c2017k2 -p -T - ``` - - (Use your object name in place of `c2017k2`). - - - -## Cleaning up - - Please do not let your MPC ephemerides linger longer than necessary. Once - you are done using them, please remove (or comment out) any entries you - generated in: - - ``` - /etc/lookup/mpc-ephem.cat - ``` - - or in: - - ``` - /etc/lookup/solarSystemRadii.dat - ``` - - and move the the ephemeris data to: - - ``` - /ephem/old/ - ``` - - (they are useless outside of their time range anyway...). - ----------------------------------------------------------------------------- -(C)2020 Attila Kovács - - diff --git a/include/lookup/mpc/mpc-ephem.cat b/include/lookup/mpc/mpc-ephem.cat deleted file mode 100644 index 2a717d8..0000000 --- a/include/lookup/mpc/mpc-ephem.cat +++ /dev/null @@ -1,28 +0,0 @@ -# SMA Minor Planet Center Ephemeris catalog file -# -# This file should be available on the SMA realtime network as -# -# /global/catalogs/mpc-ephem.cat. -# -# The file lists the Minor Planet center files and associated SMA target -# names, one per line, in the format: -# -# -# -# Names should contain lower-case letters and numbers only. No spaces or -# special characters (but hyphens and underscores are allowed). -# -# Paths should be fully qualified path names to the ephemeris data files -# as accessible by the lookup server (currently on hcn). It is recommended -# that you put MPC ephemeris files into: -# -# /data/operations/ephemeris -# -# and name them with object name, start date and duration days, with .mpc as -# an extension, e.g.: -# -# /data/operations/ephemeris/c2017k2.2020-06-01.90.mpc -# -# Please consult the documentation for how to obtain suitable epehemrides -# from the Minor Planet Center to use with the SMA realtime system. -# diff --git a/include/lookup/src/lookup.c b/include/lookup/src/lookup.c deleted file mode 100644 index 8e38dfb..0000000 --- a/include/lookup/src/lookup.c +++ /dev/null @@ -1,236 +0,0 @@ -/** - * @file - * - * @date Created on: Aug 14, 2018 - * @author Attila Kovacs - * - * @brief A collection of functions to for simplified interfacing with an RPC source lookup service. - */ - -#include -#include -#include - -#include "astrometry.h" -#include "lookup.h" -#include "position.h" -#include "coreutil.h" -#include "rpcutil.h" - -/** - * Creates a TCP/IP connection to the RPC service on a specific lookup server - * - * @param serverName Name or IP address of the lookup server - * @return The RPC client handle, or NULL if the connection could not be established. - */ -CLIENT *createLookupClient(const char *serverName) { - return rpc_connect(serverName, LOOKUPPROG, LOOKUPVERS, LOOKUP_PROTOCOL, 0); -} - -/** - * Translates the source properties obtained from a lookup query to a target definition - * that is used for specified a source for observing. - * - * @param[in] p The source properties as returned by a lookup query - * @param[out] source The translated source properties for observing - * @return NULL if successful, or else an error message. - */ -char *setSourceProperties(LQTargetProperties *p, TargetDefinition *source) { - memset(source, 0, sizeof(TargetDefinition)); - - tokenFrom(p->name, source->name, LQ_SOURCE_NAME_LENGTH); - toLowerCase(source->name); - - if(p->status.errorLevel == LQ_ERROR) return p->status.message; - - source->isSolarSystem = p->isSolarSystem.value; - - if(source->isSolarSystem) { - reportInfo("Selecting solar system source"); - - source->object.type = NOVAS_TYPE_PLANET; - tokenFrom(source->object.name, source->name, SIZE_OF_OBJ_NAME); - source->object.number = p->novasID; - source->NAIF = p->NAIF; - source->diameter = p->diameter; - // Clear the catalog coordinates. These will be set to the apparent values... - resetEquatorial(&source->catalog); - resetEquatorial(&source->properMotion); - - reportDetail("Planet: ID=%d", source->object.number); - } - else { - reportInfo("Selecting catalog source..."); - - source->object.type = NOVAS_TYPE_EXTRASOLAR; - source->catalog.ra = p->catalogCoords.RA / HOURANGLE; - source->catalog.dec = p->catalogCoords.Dec / DEGREE; - source->catalog.epoch = p->catalogCoords.epoch; - source->catalog.cosDEC = cos(p->catalogCoords.Dec); - source->properMotion.ra = p->properMotion.RA; // mas/yr - source->properMotion.dec = p->properMotion.Dec; // mas/yr - source->properMotion.epoch = p->properMotion.epoch; - source->properMotion.cosDEC = source->catalog.cosDEC; - - reportDetail("Catalog: RA=%.3f h DEC=%.2f d (%.1f)", source->catalog.ra, source->catalog.dec, source->catalog.epoch); - reportDetail("PMR: RA=%.3f DEC=%.3f [mas/yr]", source->properMotion.ra, source->properMotion.dec); - } - - if(p->status.errorLevel != LQ_SUCCESS) { - reportDebug("setSourceProperties(): %s", p->status.message); - return p->status.message; - } - return NULL; -} - - -/** - * Populates a target definition for observing with a data from user-specified source. - * - * \param sourceName The name designation for the source - * \param eq Pointer to the equatorial coordinates to set (hours/degrees) - * \param pmra Proper motion in RA (mas/year) - * \param pmdec Proper motion in DEC (mas/year) - * \param source Pointer to the returned source definition structure. - */ -void setUserSource(const char *sourceName, const EquatorialCoordinates *eq, double pmra, double pmdec, TargetDefinition *source) { - reportInfo("Selecting user-specified source."); - - memset(source, 0, sizeof(TargetDefinition)); - - source->isUserSpecified = TRUE; - - tokenFrom(sourceName, source->name, LQ_SOURCE_NAME_LENGTH); // Ignore padding... - source->catalog = *eq; - source->catalog.cosDEC = cos(source->catalog.dec * DEGREE); - source->properMotion.ra = pmra; // mas/yr - source->properMotion.dec = pmdec; // mas/yr - source->properMotion.cosDEC = source->catalog.cosDEC; - source->properMotion.epoch = source->catalog.epoch; - - reportDetail("User: RA=%.2f h DEC=%.1f d (%.1f)", source->catalog.ra, source->catalog.dec, source->catalog.epoch); -} - - -/** - * Checks if a NOVAS ID denotes a Minor Planet Center (MPC) object. - * - * \param NOVAS solar system body ID number. - * - * \return TRUE if it belongs to an MPC object, otherwise FALSE. - */ -int isMPCNovasID(short id) { - return id < 0; -} - - -#if !LOOKUP_SERVICE - -/** - * Uses the lookup server to get catalog or ephemeris source information, returning - * the essential source properties that may be used to query current track information. - * - * @param[i] name The name of the source as defined in the catalog or ephemeris. - * @param[out] p Pointer to the properties structure to fill with the source information - * @return NULL if successful, or else a descriptive error message. - */ -char *lookupSource(const char *name, LQTargetProperties *p) { - LQTargetLookupParms query = {}; - LQTargetProperties *lp; - CLIENT *cl; - - if(!name) return "Input source name is NULL"; - if(!name[0]) return "Input source name is empty"; - if(!p) return "LQTargetProperties argument is NULL"; - - tokenFrom(name, query.sourceName, LQ_SOURCE_NAME_LENGTH); - toLowerCase(query.sourceName); - - cl = createLookupClient(LOOKUP_SERVER); - if(cl == NULL) return "lookupd server RPC connection failed."; - - lp = get_target_properties_1(&query, cl); - - rpc_disconnect(cl); - - if(lp == NULL) return "lookupd replied NULL"; - - if(lp->status.errorLevel >= LQ_ERROR) return lp->status.message[0] ? lp->status.message : "lookup returned an error"; - - *p = *lp; - - return NULL; -} - - -/** - * Uses the lookup server to get ICRS coordinates and velocity information for the requested source. - * - * @param[in] serverName The name or IP address of the lookup server to use. - * @param[in] name The catalog or SPICE name of the source. - * @param[in] site The observer's location on Earth. - * @param[in] tjd Julian Date for which to get coordinates (or 0.0 for now) - * @param[out] isSolarSystem Pointer to boolean in which to return whether source is a Solar-system body. This has - * meaning for the radial velocity component of the returned coordinates, which is - * topocentric for Solar-system objects, and LSR for everything else. - * @return (rad, km/s) the ICRS equatorial coordinates and velovity of the named object, or NULL if the - * source was not found (errno = 0) or if there was an error (errno is set as appropriate). - */ -EquatorialCoordinates *lookupICRS(const char *serverName, const char *name, LQSite *site,double tjd, boolean *isSolarSystem) { - CLIENT *cl; - LQNameLookupParms p = {{'\0'}}; - LQResult *res; - EquatorialCoordinates *eq; - - if(!name) { - errno = EINVAL; - return NULL; - } - if(!name[0]) { - errno = EINVAL; - return NULL; - } - if(!isSolarSystem) { - errno = EINVAL; - return NULL; - } - - *isSolarSystem = FALSE; - - strncpy(p.sourceName, name, sizeof(p.sourceName) - 1); - p.query.tjd = tjd; - - cl = createLookupClient(serverName); - if(!cl) return NULL; - - res = lookup_by_name_1(&p, cl); - rpc_disconnect(cl); - - if(!res) { - reportError("Lookup server returned NULL (timeout?)"); - return NULL; - } - - if(res->status.errorLevel != LQ_SUCCESS) { - if(res->status.errorLevel == LQ_WARNING) reportError("Lookup warning: %s", res->status.message); - reportError("Lookup error: %s", res->status.message); - return NULL; - } - - eq = (EquatorialCoordinates *) calloc(1, sizeof(*eq)); - if(!eq) { - perror("ERROR! lookupICRS(): alloc of equatorial coordinates"); - return NULL; - } - - eq->ra = res->source.catalogCoords.RA; - eq->dec = res->source.catalogCoords.Dec; - eq->cosDEC = cos(eq->dec); - eq->epoch = 2000.0; - eq->radialVelocity = res->source.radialVelocity; // (km/s) - *isSolarSystem = res->source.isSolarSystem.value; - - return eq; -} - -#endif diff --git a/include/lookup/src/lookupClient.c b/include/lookup/src/lookupClient.c deleted file mode 100644 index 4fad5b0..0000000 --- a/include/lookup/src/lookupClient.c +++ /dev/null @@ -1,482 +0,0 @@ -/** - * @file - * - * @date Created on: Nov 13, 2017 - * @author Attila Kovacs - * - * - * A client-side program to lookupd, providing command-line user access to catalog and ephemeris - * source lookup. - */ - - -#include -#include -#include -#include -#include -#include - -#include "astrometry.h" -#include "catalog.h" -#include "lookup.h" -#include "position.h" -#include "timeutil.h" -#include "mpcephem.h" -#include "commands.h" -#include "haystack.h" -#include "rpcutil.h" - -#include - -// Local function prototypes --------------> -static CLIENT *createClient(); -static void setQuerySite(LQSite *site); -static LQResult *lookupByName(const char *name, double dRA, double dDEC, double tjd, boolean isOptical); -static LQResult *lookupByCoordinates(EquatorialCoordinates *eq, double dRA, double dDEC, const EquatorialCoordinates *properMotion, double tjd, boolean isOptical); -static LQTrackSegment *getSiderealTrack(LQEquatorialCoords *eq, const LQEquatorialCoords *properMotion, double radialVelocity); -static LQTrackSegment *getSolarSystemTrack(LQTargetProperties *p, double dRA, double dDEC); -static LQIllumination *getIllumination(const LQTargetProperties *p, double tjd); -static void reloadServerConfig(); - -static void printTimes(const LQSiteResult *result, double latitude); -static void printTargetProperties(const LQTargetProperties *p); -static void printTrackSegment(const LQTrackSegment *t); -static void printSolarSystemProperties(const LQTargetProperties *p); -static void printSiderealProperties(const LQTargetProperties *p); -static void printFluxData(const LQIllumination *illum, double diameterKM, double fGHZ); - -static void hhmm(double time, char *buf); - - -static char *lookupServer = LOOKUP_SERVER; - -int main(int argc, const char *argv[]) { - LQResult *result; - const LQSiteResult *local; - char *timeSpec; - char c; - - boolean hasTime = FALSE; - boolean isOptical = FALSE; - boolean showTimes = FALSE; - boolean showProperties = FALSE; - boolean showTrack = FALSE; - boolean showFlux = FALSE; - - char *sourceName = NULL, *raString = NULL, *decString = NULL; - EquatorialCoordinates equatorial, properMotion; - double dRA = 0.0, dDEC = 0.0; - double fGHZ = 0.0; - int n; - - struct tm date; - double tjd; - - const struct poptOption optionsTable[] = { - {"source", 's', POPT_ARG_STRING, &sourceName, 's', "Source name."}, - {"ra", 'r', POPT_ARG_STRING, &raString, 'r', "RA in hours (decimal or HH:MM:SS.SSS format)"}, - {"dec", 'd', POPT_ARG_STRING, &decString, 'd', "Declination in degrees (decimal or +DD:MM:SS.SSS)"}, - {"epoch", 'e', POPT_ARG_DOUBLE, &equatorial.epoch, 0, "Epoch of input coordinates 1950 or 2000."}, - {"pmra", 'p', POPT_ARG_DOUBLE, &properMotion.ra, 0, "Proper motion in RA (mas/yr)."}, - {"pmdec", 'q', POPT_ARG_DOUBLE, &properMotion.dec, 0, "Proper motion in declination (mas/yr)."}, - {"raoff", 'R', POPT_ARG_DOUBLE, &dRA, 0, "RA offset (arcsec)."}, - {"decoff", 'D', POPT_ARG_DOUBLE, &dDEC, 0, "Dec offset (arcsec)."}, - {"vlsr", 'v', POPT_ARG_DOUBLE, &equatorial.radialVelocity, 0, "LSR velocity (km/s)"}, - {"time", 't', POPT_ARG_STRING, &timeSpec, 't', "Date & time, e.g. \"14 Dec 2010 12:40:15\""}, - {"optical", 'o', POPT_ARG_NONE, &isOptical, 0, "Optical refraction correction (instead of radio)."}, - {"reconfigure", 'c', POPT_ARG_NONE, NULL, 'c', "Reload catalogs and ephemeris data."}, - {"properties", 'P', POPT_ARG_NONE, &showProperties, 0, "Print source properties."}, - {"track", 'T', POPT_ARG_NONE, &showTrack, 0, "Print current track segment information."}, - {"flux", 'F', POPT_ARG_DOUBLE, &fGHZ, 'F', "Print estimated brightness at given frequency (GHz)."}, - {"verbose", 'V', POPT_ARG_NONE, NULL, 'V', "Produce verbose output."}, - {"when", 'w', POPT_ARG_NONE, &showTimes, 0, "Print rise/set/transit times"}, - {"server", 'S', POPT_ARG_STRING, &lookupServer, 0, "Specify an alternative lookup server address."}, - POPT_DEFAULTS, - {"Lookup a source's coordinates and/or properties.\n"} - }; - - poptContext optCon; - - setVerbosity(VERBOSE_WARNINGS); - - // Initializations... - resetEquatorial(&equatorial); - resetEquatorial(&properMotion); - - // Process command line options... - if(argc<2) { - fprintf(stderr, "WARNING! Insufficient number of arguments. At least source-name or RA/Dec are required.\n"); - return SMASH_MISSING_ARGUMENTS; - } - - optCon = poptGetContext("lookup", argc, argv, optionsTable, 0); - - while((c = poptGetNextOpt(optCon)) >= 0) switch(c) { - case 0: break; - case 'h': poptPrintHelp(optCon, stdout, 0); break; - case 't': hasTime = TRUE; break; - case 'F': showFlux = TRUE; break; - case 'V': setVerbosity(VERBOSE_DEBUG); break; - case 'c': - reloadServerConfig(); - if(argc == 2) exit(0); - break; - default: defaultProcessOption(c, optCon); - } - - poptFreeContext(optCon); - - // Check if minimal arguments have been supplied. - if(!sourceName) if(!raString || !decString) { - fprintf(stderr, "WARNING! No source specified. Either source-name or RA/Dec are required.\n"); - return SMASH_MISSING_ARGUMENTS; - } - - if(hasTime && showTrack) { - fprintf(stderr, "WARNING! Cannot use -t (time) together with -T (current track).\n"); - return SMASH_CONFLICTING_ARGUMENTS; - } - - if(raString) { - equatorial.ra = parseHours(raString, &n); - if(n < 0) usage(SMASH_ILLEGAL_ARGUMENT, "Invalid RA format", "Use decimal hours or HH:MM:SS[.sss] format."); - } - - if(decString) { - equatorial.dec = parseDegrees(decString, &n); - if(n < 0) usage(SMASH_ILLEGAL_ARGUMENT, "Invalid declination format", "Use decimal degrees or [-]DDD:MM:SS[.sss] format."); - } - - properMotion.epoch = equatorial.epoch; - - if(hasTime) { - int nt; - if(!parseDateTime(timeSpec, DMY, &date, &nt)) { - reportError("ERROR! Bad time argument: '%s'.\n", timeSpec); - exit(SMASH_ILLEGAL_ARGUMENT); - } - tjd = tjdDate(&date); - } - else tjd = 0; // tjd=0 triggers the server to poll for current time. - - reportDetail("TJD = %.6f", tjd); - - result = (raString && decString) ? lookupByCoordinates(&equatorial, dRA, dDEC, &properMotion, tjd, isOptical) : lookupByName(sourceName, dRA, dDEC, tjd, isOptical); - - if(!result) { - fprintf(stderr, "ERROR! Got NULL (timeout?) from lookup server.\n"); - return SMASH_CONNECTION_ERROR; - } - - if(result->status.errorLevel == LQ_ERROR) { - if(isShowingErrors()) fprintf(stderr, "ERROR! %s\n", result->status.message); - return SMASH_BAD_VALUE; - } - - if(result->status.errorLevel == LQ_WARNING) { - if(isShowingWarnings()) fprintf(stderr, "WARNING! %s\n", result->status.message); - } - - if(showProperties) printTargetProperties(& result->source); - - if(showFlux) if(result->source.isSolarSystem.value) printFluxData(getIllumination(&result->source, tjd), result->source.diameter, fGHZ); - - if(showTrack) printTrackSegment( - result->source.isSolarSystem.value ? - getSolarSystemTrack(&result->source, dRA, dDEC) : - getSiderealTrack(&result->source.catalogCoords, &result->source.properMotion, result->source.radialVelocity) - ); - - local = &result->local; - - printf("AZ %f EL %f SunDist %f", local->horizontal.Az/DEGREE, local->horizontal.El/DEGREE, local->sunDistance/DEGREE); - if(result->source.isSatellite.value) if(local->planetDistance != 0.0) printf(" PlanetSep %f \"", local->planetDistance/ARCSEC); - printf("\n"); - - if(showTimes) printTimes(local, HAYSTACK_LATITUDE_DEG * DEGREE); - - return 0; -} - -static CLIENT *createClient() { - return createLookupClient(lookupServer); -} - -/** - * Print rise/transit/set times for the given query result in hh:mm format. - * - * \param result Pointer to the successful lookup query result. - * \param latitude (radian) The observe's latitude - * - */ -static void printTimes(const LQSiteResult *result, double latitude) { - double ha; - char timeString[10]; - - ha = acos((sin(20.0 * DEGREE) - sin(result->apparent.Dec) * sin(latitude)) / (cos(result->apparent.Dec) * cos(latitude))) / SECONDANGLE; - - hhmm(result->transitUTC - ha, timeString); - printf("rising at %s, ", timeString); - - hhmm(result->transitUTC, timeString); - printf("transiting at %s, ", timeString); - - hhmm(result->transitUTC + ha, timeString); - printf("setting at %s UTC\n", timeString); -} - - -static void setQuerySite(LQSite *site) { - site->longitude = HAYSTACK_LONGITUDE_DEG * DEGREE; - site->latitude = HAYSTACK_LATITUDE_DEG * DEGREE; - site->altitude = HAYSTACK_HEIGHT; -} - -static LQResult *lookupByName(const char *name, double dRA, double dDEC, double tjd, boolean isOptical) { - LQNameLookupParms parms; - LQResult *result; - CLIENT *cl; - - reportInfo("Lookup '%s' (offset %.1f, %.1f arcsec)", name, dRA, dDEC); - - tokenFrom(name, parms.sourceName, LQ_SOURCE_NAME_LENGTH); - parms.dRA = dRA * ARCSEC; - parms.dDEC = dDEC * ARCSEC; - parms.query.tjd = tjd; - parms.query.isOptical.value = isOptical; - setQuerySite(&parms.query.site); - - result = lookup_by_name_1(&parms, cl = createClient()); - rpc_disconnect(cl); - - if(!result) clnt_perror(cl, "lookup_by_name()"); - - return result; -} - - -static LQResult *lookupByCoordinates(EquatorialCoordinates *eq, double dRA, double dDEC, const EquatorialCoordinates *properMotion, double tjd, boolean isOptical) { - LQCoordinateLookupParms parms; - LQResult *result; - CLIENT *cl; - - reportInfo("Lookup: RA=%.3f h, DEC=%.3f deg (%.1f), offset: %.1f %.1f arcsec", eq->ra, eq->dec, eq->epoch, dRA, dDEC); - - parms.coords.Dec = eq->dec * DEGREE + dDEC * ARCSEC; - parms.coords.RA = eq->ra * HOURANGLE + dRA * ARCSEC * cos(parms.coords.Dec); - parms.coords.epoch = eq->epoch; - - if(properMotion != NULL) { - parms.properMotion.RA = properMotion->ra; // mas/yr - parms.properMotion.Dec = properMotion->dec; // mas/yr - parms.properMotion.epoch = properMotion->epoch; - } - else { - parms.properMotion.RA = parms.properMotion.Dec = 0.0; - parms.properMotion.epoch = eq->epoch; - } - - parms.query.tjd = tjd; - parms.query.isOptical.value = isOptical; - setQuerySite(&parms.query.site); - - result = lookup_by_coords_1(&parms, cl = createClient()); - rpc_disconnect(cl); - - result->source.radialVelocity = eq->radialVelocity; - - return result; -} - -static LQTrackSegment *getSiderealTrack(LQEquatorialCoords *eq, const LQEquatorialCoords *properMotion, double radialVelocity) { - LQSiderealTrackParms p; - LQTrackSegment *t; - - CLIENT *cl; - - reportInfo("Track for: RA=%.3f h, DEC=%.3f deg (%.1f)", eq->RA / HOURANGLE, eq->Dec / DEGREE, eq->epoch); - - p.equatorial = *eq; - - if(properMotion != NULL) p.properMotion = *properMotion; - else { - p.properMotion.RA = p.properMotion.Dec = 0.0; - p.properMotion.epoch = eq->epoch; - } - - p.radialVelocity = radialVelocity; - - t = get_sidereal_track_1(&p, cl = createClient()); - rpc_disconnect(cl); - - if(t == NULL) reportError("lookupd returned NULL"); - - return t; -} - - -static LQTrackSegment *getSolarSystemTrack(LQTargetProperties *source, double dRA, double dDEC) { - LQTrackSegment *t; - LQSolarSystemTrackParms p; - CLIENT *cl; - - if(source->NAIF) reportInfo("Track for NAIF ID %d", source->NAIF); - else if(isMPCNovasID(source->novasID)) reportInfo("Track for MPC object '%s'\n", source->name); - - p.id.code = source->novasID; - p.id.isNAIF.value = LQ_FALSE; - setQuerySite(&p.site); - - t = get_solarsystem_track_1(&p, cl = createClient()); - rpc_disconnect(cl); - - if(t == NULL) reportError("lookupd returned NULL"); - else { - t->apparent.Dec += dDEC * ARCSEC; - t->apparent.RA += dRA * ARCSEC * cos(t->apparent.Dec); - } - - return t; -} - - -static LQIllumination *getIllumination(const LQTargetProperties *p, double tjd) { - LQIlluminationQuery q; - LQIllumination *i; - CLIENT *cl; - - q.id.code = p->novasID; - q.id.isNAIF.value = LQ_FALSE; - q.tjd = tjd; - - i = get_solar_illumination_1(&q, cl = createClient()); - if(i == NULL) reportError("lookupd returned NULL"); - - rpc_disconnect(cl); - - return i; -} - -static void reloadServerConfig() { - const LQStatus *status; - CLIENT *cl; - status = lookup_refresh_1(NULL, cl = createClient()); - rpc_disconnect(cl); - - if(status->errorLevel == LQ_ERROR) reportWarning(status->message); -} - - - -/** - * Formats time in hh:mm format. - * - * \param time (sec) The time of the day. - * \param buf Pointer to the string buffer that will hold the result. It should be appropriately sized. - * - */ -static void hhmm(double time, char *buf) { - int h, m; - - time = remainder(time, DAY); - if(time < 0.0) time += DAY; - - h = (int) (time / HOUR); - time -= h * HOUR; - - m = (int) (time / MINUTE); - - sprintf(buf, "%02d:%02d", h, m); -} - - -static void printTargetProperties(const LQTargetProperties *p) { - if(p->status.errorLevel == LQ_ERROR) reportError(p->status.message); - else if(p->status.errorLevel == LQ_WARNING) reportWarning(p->status.message); - else if(p->isSolarSystem.value) printSolarSystemProperties(p); - else printSiderealProperties(p); -} - -static void printSolarSystemProperties(const LQTargetProperties *p) { - printf(" Name: %s\n", p->name); - if(!p->NAIF && p->novasID) { - printf(" Origin: Minor Planet Center\n"); - } - else { - static const char *planets[] = { "", "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Neptune", "Pluto" }; - printf(" NAIF code: %ld\n", p->NAIF); - printf(" Orbits: %s\n", (p->isSatellite.value ? planets[p->NAIF/100] : "Sun")); - } - printf(" Temporary ref#: %d\n", p->novasID); - if(p->diameter > 0.0) printf(" Diameter: %.1f km\n", p->diameter); - printf("\n"); -} - - -static void printSiderealProperties(const LQTargetProperties *p) { - char RA[40], DEC[40]; - - formatHMSAngle(p->catalogCoords.RA, RA); - formatDMS(p->catalogCoords.Dec, DEC); - - printf(" Name: %s\n", p->name); - printf(" Type: %s\n", (p->isOptical.value ? "optical" : "radio")); - printf(" Catalog coords: %s %s (%.1f)\n", RA, DEC, p->catalogCoords.epoch); - printf(" Proper motion: %.1f, %.1f mas/yr\n", p->properMotion.RA, p->properMotion.Dec); - printf(" vRadial: %.3f km/s\n", p->radialVelocity); - - if(p->isOptical.value) { - printf(" Spectral type: %s\n", p->spectralType); - printf(" Magnitude: %.1f\n", p->magnitude); - printf(" Proper motion: %.1f, %.1f mas/yr\n", p->properMotion.RA, p->properMotion.Dec); - } - printf("\n"); -} - -static void printTrackSegment(const LQTrackSegment *t) { - char RA[40], DEC[40]; - - if(t->status.errorLevel == LQ_ERROR) reportError(t->status.message); - else if(t->status.errorLevel == LQ_WARNING) reportWarning(t->status.message); - else { - formatHMSAngle(t->apparent.RA, RA); - formatDMS(t->apparent.Dec, DEC); - - printf("Current Tracking Parameters\n"); - printf(" MJD: %0.6f\n", t->tjd - JD_MJD0); - printf(" Apparent: %s %s (%.1f)\n", RA, DEC, t->apparent.epoch); - printf(" Rate: %.3f, %.3f arcsec/hour\n", t->apparentRate.RA * HOUR / ARCSEC, t->apparentRate.Dec * HOUR / ARCSEC); - printf(" vRadial: %.3f km/s\n", t->radialVelocity); - printf(" aRadial: %.3g km/s^2\n", t->radialVelocityRate); - - if(t->distance > 0.0) printf(" distance: %.3f AU\n", t->distance); - printf("\n"); - } -} - - -static void printFluxData(const LQIllumination *illum, double diameterKM, double fGHZ) { - double T1AU = 320.0; - double k = 1.38e-23; - double h = 6.64e-34; - double c = 299792458.0; - double f = fGHZ * GHZ; - double T = T1AU / sqrt(illum->sunDistance); - double B = 2.0 * h * f * f * f / (c*c) / expm1(h*f / (k*T)); - double dA = 1e3 * diameterKM / (illum->distance * AU); - double dO = illum->fraction * 0.25 * PI * dA * dA; - - if(illum->status.errorLevel == LQ_ERROR) reportError(illum->status.message); - else if(illum->status.errorLevel == LQ_WARNING) reportWarning(illum->status.message); - else { - if(diameterKM > 0.0) printf(" Angular size: %.3f arcsec\n", dA / ARCSEC); - printf(" Illum. fraction: %.1f %%\n", 100.0 * illum->fraction); - printf(" Distance: %.3f AU\n", illum->distance); - printf(" Sun distance: %.3f AU\n", illum->sunDistance); - printf(" Estimated temp: %.1f K\n", T); - if(diameterKM > 0.0) printf(" S(%dGHz) %.3f Jy\n", (int) fGHZ, 1e26 * B * dO); - printf("\n"); - } -} - diff --git a/include/lookup/src/lookupService.c b/include/lookup/src/lookupService.c deleted file mode 100644 index 0778d92..0000000 --- a/include/lookup/src/lookupService.c +++ /dev/null @@ -1,646 +0,0 @@ -/** - * @file - * - * @date Created on: Nov 13, 2017 - * @author Attila Kovacs - * - * @version 2.2-Haytack - * - * This program implements a source position lookup service via RPC. - * - * The server processes HUP signals to reload configuration (catalogs and ephemeris files) - * - */ - -#include -#include -#include -#include -#include -#include -#include - - -#include "astrometry.h" -#include "catalog.h" -#include "ephemeris.h" -#include "lookup.h" -#include "position.h" -#include "timeutil.h" -#include "haystack.h" -#include "tcputil.h" -#include "rpcutil.h" -#include "proclock.h" - - -#ifndef SIG_PF -#define SIG_PF void(*)(int) -#endif - -#define RPC_MAX_QUEUE 100 -#define LOOKUPD_LOCK_ID "lookupd" - -#define DEFAULT_TEMPERATURE_C HAYSTACK_AVERAGE_TEMPERATURE -#define DEFAULT_PRESSURE_MBAR HAYSTACK_AVERAGE_PRESSURE -#define DEFAULT_HUMIDITY HAYSTACK_AVERAGE_HUMIDITY - -#define EVOLVE_TIME 60.0 ///< (s) Time step around current for rate calculations using cord. - - -static void initLookup(); -static LQTargetProperties *lookupName(const char *name); -static LQTargetProperties *lookupSolarSystem(const char *name); -static LQTargetProperties *lookupSidereal(const char *name, boolean isOptical); -static void printLQQuery(LQParms *query); -static void reportLQStatus(const LQStatus *status); -static void generateLQResult(LQParms *query, LQTargetProperties *p, double dRA, double dDEC, LQResult *result); -static LQTrackSegment *getSourceTrack(TargetDefinition *source, const LQSite *lookupSite); -static void setLQStatus(int errorLevel, const char *message, LQStatus *status); -static void updateLQStatus(int errorLevel, const char *message, LQStatus *status); -static double objectDistance(const EquatorialCoordinates *apparent, short novasID, on_surface *site, double tjd); -static void setOption(char *value); -static void initSignalHandler(); -static void processSignal(int signum); - -static boolean ignoreLock; - -static void initLookup() { - setVerbosity(VERBOSE_WARNINGS); - - setSpiceExitOnError(FALSE); // Handle SPICE errors gracefully... - //if(!isShowingDebug()) setSpiceErrorVerbosity("EXPLAIN"); // Print only short errors (without trace or explanation), unless running with 'debug' - - lookup_refresh_1_svc(NULL, NULL); - - initSignalHandler(); -} - -LQResult *lookup_by_name_1_svc(LQNameLookupParms *lookup, struct svc_req *req) { - static LQResult result; - LQTargetProperties *p; - - reportInfo("Looking up '%s' (offset %.1, %.1f arcsec)", lookup->sourceName, lookup->dRA / ARCSEC, lookup->dDEC / ARCSEC); - if(isShowingDetails()) printLQQuery(&lookup->query); - - memset(&result, 0, sizeof(LQResult)); - - p = lookupName(lookup->sourceName); - - if(p->status.errorLevel != LQ_ERROR) generateLQResult(&lookup->query, p, lookup->dRA, lookup->dDEC, &result); - else result.status = p->status; - - reportLQStatus(&result.status); - - return &result; -} - -// local implemetation for lookup.o -LQResult * lookup_by_name_1(LQNameLookupParms *p, CLIENT *cl) { - return lookup_by_name_1_svc(p, NULL); -} - - -static LQTargetProperties *lookupName(const char *name) { - LQTargetProperties *p; - - p = lookupSolarSystem(name); // solar system lookup... - if(p->status.errorLevel == LQ_ERROR) p = lookupSidereal(name, FALSE); // radio catalog lookup... - if(p->status.errorLevel == LQ_ERROR) p = lookupSidereal(name, TRUE); // optical catalog lookup... - - return p; -} - -static LQTargetProperties *lookupSolarSystem(const char *name) { - static LQTargetProperties p; - - reportDetail("Trying solar system..."); - - memset(&p, 0, sizeof(LQTargetProperties)); - - tokenFrom(name, p.name, LQ_SOURCE_NAME_LENGTH); - - p.novasID = mpcGetNovasID(name); - if(p.novasID < 0) { - // Minor Planet Center object... - p.isSolarSystem.value = TRUE; - p.NAIF = 0; - } - else { - // Try as SPICE object.... - spiceErrorReset(); // Clear prior SPICE errors... - - p.NAIF = getPlanetID(name); - if(p.NAIF <= 0) { - p.isSolarSystem.value = FALSE; - p.novasID = -1; - setLQStatus(LQ_ERROR, "Source not found", &p.status); - return &p; - } - - p.isSolarSystem.value = TRUE; - p.novasID = NAIFtoNOVAS(p.NAIF); - } - - - p.diameter = getPlanetDiameter(p.name) / KM; - - p.isSatellite.value = p.NAIF > 100 && p.NAIF < 1000 && (p.NAIF % 100) != 99; - p.isComplete.value = p.novasID > 0; - - setLQStatus(LQ_SUCCESS, NULL, &p.status); - - reportDetail("Source found!\n"); - - return &p; -} - -static LQTargetProperties *lookupSidereal(const char *name, boolean isOptical) { - static LQTargetProperties p; - CatalogEntry entry; - boolean isFound; - - reportDetail("Trying %s catalog...", isOptical ? "optical" : "radio"); - - memset(&p, 0, sizeof(LQTargetProperties)); - - tokenFrom(name, p.name, LQ_SOURCE_NAME_LENGTH); - - if(isOptical) isFound = lookupOpticalCatalog(name, &entry); - else isFound = lookupRadioCatalog(name, &entry); - - if(!isFound) { - setLQStatus(LQ_ERROR, "Source not found.", &p.status); - return &p; - } - - p.isSolarSystem.value = FALSE; - p.isOptical.value = isOptical; - - p.catalogCoords.RA = (entry.rah + entry.ram / 60. + entry.ras / 3600.) * HOURANGLE; - p.catalogCoords.Dec = (fabs(entry.decd) + entry.decm / 60. + entry.decs / 3600.) * DEGREE; - if(entry.decsign == '-') p.catalogCoords.Dec *= -1; - p.catalogCoords.epoch = entry.epoch; - - p.radialVelocity = entry.vel; - - p.magnitude = entry.magnitude; - - p.properMotion.RA = entry.pmr; // mas/year - p.properMotion.Dec = entry.pmd; // mas/year - p.properMotion.epoch = p.catalogCoords.epoch; - - memcpy(p.spectralType, entry.spectralType, LQ_SPECTRAL_TYPE_LENGTH); - - p.isComplete.value = entry.isComplete; - - reportDetail("Source found!\n"); - - return &p; -} - -LQResult *lookup_by_coords_1_svc(LQCoordinateLookupParms *lookup, struct svc_req *req) { - static LQResult result; - LQTargetProperties p; - LQEquatorialCoords *eq = &p.catalogCoords; - - memset(&p, 0, sizeof(LQTargetProperties)); - - strcpy(p.name, "user"); - p.catalogCoords = lookup->coords; - p.properMotion = lookup->properMotion; - - reportInfo("Looking up RA=%.3f h, DEC=%.3f deg (%.1f)", eq->RA / HOURANGLE, eq->Dec / DEGREE, eq->epoch); - if(isShowingDetails()) printLQQuery(&lookup->query); - - generateLQResult(&lookup->query, &p, 0.0, 0.0, &result); - reportLQStatus(&result.status); - - return &result; -} - -LQTargetProperties * get_target_properties_1_svc(LQTargetLookupParms *lookup, struct svc_req *req) { - static LQTargetProperties *p; - - p = lookupName(lookup->sourceName); - - reportLQStatus(&p->status); - - return p; -} - -// Local implementation for lookup.o -LQTargetProperties * get_target_properties_1(LQTargetLookupParms *p, CLIENT *cl) { - return get_target_properties_1_svc(p, NULL); -} - - -LQTrackSegment *get_sidereal_track_1_svc(LQSiderealTrackParms *p, struct svc_req *req) { - TargetDefinition source; - - memset(&source, 0, sizeof(TargetDefinition)); - - source.isSolarSystem = FALSE; - source.catalog.ra = p->equatorial.RA / HOURANGLE; - source.catalog.dec = p->equatorial.Dec / DEGREE; - source.catalog.epoch = p->equatorial.epoch; - source.catalog.radialVelocity = p->radialVelocity; - - source.properMotion.ra = p->properMotion.RA; - source.properMotion.dec = p->properMotion.Dec; - source.properMotion.epoch = p->properMotion.epoch; - - return getSourceTrack(&source, NULL); -} - - - -LQTrackSegment *get_solarsystem_track_1_svc(LQSolarSystemTrackParms *p, struct svc_req *req) { - TargetDefinition source; - - memset(&source, 0, sizeof(TargetDefinition)); - - source.isSolarSystem = TRUE; - source.object.number = p->id.isNAIF.value ? NAIFtoNOVAS(p->id.code) : (short) p->id.code; - - return getSourceTrack(&source, &p->site); -} - - - -static LQTrackSegment *getSourceTrack(TargetDefinition *source, const LQSite *lookupSite) { - static LQTrackSegment track; - - on_surface site; - EquatorialCoordinates apparent, next, prev; - - if(source->isSolarSystem) reportInfo("Getting track segment for NAIF code %ld", NOVAStoNAIF(source->object.number)); - else { - reportInfo("Getting track segment for: RA=%.3f DEC=%.3f (%.1f) vRadial=%.1f km/s", - source->catalog.ra, source->catalog.dec, source->catalog.epoch, source->catalog.radialVelocity); - } - - memset(&track, 0, sizeof(LQTrackSegment)); - - track.tjd = tjdNow(); - reportDebug("TJD=%f", track.tjd); - - if(lookupSite == NULL) { - site.longitude = HAYSTACK_LONGITUDE_DEG; - site.latitude = HAYSTACK_LATITUDE_DEG; - site.height = HAYSTACK_HEIGHT; - } - else { - site.longitude = lookupSite->longitude / DEGREE; - site.latitude = lookupSite->latitude / DEGREE; - site.height = lookupSite->altitude; - } - - spiceErrorReset(); // Clear prior SPICE errors... - - track.distance = getApparentSource(source, &site, track.tjd, &apparent); - if(track.distance > 0.0) reportDetail("Distance: %.2f AU", track.distance); - - // Check that we have ephemeris data for this source... - if(source->isSolarSystem) if (hadSpiceError()) { - setLQStatus(LQ_ERROR, "SPICE error!", &track.status); - reportLQStatus(&track.status); - return &track; - } - - track.apparent.RA = apparent.ra; - track.apparent.Dec = apparent.dec; - track.apparent.epoch = apparent.epoch; - track.radialVelocity = apparent.radialVelocity; - - reportDetail("Apparent: RA=%.3f DEC=%.3f (%.1f)", apparent.ra / HOURANGLE, apparent.dec / DEGREE, apparent.epoch); - reportDetail("Radial velocity: %.1f km/s", apparent.radialVelocity); - - getApparentSource(source, &site, track.tjd - EVOLVE_TIME / DAY, &prev); - getApparentSource(source, &site, track.tjd + EVOLVE_TIME / DAY, &next); - - // Check that we have ephemeris data for this source... - if (source->isSolarSystem) if (hadSpiceError()) { - setLQStatus(LQ_ERROR, "SPICE error : could not calculate apparent coordinates.", &track.status); - reportLQStatus(&track.status); - return &track; - } - - track.apparentRate.RA = (next.ra - prev.ra) / (2.0 * EVOLVE_TIME); - track.apparentRate.Dec = (next.dec - prev.dec) / (2.0 * EVOLVE_TIME); - track.radialVelocityRate = (next.radialVelocity - apparent.radialVelocity) / (2.0 * EVOLVE_TIME); - - reportDetail("Apparent rates: %.3f, %.3f arcsec/s", track.apparentRate.RA / ARCSEC, track.apparentRate.Dec / ARCSEC); - reportDetail("Acceleration: %.2g km/s^2", track.radialVelocityRate); - - reportLQStatus(&track.status); - - return &track; -} - -LQIllumination *get_solar_illumination_1_svc(LQIlluminationQuery *q, struct svc_req *req) { - static LQIllumination illumination; - double pos[3], ePos[3], v[3]; - double dSun, dObs, dEarth; - - short id; - - if(isMPCNovasID(q->id.code)) id = (short) q->id.code; // MPC ephemeris - else id = q->id.isNAIF.value ? NAIFtoNOVAS(q->id.code) : (short) q->id.code; - - if(q->tjd == 0.0) q->tjd = tjdNow(); - - spiceErrorReset(); // Clear prior SPICE errors... - - // Body's distance from Sun... - solarsystem(q->tjd, id, 1, pos, v); - if(hadSpiceError()) { - setLQStatus(LQ_ERROR, "SPICE Error : Could not calculate body position w.r.t. the Sun.", &illumination.status); - reportLQStatus(&illumination.status); - return & illumination; - } - illumination.sunDistance = dSun = sqrt(pos[0]*pos[0] + pos[1] * pos[1] + pos[2] * pos[2]); - - // Earth's distance from Sun... - solarsystem(q->tjd, 3, 1, ePos, v); - if(hadSpiceError()) { - setLQStatus(LQ_ERROR, "SPICE Error : Could not calculate Earth position w.r.t. the Sun.", &illumination.status); - reportLQStatus(&illumination.status); - return & illumination; - } - dEarth = sqrt(ePos[0]*ePos[0] + ePos[1] * ePos[1] + ePos[2] * ePos[2]); - - // Get distance to Earth.... - pos[0] -= ePos[0]; - pos[1] -= ePos[1]; - pos[2] -= ePos[2]; - - illumination.distance = dObs = sqrt(pos[0]*pos[0] + pos[1] * pos[1] + pos[2] * pos[2]); - illumination.fraction = 0.5 + 0.5 * (dObs * dObs + dSun * dSun - dEarth * dEarth) / (2.0 * dSun * dObs); - - setLQStatus(LQ_SUCCESS, NULL, &illumination.status); - reportLQStatus(&illumination.status); - - return &illumination; -} - - -LQStatus *lookup_refresh_1_svc(void *nil, struct svc_req *req) { - static LQStatus status; - int n; - const char *error; - - sd_notify(0, "RELOADING=1"); - - setLQStatus(LQ_SUCCESS, NULL, &status); - - reportInfo("Reloading radio catalog."); - n = reloadCatalog(DEFAULT_RADIO_CATALOG_FILE, TRUE); - if(n < 0) updateLQStatus(LQ_WARNING, "Could not open radio catalog.", &status); - - reportInfo("Reloading optical catalog."); - n = reloadCatalog(DEFAULT_OPTICAL_CATALOG_FILE, FALSE); - if(n < 0) updateLQStatus(LQ_WARNING, "Could not open optical catalog.", &status); - - reportInfo("Reloading SPICE kernels."); - error = reloadSpiceKernels(SPICE_KERNELS_LIST); - if(error != NULL) reportWarning(error); - updateLQStatus(error == NULL ? LQ_SUCCESS : LQ_ERROR, error, &status); - - reportInfo("Reloading MPC catalog."); - n = mpcSetCatalog(DEFAULT_MPC_CATALOG_FILE); - if(n != MPC_SUCCESS) updateLQStatus(LQ_ERROR, "Could not load MPC catalog file.", &status); - - reportInfo("Reloading Leap second data."); - error = readLeap(DEFAULT_LEAP_FILE); - if(error != NULL) reportWarning(error); - updateLQStatus(error == NULL ? LQ_SUCCESS : LQ_ERROR, error, &status); - - reportInfo("Reloading polar wobble parameters."); - error = readPolarWobbleParms(DEFAULT_WOBBLE_PARMS_FILE); - if(error != NULL) reportWarning(error); - updateLQStatus(error == NULL ? LQ_SUCCESS : LQ_ERROR, error, &status); - - reportLQStatus(&status); - - sd_notify(0, "READY=1"); - - return &status; -} - -static void printLQQuery(LQParms *query) { - reportDetail("Site: LON=%.3f deg, LAT=%.3f deg, alt=%.1f m", query->site.longitude/DEGREE, query->site.latitude/DEGREE, query->site.altitude); - reportDetail("TJD = %f", query->tjd); - reportDetail("optical: %s", query->isOptical.value ? "TRUE" : "FALSE"); -} - -static void reportLQStatus(const LQStatus *status) { - if(status->errorLevel == LQ_SUCCESS) { - if(strlen(status->message) > 0) reportInfo(status->message); - } - else if(status->errorLevel == LQ_WARNING) reportWarning(status->message); - else if(status->errorLevel == LQ_ERROR) reportError(status->message); -} - - -static void generateLQResult(LQParms *query, LQTargetProperties *p, double dRA, double dDEC, LQResult *result) { - EquatorialCoordinates apparent; - HorizontalCoordinates ho; - TargetDefinition source; - LQSiteResult *local; - on_surface site; - const char *error; - - spiceErrorReset(); // Reset the SPICE error status... - - reportDetail(""); - - // Clear the result - memset(result, 0, sizeof(LQResult)); - - // For sidereal objects add offset up front to the catalog coordinates... - if(!p->isSolarSystem.value) { - p->catalogCoords.Dec += dDEC; - p->catalogCoords.RA += dRA * cos(p->catalogCoords.Dec); - } - - result->source = *p; - result->status = p->status; - - error = setSourceProperties(p, &source); - if(error != NULL) { - updateLQStatus(LQ_ERROR, error, &result->status); - return; - } - - if(query->tjd == 0.0) query->tjd = tjdNow(); - - reportDetail("TJD: %f\n", query->tjd); - - // Calculate apparent coordinates... - site.longitude = query->site.longitude / DEGREE; - site.latitude = query->site.latitude / DEGREE; - site.height = query->site.altitude; - - reportDetail("Site: LON=%.3f deg, LAT=%.3f deg, alt=%.1f m", site.longitude, site.latitude, site.height); - - local = &result->local; - local->tjd = query->tjd; - local->distance = getApparentSource(&source, &site, query->tjd, &apparent); - - if(hadSpiceError()) { - updateLQStatus(LQ_ERROR, "Apparent lookup failed (CSPICE).", &result->status); - spiceErrorReset(); - } - else if(isnan(apparent.ra) || isnan(apparent.dec)) updateLQStatus(LQ_ERROR, "NOVAS NaN error -- Ouch!!!.", &result->status); - - if(p->isSolarSystem.value) { - // For solar-system objects add offset to the apparent coordinates... - apparent.dec += dDEC; - apparent.cosDEC = cos(apparent.dec); - apparent.ra += dRA * apparent.cosDEC; - - // Calculate J2000 'catalog' coordinates - source.catalog = apparent; - precess(&source.catalog, 2000.0); - } - - reportDetail("Apparent: RA=%.3f h, DEC=%.3f deg (%.1f)", apparent.ra/HOURANGLE, apparent.dec/DEGREE, apparent.epoch); - - local->apparent.RA = apparent.ra; - local->apparent.Dec = apparent.dec; - local->apparent.epoch = apparent.epoch; - - local->radialVelocity = apparent.radialVelocity; - - // Calculate Sun and planet distances... - local->sunDistance = objectDistance(&apparent, NOVAS_SUN, &site, query->tjd); - if(hadSpiceError()) { - spiceErrorReset(); - updateLQStatus(LQ_WARNING, "Sun position lookup failed.", &result->status); - local->sunDistance = 0.0; - } - - if(p->isSatellite.value) if(p->NAIF != NAIF_MOON) { - local->planetDistance = objectDistance(&apparent, p->NAIF / 100, &site, query->tjd); - if(hadSpiceError()) { - spiceErrorReset(); - updateLQStatus(LQ_WARNING, "Planet separation lookup failed.", &result->status); - local->planetDistance = 0.0; - } - } - - local->lstAngle = getLSTAngle(site.longitude, query->tjd - JD_MJD0, getUT1toTT()); - reportDetail("LST =%.3f h", local->lstAngle/HOURANGLE); - - equatorialToHorizontal(&apparent, local->lstAngle, site.latitude * DEGREE, &ho); - local->horizontal.Az = ho.az; - local->horizontal.El = ho.el; - reportDetail("Horizontal: AZ=%.3f deg, EL=%.3f deg", ho.az/DEGREE, ho.el/DEGREE); - - refractionCorrect(&ho.el, query->isOptical.value, DEFAULT_TEMPERATURE_C, DEFAULT_PRESSURE_MBAR, DEFAULT_HUMIDITY, &local->refraction); - - local->transitUTC = (apparent.ra - local->lstAngle) / SECONDANGLE + tt2utc(fmod(query->tjd + 0.5, 1.0) * DAY); - reportDetail("Transit: UTC=%.3f h", local->transitUTC/HOUR); -} - -static void setLQStatus(int errorLevel, const char *message, LQStatus *status) { - reportDetail("Status %d: %s", errorLevel, message == NULL ? "null" : message); - status->errorLevel = errorLevel; - if(message == NULL) status->message[0] = '\0'; - else { - strncpy(status->message, message, LQ_MESSAGE_LENGTH - 1); - status->message[LQ_MESSAGE_LENGTH - 1] = '\0'; - } - spiceErrorReset(); - return; -} - -static void updateLQStatus(int errorLevel, const char *message, LQStatus *status) { - if(status->errorLevel >= errorLevel) { - spiceErrorReset(); - return; - } - else setLQStatus(errorLevel, message, status); -} - - -static double objectDistance(const EquatorialCoordinates *apparent, short novasID, on_surface *site, double tjd) { - object planet = {0, novasID, "reference"}; - EquatorialCoordinates apparentPlanet; - - getApparentPlanet(&planet, site, tjd, &apparentPlanet); - return sphericalDistance(apparent->ra, apparent->dec, apparentPlanet.ra, apparentPlanet.dec); -} - - -static void setOption(char *value) { - toLowerCase(value); - - if(!strcmp(value, "silent")) setVerbosity(SILENT); - else if(!strcmp(value, "errors")) setVerbosity(VERBOSE_ERRORS); - else if(!strcmp(value, "warnings")) setVerbosity(VERBOSE_WARNINGS); - else if(!strcmp(value, "info")) setVerbosity(VERBOSE_INFO); - else if(!strcmp(value, "details")) setVerbosity(VERBOSE_DETAILS); - else if(!strcmp(value, "debug")) setVerbosity(VERBOSE_DEBUG); - else if(!strcmp(value, "force")) ignoreLock = TRUE; - else reportWarning("Unrecognized option '%s'.", value); -} - - -/** - * Sets up a handler for capturing Ctrl-C. - * - */ -static void initSignalHandler() { - static struct sigaction action, old_action; - - reportInfo("Set up signal handler for HUP."); - - /* signal handler for control C */ - action.sa_flags=0; - sigemptyset(&action.sa_mask); - action.sa_handler = processSignal; - - sigaction(SIGHUP, &action, &old_action); - sigaction(SIGINT, &action, &old_action); - sigaction(SIGTERM, &action, &old_action); - - reportDetail("OK."); -} - - -static void processSignal(int signum) { - if(signum == SIGHUP) { - if(!isSilent()) fprintf(stderr, "Received SIGHUP --> Reconfiguring.\n"); - lookup_refresh_1_svc(NULL, NULL); - } - else if(signum == SIGINT || signum == SIGTERM) { - if(!isSilent()) fprintf(stderr, "Received SIGINT/SIGTERM --> Exiting.\n"); - exit(EINTR); - } - else if(!isSilent()) fprintf(stderr, "Received signal %d. Ignoring.\n", signum); -} - - -int main(int argc, char **argv) { - extern void lookupprog_1(struct svc_req *rqstp, register SVCXPRT *transp); - - int i, sock; - - for(i=1; i