Swift TOO API
Swift MOC

swift_too module

Swift_TOO example - Swift Target of Opportunity Submission Example

API version = 1.2, swifttools version = 2.4

Author: Jamie A. Kennea (Penn State)

The Swift_TOO class is used to submit Target of Opportunity Requests for the Swift mission. Before this required manual filling out of a web based form, but given the requirements to trigger Swift using algorithmically determined criteria, this can now be automated through the Swift TOO API, and this class. Here we give a simple example of how to submit a TOO request with this class. Note that we will enable debug mode here, so that the submission will actually complete, but importantly it will not submit an actual Swift TOO!

from swifttools.swift_too import TOO, Resolve

We start by initializing the class and giving our username and shared secret. These can be set up on the Swift TOO website. After you log in, you will find your shared secret, and can modify it as necessary under the Update Account Info link. Note that unlike other TOO API classes, you cannot use anonymous login to submit a TOO request.

username = "myuser"
shared_secret = "my_shared_secret"

OK let's set up the Swift_TOO request (in this case we'll use the swifttools 2.3 shorthand, TOO. Also we're setting debug mode here. Note that I'm not passing my shared_secret here, because my computer supports keyring. This records your shared_secret the first time that you use it, so it's not necessary to include it in later requests.

too = TOO()
too.username = username
# too.shared_secret = shared_secret
too.debug = True

OK, so what are we going to observe, let's start with a name, oh say, SMC X-3, that's a cool object. However, darn, I can't remember the coordinates, but thankfully we have a class called Swift_Resolve (we'll use Resolve for short) for looking these up.

too.source_name = "SMC X-3"
res = Resolve(name=too.source_name)
print(f"RA/Dec (J2000) = {res.ra:.4f},{res.dec:.4f}")
print(f"SkyCoord = {res.skycoord}")
RA/Dec (J2000) = 13.0234,-72.4345
SkyCoord = <SkyCoord (FK5: equinox=J2000.000): (ra, dec) in deg
    (13.02343792, -72.43450778)>

Swift_Resolve reports back ra and dec, but it also reports back as a SkyCoord using the skycoord property if you have astropy installed. Swift_TOO can take a SkyCoord directly.

too.skycoord = res.skycoord

If you use a SkyCoord, it means you can also use more other coordinate systems or formats, rather than just J2000 decimal degrees. Internally all Swift TOOs are stored as decimal RA/Dec in J2000, as this is what Swift uses. Let's check what the values are.

print(f"RA/Dec (J2000) = {too.ra:.4f}, {too.dec:.4f}")
RA/Dec (J2000) = 13.0234, -72.4345

For those who don't want to use astroquery or simbad, you can just do this. Note you can give any number of decimal places, but 4 gives accuracy to less than an arc-second, and Swift isn't that accurate itself.

too.ra, too.dec = 13.0234, -72.4345

Finally, what kind of source is SMC X-3?

too.source_type = "Be/X-ray Binary"

OK, now we've determined what we're looking at, and the coordinates, let's decide what we want to do with this TOO. Well, our object SMC X-3 seems to have gone into outburst again, that's pretty interesting. It's pretty bright also, and evolves quickly, so let's say, oh, we're going to look at it for 1ks per day, every other day for two weeks. Sounds good.

too.exp_time_per_visit = 1000
too.monitoring_freq = "2 days"
too.num_of_visits = 7

Need to justify that exposure time. Not too many words.

too.exp_time_just = "1ks to measure flux and period"

We also need to explain briefly why we're requesting this. One sentence version...

too.immediate_objective = (
    "Track the X-ray evolution and pulsar period in this new outburst of SMC X-3"
)

How quickly should Swift respond to this. We have 4 options.

  • Urgency 1: We need observations within 4 hours. This'll wake people up if it's in the middle of the night for the Swift Team
  • Urgency 2: Observations should start within the next 24 hours. Most typical for new transients, however not to be used if you forgot to submit a TOO request to continue observations of a previous TOO, as that makes people grumpy.
  • Urgency 3: Observations should start in the next few days. Most common when observations aren't super urgent, but you still want to start in a few days.
  • Urgency 4: Weeks to a month. This is for when a TOO isn't really urgent, but you'd like Swift to observe the source in the coming few weeks.

So in our case, SMC X-3 just got detected as in outburst, so we'd like observations ASAP, but 4 hour doesn't really make sense, so....

too.urgency = 2

OK, now we have to define what sort of observation type we're doing here, i.e. what is the primary objective of the observation. There are four options.

_ = [print(f"{t[0]}: {t[1]}") for t in enumerate(too.obs_types)]
0: Spectroscopy
1: Light Curve
2: Position
3: Timing

We're interested primarily in the light curve here, so we'll select that.

too.obs_type = too.obs_types[1]

OK, now we've told the TOO_API what we're looking at, what it is, how long and often we want to look at it, and how quickly. What next? Instrument set-up.

Swift has three telescopes on-board, the UV/Optical Telescope (UVOT), X-ray Telescope (XRT) and Burst Alert Telescope (BAT). Typically TOOs are going to be focused on the first two, as BAT has an extremely large field of view. First step is to pick a primary instrument, this doesn't mean you don't use both, but it helps the teams focus on what you really want here. If you can't decide, roll a dice.

