The resource descriptor (RD file) can include procedure coded in python. We test here a access to a remote webservice at IMCCE to retrieve ephemeris parameters for a given target, observer and observation date.

As the IMCCE/Miriade web services are using SAOP interface, we use the ZEEP python package to query the service. The IMCCE/Miriade web services interfaces are described on each service page on the Miriade portal.

The example presented below is used in a prototype service built for IRTF (Mauna Kea Observatory telescope) NIR images in support of the NASA Juno Mission. You can try out the service following instructions available here.

Procedure Definition

The definition of the procedure in the RD file is done using the <procDef> element. The next code snippet is used for IRTF observations of Jupiter.

<resource schema='irtf_orton'>

  -- Place the <procDef> element after the <meta> elements 

	<procDef type="apply" id="miriadeEphemph">


			<!-- input parameters to be set with <bind> elements in <apply> element -->

			<par key="ignoreUnknowns" description="Return Nones for unknown
				objects?  (if false, ValidationErrors will be raised)">True</par>
			<par key="logUnknowns" description="Write unresolved object names
				to the info log">False</par>
			<par key="target_name" late="True"
				description="The observed target name (Default is Jupiter).">'p:jupiter'</par>
			<par key="observer" late="True"
				description="The observer name (Default is Mauna Kea Observatory, for IRTF).">'@568'</par>
			<par key="obs_time" late="True"
				description="Observation date time."/>

			<!-- any piece of python code to be run before the main procedure, like importing modules -->

				import zeep


			## This is the beginning of the core python code, indentation matters as in python.
			# Initializing some parameters
			slat, slon, olat, olon = None, None, None, None
			np_pos, phase, rap, hemis1, hemis2 = None, None, None, None, None

				# Initialize SOAP client using zeep module 
				client = zeep.Client('')

				# Setting up request parameters (as defined on service description page)
				# NB: Here we will use the ephemph webservice.
				request = {'name': target_name, 'type':'', 'epoch':obs_time.isoformat(), 
					'nbd':1, 'step':'', 'tscale':'', 'so':1, 'observer':observer, 
					'mime':'text', 'view':'none', 'rv':0, 'anim':0, 'print':1, 'visu':'', 
					'output':'--iso,--coord:eq', 'get':''}

				# Retrieving response from webservice
				response = client.service.ephemph(request)

				# Each line of the output text is separated by ';' characters, 
				# and the data line is the first line not starting with '#'
				# The next command split lines and retrieves the first data line
				for line in (item for item in response['result'].split(';') if item[0] != '#'): break

				# splitting results columns
				data = line.split()

				olon = float(data[3])  # Sub-Observer Longitude in Jovian System III (Sub-Earth Point) 
				olat = float(data[4])  # Sub-Observer Latitude in Jovian System III (Sub-Earth Point)
				slon = float(data[7])  # Sub-Solar Longitude in Jovian System III
				slat = float(data[8])  # Sub-Solar Latitude in Jovian System III
				np_pos = float(data[9])  # Angle between planetary North pole and celestial North Pole
				phase = float(data[11])  # Phase angle 
				rap = float(data[12])  # Apparent radius of target
				# in case of APIS extension, we need to tell what is the primary hemisphere (best view) 
				if olat >= 0:
					hemis1 = 'north'
					hemis2 = 'south'
					hemis1 = 'south'
					hemis2 = 'north'

			except KeyError:
				if logUnknowns:
					base.ui.notifyInfo("Identifier did not resolve: %s"%identifier)
				if not ignoreUnknowns:
					raise base.Error("resolveObject could not resolve object"
						" %s."%identifier)

			# Preparing output: whatever you put into the vars dictionary can be used outside the procedure.
			# E.g.: vars["subsolar_longitude"] is defined here, and can be used as @subsolar_longitude outside
			vars["subsolar_longitude"] = slon
			vars["subsolar_latitude"] = slat
			vars["subobserver_longitude"] = olon
			vars["subobserver_latitude"] = olat
			vars["np_pos"] = np_pos
			vars["phase"] = phase
			vars["rap"] = rap
			vars["hemis1"] = hemis1
			vars["hemis2"] = hemis2

  -- Any other RD stuff... 


Using Procedures

Then to use the procedure, we use the <apply> element, with proper configuration. The procedure is used here inside a <rowmaker> element. The <bind> elements allow to link content (constant values or computed values) to input parameters.

<apply procDef="miriadeEphemph">
	<bind key="target_name">'p:jupiter'</bind>
	<bind key="observer">'@568'</bind>
	<bind key="obs_time">parseISODT('T'.join([@DATE_OBS,@TIME_OBS]))</bind>
  • No labels


  1. Very nice achievement! Now, we want to use this with many services, starting with small bodies' (M4ast, TNOsarecool…)

    Next: can we use something similar to retrieve data from a service granule and get results as a VOtable (e.g., for cross-matching in TOPCAT)? That would allow for processing on the fly when the info is not in the service.

    1. Thanks. I'm quite happy indeed (smile)

      My goal would be to include this into the epntap2.rd, so that we can get simple ephemeris and geometry parameters for all services. I also want to try to query the SsODNet name resolver to get the right target names in services. 

    2. For the second point: There is an option of the webservice that outputs in VOTable format. I'll try it out at some point, to make the processing more generic (e.g.: setting Jupiter as a target makes the output a bit specific because of its multiple longitude systems). Parsing the VOTable output would make it easier to identify the columns and map them to our needed parameters.  

  2. Also of interest for BDIP and PVOL of course!

      And even more T1m / Pic du Midi - this almost makes it possible.

  3. What about speed? If we have a service with 10,000 entries, updated on regular basis, we may not want to recompute everything each week. Can we keep previous results and only process updated + new entries?

    1. This is a question of architecture of the RD: if you activate the "updating=True" flag, then only the new or modified rows are processed. If you want to separate the ephemeris computation from the metadata update, then we probably need to have separate tables, with some smart SQL join together with a piece of code to check if ephemeris computation is needed. 

  4. I highly recommend to use the VOTable output of Miriade. NB: a major release is going to occur soon (end of the year, early 2019 at worse), and the users will be able to specify all the columns (i.e., which ones, their order, the format, the units, etc) they want in the output.

    To do so, you will have to upload the VOTable header, and the service will return its outputs accordingly.

    If you plan to always request the same suite of columns/parameters, we can even set a "default" formatted output  for your needs. I.e., instead of pushing each time your header (which would slow down the services), we can define together the outputs you need, so you have a direct access to them (there is a dedicated parameter "tcoor" to select a suite of columns).

    Please send a list of physical quantities (time, coordinates, distances, etc.) and formats (decimal, sexagesimal, ...) you want and we'll prepare that.

    1. OK, thanks. Don't forget to state this in the monthly reports when done (wink)

      About my preferred options:

      • Time and target is all cases (the current ISO format is OK I guess)
      • RA/Dec + Mv for telescopic images in general
      • In the case of HST and similar services, what I find most useful is: phase angle, coord of disk center (sub obs), solar point coordinates (decimal in both cases, E-handed), N pole location (angular distance + azimuth), target ang. size.
      • For event-related mesurements, geocentric / heliocentric distances of target are also handy - and they are also required for radiance to reflectance conversions