too.instrument = "XRT"

As we're saying XRT is our primary instrument, we should give an important detail for that instrument, in this case brightness.

too.xrt_countrate = 20

OK, so we're observing with XRT. This is a very simple instrument to configure, as it only has three options: Windowed Timing (WT), Photon Counting (WT) and 'Auto'. Here our choice is driven by source brightness, and at our estimated countrate of 20, we'll going to need WT mode to avoid pile-up. 'Auto' picks the mode based on source brightness, but if we know the brightness, it's best to pick ourselves.

too.xrt_mode = "WT"

Note that XRT modes are internally converted to numbers, Auto = 0, PC = 7 and WT = 6. You can use these if you like.

too.xrt_mode = 6
too.xrt_mode
'WT'

Basic validation of mode is done internally, so we can't set the mode to something wrong. The next two commands should return errors.

too.xrt_mode = "Bananas"
---------------------------------------------------------------------------

NameError                                 Traceback (most recent call last)

Input In [19], in <cell line: 1>()
----> 1 too.xrt_mode = "Bananas"

File ~/TOO_API/release/1.2/python/lib/python3.9/site-packages/swifttools/swift_too/common.py:762, in TOOAPI_Instruments.xrt(self, mode)
    760 @xrt.setter
    761 def xrt(self, mode):
--> 762     self.xrt_mode_setter("xrt", mode)

File ~/TOO_API/release/1.2/python/lib/python3.9/site-packages/swifttools/swift_too/common.py:743, in TOOAPI_Instruments.xrt_mode_setter(self, attr, mode)
    741         setattr(self, f"_{attr}", modesxrt[mode])
    742     else:
--> 743         raise NameError(f"Unknown mode ({mode}), should be PC, WT or Auto")
    744 elif mode is None:
    745     setattr(self, f"_{attr}", mode)

NameError: Unknown mode (Bananas), should be PC, WT or Auto
too.xrt_mode = 96
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

Input In [20], in <cell line: 1>()
----> 1 too.xrt_mode = 96

File ~/TOO_API/release/1.2/python/lib/python3.9/site-packages/swifttools/swift_too/common.py:762, in TOOAPI_Instruments.xrt(self, mode)
    760 @xrt.setter
    761 def xrt(self, mode):
--> 762     self.xrt_mode_setter("xrt", mode)

File ~/TOO_API/release/1.2/python/lib/python3.9/site-packages/swifttools/swift_too/common.py:750, in TOOAPI_Instruments.xrt_mode_setter(self, attr, mode)
    748     setattr(self, f"_{attr}", mode)
    749 else:
--> 750     raise ValueError(
    751         f"Unknown mode ({mode}), should be PC (7), WT (6) or Auto (0)"
    752     )

ValueError: Unknown mode (96), should be PC (7), WT (6) or Auto (0)

UVOT is a more complicated instrument to configure, having as it does a large number of combinations of filters. Default for UVOT is filter of the day, which is mode 0x9999. If you want to pick a filter, you can look up the correct mode on the UVOT modes web page.

I think we should look at this guy using UVOT's u filter, so let's pick that.

too.uvot_mode = 0x01AB

Note that we don't do any internal validation of the UVOT mode, because the UVOT mode table is huge, so outside the scope of this. We will check the mode is valid at the server side and report back an error if it's not. Note that although we can set uvot_mode as an integer, when we print it, it always reports as a hex string.

too.uvot_mode
'0x01ab'

Sanity check time, is this UVOT mode the one we want? We can always check with the UVOT_mode class.

from swifttools.swift_too import UVOT_mode

UVOT_mode(too.uvot_mode)

UVOT Mode: 0x01ab

The following table summarizes this mode, ordered by the filter sequence:

Filter Event FOV Image FOV Bin Size Max. Exp. Time Weighting Comments
u None 17 1 3000 3000 FILL THE SNAPSHOT

Filter: The particular filter in the sequence.
Event FOV: The size of the FOV (in arc-minutes) for UVOT event data.
Image FOV: The size of the FOV (in arc-minutes) for UVOT image data.
Max. Exp. Time: The maximum amount of time the snapshot will spend on the particular filter in the sequence.
Weighting: Ratio of time spent on the particular filter in the sequence.
Comments: Additional notes that may be useful to know.

Note if you don't know what UVOT mode you want, you can just put some text in there.

Note if you don't know what UVOT mode you want, you can just put some text in there.

too.uvot_mode = (
    "I think I want all UV filters for this, whatever the UVOT team recommends."
)

OK, one last sanity check before submission, do this pass the internal checks for submission?

if too.validate():
    print("Good to go!")
ERROR: Missing key: science_just

Looks like we forgot something, so we should figure that out! science_just is the clue here, we didn't enter a science justification.

OK, let's write a science justification for this request. This should be persuasive as to why this object requires both rapid observations, and the interest of the Swift mission. Think of writing a proposal, but in a paragraph or two. Let's give it a go...

too.science_just = (
    "SMC X-3 has been detected to be entering it's 3rd outburst since discovery."
    "We wish to monitor the flux and pulsar period in order to track the evolution "
    "of this Be/XRB which has previously shown to enter a Super-Eddington level outburst. "
    "As the outburst has been detected in it's early stages, we request observations begin "
    "ASAP, and request an initial 2 week monitoring period to accurately sample flux rise "
    "and pulsar period evolution."
)
if too.validate():
    print("Good to go!")
INFO: Total exposure time does not match total of individuals. Correcting.
Good to go!

One thing to note, there should have been an warning here, we never entered the total exposure time for the request, but as we gave the individual exposure time, and number of observations, so it calculated it itself. Let's check it real quick, should be 7 exposure x 1000s each....

You can also validate on the server side, this means that the TOO will be checked for any additional issues before submission. Here we go...

if too.server_validate():
    print("Good to go! (server side edition)")
Good to go! (server side edition)

If the server side validation passes with no errors or warnings, we can guarantee that there are no problems with our TOO.

Let's just look at our TOO before we submit it.

too
Parameter Value
Requester myuser
Object Name SMC X-3
Type or Classification Be/X-ray Binary
Right Ascenscion (J2000) 13.0234
Declination (J2000) -72.4345
Position Error (90% confidence - arcminutes) 0.0
Instrument XRT
Urgency 2
XRT Estimated Rate (c/s) 20
Immediate Objective Track the X-ray evolution and pulsar period in this new outburst of SMC X-3
Science Justification SMC X-3 has been detected to be entering it's 3rd outburst since discovery.We wish to monitor the flux and pulsar period in order to track the evolution of this Be/XRB which has previously shown to enter a Super-Eddington level outburst. As the outburst has been detected in it's early stages, we request observations begin ASAP, and request an initial 2 week monitoring period to accurately sample flux rise and pulsar period evolution.
Exposure Time (seconds) 7000
Exposure Time Justification 1ks to measure flux and period
Exposure Time per Visit (seconds) 1000
Number of Visits 7
Monitoring Cadence 2 days
XRT Mode WT
UVOT Mode I think I want all UV filters for this, whatever the UVOT team recommends.
Observation Strategy multiple
What is Driving the Exposure Time? Light Curve
Debug mode True
Validate only False

Now it's time to submit our TOO. Remember as we enabled debug mode, this won't submit a TOO request, but it will act like it, including sending you emails saying it's been recieved.

if too.submit():
    print(f"Submitted TOO ID = {too.status.too_id}")
else:
    print(f"{too.status.status}. Errors: {too.status.errors}")
Rejected. Errors: ['TOO already recently submitted. TOO ID: 13837']
if too.status:
    print("Yes")
else:
    print("No")
No

If the above is reports all good then you're good. You should get an email saying you submitted a TOO (yes even in debug mode). Let's check the status of the TOO anyway, this will give us the TOO ID number assigned to our TOO.

However, this is SMC X-3 we're talking about here, it's declination is -72.4345 degrees. That is pretty close to Swift's pole constraint, and we're submitting at urgency = 2, observations in 24 hours. If you happen to be running this notebook during a period when SMC X-3 is in pole constraint, then you'll see that the request has been rejected, and you'll see an error like this:

Rejected. Errors: ['ERROR: Object currently constrained until 2021-03-20 06:36:00, so 24-hour response TOO rejected.']

If this happens, you can always try resubmitting as Urgency 3 or 4 instead, depending on how long it will be until it comes out of constraint. This will essentially ask the Swift team to please observe it when it becomes visible.

Note: If you want to resubmit a Rejected TOO after modification, you need to clear the current status. This can be done with the status.clear() method, example below:

if not too.status:
    too.urgency = 4  # Change urgency to weeks to months
    too.status.clear()  # Clear the 'Rejected' status of the previous attempt to submit

    # Go ahead and submit again with the revised parameter
    if too.submit():
        print(f"Submitted TOO ID = {too.status.too_id}")
    else:
        print(f"{too.status.status}. Errors: {too.status.errors}")
else:
    print("TOO was already accepted, so no need for modification.")
Submitted TOO ID = 13838

You might have noticed a little trick here. You can check if a TOO is accepted by simple checking the truth value of too.status. So if the TOO has been accepted too.status == True will be return True.

There is another method for checking if a TOO has been accepted, complete which is invoked as such:

too.complete
True

Note that this is different, as it actually queries the TOO API server every time it is called to query if the TOO was accepted. Generally the former method is preferred.

if too.status:
    print("We are done here.")
else:
    print("You shouldn't see this message.")
We are done here.

That is it! There are more configuration options, but this is a simple case. Look at the documentation for more options.

Swift Mission Operations Center

The Pennsylvania State University
301 Science Park Road,
Building 2 Suite 332,
State College, PA 16801
USA
☎ +1 (814) 865-6834
📧 swiftods@swift.psu.edu

Swift MOC Team Leads

Mission Director: John Nousek
Science Operations: Jamie Kennea
Flight Operations: Mark Hilliard
UVOT: Michael Siegel
XRT: Jamie Kennea