C699util User's Guide

From 699wiki
Jump to navigation Jump to search

Similar to Introduction to the 699 Python Library, this article is a high-level description of c699util, intended for those who are only using it to write Python scripts. I do not describe low level c699util details here. For that, see the c699util developer's guide.

c699util is a Python module which provides housekeeping and science data extraction routines for MOMA telemetry files. Its interface is very similar to 699util's tmread module:

   #!/usr/bin/env python3 
   # Packet data extraction through 699util's tmread module: 
   import tmread 
   tmfile = tmread.get_tmfile('/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3')
   wrp_current_datapoints = []
   wrp_current_hkid = 800 
   pkt_17_count = 0 
   for pkt in tmfile(17): 
       pkt_17_count += 1 
   # Print out the data: 
   print("pkt_17_count:", pkt_17_count)
   print("WRP current sample timestamp, WRP current sample science value:")
   for timestamp, value in wrp_current_datapoints: 
       print(timestamp, '\t', value)
   # Packet data extraction through c699util: 
   import c699util 
   c_tmfile = c699util.construct_tmfile('/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3')
   wrp_current_datapoints = []
   wrp_current_hkid = 800 
   pkt_17_count = 0 
   for pkt in c_tmfile(17): 
       pkt_17_count += 1 
   # Print out the data: 
   print("pkt_17_count:", pkt_17_count)
   print("WRP current sample timestamp, WRP current sample science value:")
   #for timestamp, value in wrp_current_datapoints: 
   #    print(timestamp, '\t', value)
   # Note the change here! 
   for datapoint in wrp_current_datapoints: 
       print(datapoint.relative_timestamp, '\t', datapoint.value)

As this example illustrates, some minor interface differences exist between c699util and tmread, which are documented at the end of this article.

You are highly encouraged to follow the following convention: if you use c699util in a Python script, please prefix it with "c_". For example, when I ported ioncount.py over to c699util, I made a copy of ioncount.py, called it c_ioncount.py, and then replaced tmread code with similar c699util code. This way, both scripts are available to run (a nice option to have if we encounter bugs), and we always know which underlying library we're using.

If we already have tmread, why bother with c699util?

Well, for one, c699util is about an order of magnitude faster than tmread (and sometimes more -- c_ioncount.py was 39x faster than ioncount.py when extracting selected ion counts).

More importantly, much of tmread is deprecated for MOMA. Any feature that tmread shares with c699util is no longer maintained. Instead of maintaining telemetry extraction libraries in C++, and then duplicating the exact same functionality in Python, we've decided to simply add a Python interface to the C++ code. This dramatically simplifies feature implementation, eliminates consistency issues between various tools, and speeds up software development and program run time, but it also means that tmread won't output data as accurately as c699util, and also won't have as many features.

c699util Flaw -- only one TMFile at a time

Because the C++ code around which c699util wraps frequently uses singletons, c699util can only operate on one TMFile at a time. Calling c699util.construct_tmfile() will invalidate any previously existing c699util.TMFile objects.

We rarely ever (if at all) need this capability, but when the C++ and c699util code is ported over to future missions, this design should be reconsidered.

Obtaining c699util

If you do not have the 699 Python tools installed on your computer, then the developer instructions in Python_Tool_Installation should work, although it's probably best to just ask a MOMA software developer to do it for you. Be sure to install Python 3.4.3 from the Python website.

If you already have 699 Python tools installed, you will probably also have to ask a MOMA software developer to setup c699util. Most likely, Python 3.4.3 will need to be installed directly from the website (sorry, Homebrew aficionados), and your virtual environment will need to be rebuilt so that it uses Python 3.4.3. However, if you happen to already be using Python 3.4.3, then SSH tunneling into repos699 and then updating ~/config699 and ~/labcode/699util should be all that you need to do to start using c699util.


c699util provides a TMFile class which is very similar to tmread's TMFile class. c699util.TMFile objects can be obtained as follows:

   import c699util 
   c_tmfile = c699util.get_tmfile('/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3')

c699util.get_tmfile() is a thin wrapper around tmread.get_tmfile(), so it does all of the telemetry-file-finding-magic that tmread.get_tmfile() does:

   import c699util 
   c_tmfile = c699util.get_tmfile() # grab the tm.mom file in the cwd 
   c_tmfile = c699util.get_tmfile(12345) # Grab TID 12345 
   c_tmfile = c699util.get_tmfile("/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC") # Grab the tm.mom file in the specified directory

It would be preferable to not use the deprecated tmread module, but it seems unlikely to me that I'll ever get around to implementing get_tmfile()'s magic inside of c699util, at least on MOMA. Also, this tactic allows us to keep using the extremely useful TMArgumentParser class.

If tmread is not available, c699util.construct_tmfile() can be used:

   import c699util 
   c_tmfile = c699util.construct_tmfile('/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3')

Also, note the convention of using c_tmfile. I prefer to use 'tmfile' for tmread.TMFile objects, and 'c_tmfile' for c699util.TMFile objects, so that I can tell at a glance what kind of object I'm using. I strongly recommend that other script writers do the same.

Other useful methods:

   #!/usr/bin/env python3 
   import tmread, c699util 
   tmfile = tmread.get_tmfile(30410) # Give it a TID and let it find the file for us 
   c_tmfile = c699util.construct_tmfile(tmfile.filename)
   # (alternatively, we could just do c_tmfile = c699util.get_tmfile(30410) 
   print("Absolute filename:", c_tmfile.filename())
   print("Absolute filename:", str(c_tmfile))
   # Absolute filename: /Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3
   print("Absolute directory:", c_tmfile.absolute_directory())
   # Absolute directory: /Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC
   # Parsed from the first GSE packet in the tm.mom file: 
   print("TID Directory name:", c_tmfile.directory_string())
   # TID Directory name: 2016-01-15-14.06.47-30410-MSFUNC
   print("Mass calibration file used:", c_tmfile.get_mcal_filename())
   # Mass calibration file used: 2016-01-17-23.48.39-30410.mcal
   print("File size in bytes:", c_tmfile.file_size())
   # File size in bytes: 48384623
   print("TID:", c_tmfile.tid())
   # TID: 30410
   print("t0 in Unix time:", c_tmfile.t0_in_unix_time())
   # t0 in Unix time: 1452884878.3959727
   print("Number of packets:", c_tmfile.length())
   print("Number of packets:", len(c_tmfile))
   # Number of packets: 70232
   print("TMFile actually exists on the filesystem:", c_tmfile.exists())
   print("TMFile actually exists on the filesystem:", bool(c_tmfile))
   # TMFile actually exists on the filesystem: True
   pkt_at_index_10 = c_tmfile.get_pkt(10)
   pkt_at_index_10 = c_tmfile[10]
   # We can iterate through c_tmfile and get packet objects: 
   pkt_count = 0 
   for pkt in c_tmfile: 
       pkt_count += 1 
   # The old tm_filter routines also work for c699util: 
   pkt_17_count = 0 
   for pkt in c_tmfile(17): 
       pkt_17_count += 1 
   pkt_count = 0 
   for pkt in c_tmfile(type_filter=17,      # Only yield packets of type 17 
                       marker_filter=2500,  # Only yield packets at marker 2500 
                       start_time=1000,     # Relative time = 1000 seconds 
                       stop_time=2000):     # Relative time = 2000 seconds 
       pkt_count += 1 
   # If the directory name is
   #     '2016-01-15-14.06.47-30410-MSFUNC'
   # then the test name is 
   #     'MSFUNC'
   print("Test name:", c_tmfile.test_name())
   # tmread.MessageLog is not deprecated, and is fully compatible with c699util:
   msg_log = c_tmfile.message_log()
   meta_markers = c_tmfile.get_meta_markers()
   for meta_marker in meta_markers: 
   print("model:", c_tmfile.model())
   # model: fm
   print("FSW timestamp at of t0 packet:", c_tmfile.t0_in_sclk())
   # FSW timestamp at of t0 packet: 19351744

tmread.extract_tmfields() is compatible with c699util.TMFile objects:

   #!/usr/bin/env python3 
   import tmread, c699util 
   tmfile = tmread.get_tmfile(30410) # Give it a TID and let it find the file for us 
   c_tmfile = c699util.construct_tmfile(tmfile.filename)
   RF_AMP_MON_HKID      = 62
   fields = tmread.extract_tmfields(c_tmfile, [AUX_AMP_DAC_SET_HKID, RF_AMP_MON_HKID])
   # Note that we still get c699util.TMDatapoint objects here, which are different
   # from 699util's tmread datapoints!
   sum_ = 0 
   count = 0 
   for datapoint in fields[RF_AMP_MON_HKID]: 
       relative_timestamp = datapoint.relative_timestamp 
       unix_timestamp = datapoint.unix_timestamp
       raw_timestamp = datapoint.fsw_timestamp
       sum_ += datapoint.value 
       count += 1 
   if count != 0: 
       print("RF Amp mon avg:", sum_ / count)


Just like TMFile, c699util provides TMPacket objects which are very similar to tmread.TMPacket objects:

   #!/usr/bin/env python3 
   import tmread, c699util 
   tmfile = tmread.get_tmfile(30410) # Give it a TID and let it find the file for us 
   c_tmfile = c699util.construct_tmfile(tmfile.filename)
   gse_pkt = c_tmfile[0]       # Pkt type 8, GSE generated 
   pkt_22 = c_tmfile[65]       # Pkt type 22 
   msg_log_pkt = c_tmfile[85]  # Pkt type 8 
   print("Unmasked type of gse_pkt:", gse_pkt.full_type())
   # Unmasked type of gse_pkt: 136
   print("Unmasked type of pkt_22:", pkt_22.full_type())
   # Unmasked type of pkt_22: 22
   # This is analagous to tmread.TMPacket.type 
   print("gse_pkt with gse-generated bit masked out:", gse_pkt.get_type())
   # gse_pkt with gse-generated bit masked out: 8
   print("pkt_22 length, including header and checksum:", pkt_22.total_length())
   # pkt_22 length, including header and checksum: 224
   print("pkt_22 length, just the data:", pkt_22.length())
   # pkt_22 length, just the data: 212
   print("pkt_22 checksum:", pkt_22.checksum())
   print("pkt_22 checksum:", hash(pkt_22))
   # pkt_22 checksum: 1379474455
   print("Is pkt_22 gse created?", pkt_22.gse_created())
   # Is pkt_22 gse created? False
   print("Is gse_pkt gse created?", gse_pkt.gse_created())
   # Is gse_pkt gse created? True
   print("pkt_22 sequence number:", pkt_22.sequence())
   # pkt_22 sequence number: 146
   # Yes, I'm aware that 'sclk' is a misnomer 
   print("pkt_22 FSW timestamp:", pkt_22.sclk())
   # pkt_22 FSW timestamp: 19540225
   print("pkt_22 FSW timestamp, in seconds:", pkt_22.sclk_in_seconds())
   # pkt_22 FSW timestamp, in seconds: 1954.0225
   print("pkt_22 index:", pkt_22.index())
   # pkt_22 index: 65
   print("pkt_22 marker ID:", pkt_22.marker_id())
   # pkt_22 marker ID: 0
   # Packets before the first marker packet have a marker index of 0 
   print("pkt_22 marker index:", pkt_22.xina_marker_index())
   # pkt_22 marker index: 0
   print("pkt_22 unix timestamp, in seconds:", pkt_22.unix_timestamp())
   # pkt_22 unix timestamp, in seconds: 1452884897.2440727
   print("pkt_22 relative timestamp, in seconds:", pkt_22.relative_timestamp())
   # pkt_22 relative timestamp, in seconds: 18.848099946975708
   print("pkt_22 marker text:", pkt_22.marker_text())
   # pkt_22 marker text: <no marker text, but you get the idea>
   # (this doesn't actually work for TID 30410, but I think you get the picture)
   # HKID 100 = phase cycle readback HKID
   phase_cycle_readback_raw_data = pkt_22.all_raw_data(100)
   phase_cycle_readback_eng_data = pkt_22.all_eng_data(100)
   phase_cycle_readback_sci_data = pkt_22.all_data(100)
   phase_cycle_readback_sci_data = pkt[100]
   datapoint = phase_cycle_readback_sci_data[0]
   print("Datapoint unix timestamp, in seconds:", datapoint.unix_timestamp)
   print("Datapoint relative timestamp, in seconds:", datapoint.relative_timestamp)
   print("Datapoint value:", datapoint.value)
   first_phase_cycle_readback_science_sample = pkt_22.get_first_value(100) 
   print("Does gse_pkt have an earlier timestamp than pkt_22?", gse_pkt < pkt_22)
   # Does gse_pkt have an earlier timestamp than pkt_22? True
   print("Raw message log:", msg_log_pkt.raw_message())
   print("Sanitized message log:", msg_log_pkt.message())
   # (output omitted for brevity)
   print("raw bytes:", pkt_22.raw_packet())
   # b'\x16\x92\x00\xd4\x01*)\x01\xfa\xf3 \x02\x00...(etc). 
   meta_markers = pkt_22.get_meta_markers() 
   for meta_marker in meta_markers: 

Extracting Science Data

c699util has a get_scans() function, just like tmread.momascience:

   #!/usr/bin/env python3 
   import c699util 
   c_tmfile = c699util.get_tmfile(30410)
   scan_count = 0 
   for scan in c699util.get_scans(c_tmfile): 
       scan_count += 1 
   print("Number of scans:", scan_count)

The usual packet type, marker filtering, start time, etc. filtering options are available.

Unlike tmread, c699util provides a wrapper around MOMA Data View's ScienceDataCache class:

   #!/usr/bin/env python3 
   import c699util 
   # Not needed 
   # c_tmfile = c699util.construct_tmfile(tmfile.filename)
   # Notice that this factory function takes the absolute filename, just like 
   # construct_tmfile
   # science_cache = c699util.construct_science_data_cache('/Users/mpallone/momadata/fm/2016-01-15-14.06.47-30410-MSFUNC/tm.mom.m3.s3')
   science_cache = c699util.get_science_data_cache(30410) 

c699util.get_science_data_cache() is analagous to c699util.get_tmfile(), so it can be passed no arguments if the programmer wants to search the cwd, or just the TID to search for, or the absolute path of the tm.mom file, etc.

The science cache can be iterated through to get scan objects (just like c699util.get_scans()), or it can be indexed, as demonstrated below.

   #!/usr/bin/env python3 
   import c699util 
   science_cache = c699util.get_science_data_cache(30410)
   last_scan = science_cache[-1]
   print("Last scan data:")
   print("Unix timestamp, in seconds:", last_scan.unix_timestamp())
   # Unix timestamp, in seconds: 1452890221.7956727
   print("Relative timestamp, in seconds:", last_scan.relative_timestamp())
   # Relative timestamp, in seconds: 5343.399699926376
   print("marker ID:", last_scan.marker_id())
   # marker ID: 2050
   print("marker Index:", last_scan.xina_marker_index())
   # marker Index: 136
   print("marker text:", last_scan.marker_text())
   # marker text: SCN 602 START Emission Current Source B
   list_of_ion_counts = last_scan.counts() 
   print("total ion count:", sum(list_of_ion_counts))
   print("total ion count:", last_scan.total_ion_count())
   # total ion count: 40463
   print("Highest count in the last_scan:", last_scan.highest_count())
   # Highest count in the last_scan: 708
   print("Bin number containing the highest count:", last_scan.highest_count_bin_num())
   # Bin number containing the highest count: 1710
   print("Lowest count:", last_scan.lowest_count())
   # Lowest count: 0
   # There should be one entry for every 100 bins 
   rf_status_entry_list = last_scan.rf_status_entries()
   rf_entry = rf_status_entry_list[0]
   print("First RF Entry start bin:", rf_entry.start_bin)
   # First RF Entry start bin: 0
   print("First RF Entry RF Amp V:", rf_entry.rf_amp_v)
   # First RF Entry RF Amp V: 66.67613871395588
   print("First RF Entry RF Amp DAC V:", rf_entry.rf_amp_dac_v)
   # First RF Entry RF Amp DAC V: 70.00512770935893
   print("First RF Entry Aux Amp DAC V:", rf_entry.aux_amp_dac_v)
   # First RF Entry Aux Amp DAC V: 1.0998702980577946
   print("RF Amp Start:", last_scan.rf_amp_start())
   # RF Amp Start: 66.67613871395588
   print("RF Amp End:", last_scan.rf_amp_end())
   # RF Amp End: 993.6579284607433
   print("RF Amp DAC Start:", last_scan.rf_amp_dac_start())
   # RF Amp DAC Start: 70.00512770935893
   print("RF Amp DAC End:", last_scan.rf_amp_dac_end())
   # RF Amp DAC End: 996.3826513544906
   print("Aux Amp DAC Start:", last_scan.aux_amp_dac_start())
   # Aux Amp DAC Start: 1.0998702980577946
   print("Total scan time, in seconds:", last_scan.total_scan_time())
   # Total scan time, in seconds: 0.05000000074505805
   print("Peak counts per second:", last_scan.peak_counts_per_sec())
   # Peak counts per second: 70799998.9449978
   print("Pkt source type (26 or 27):", last_scan.src_pkt_type())
   # Pkt source type (26 or 27): 27
   print("Number of scans that went into this scan (typically 10 for sum packets):")
   # Number of scans that went into this scan (typically 10 for sum packets):
   # 10
   print("Does this scan have a scan status packet?", last_scan.has_scan_status())
   # Does this scan have a scan status packet? True
   print("Number of scan status packets:", last_scan.num_scan_status_pkts())
   # Number of scan status packets: 10
   print("Does this scan have a preceding SEB HK packet?", last_scan.has_seb_hk_pkt())
   # Does this scan have a preceding SEB HK packet? True
   print("Is this scan a dark count scan?", last_scan.is_dark_count_scan())
   # Is this scan a dark count scan? False
   print("Sum of the ion counts for bins 500-600:")
   # Sum of the ion counts for bins 500-600:
   # 3981
   print("Sum of the ion counts between masses 138-140:")
   # Sum of the ion counts between masses 138-140:
   # 78
   print("Maximum ion count between bins 500-600:")
   # Maximum ion count between bins 500-600:
   # 537
   print("Maximum ion count between masses 138-140:")
   # Maximum ion count between masses 138-140:
   # 21
   print("seb_bin_time_readback:", last_scan.seb_bin_time_readback())
   # seb_bin_time_readback: 10.000000149011612
   print("seb_bin_time_readback_in_seconds:", last_scan.seb_bin_time_readback_in_seconds())
   # seb_bin_time_readback_in_seconds: 1.0000000149011612e-05
   print("seb_special_scan_id:", last_scan.seb_special_scan_id())
   # seb_special_scan_id: 602
   print("seb_raw_scan_value:", last_scan.seb_raw_scan_value())
   # seb_raw_scan_value: 127
   print("seb_scan_value:", last_scan.seb_scan_value())
   # seb_scan_value: 49.80392238497734
   print("seb_rf_freq_hz:", last_scan.seb_rf_freq_hz())
   # seb_rf_freq_hz: 988400.0
   print("seb_last_rf_amp_mon:", last_scan.seb_last_rf_amp_mon())
   # seb_last_rf_amp_mon: 993.6579284607433
   print("seb_rf_amp_dac_set:", last_scan.seb_rf_amp_dac_set())
   # seb_rf_amp_dac_set: 996.3826513544906
   print("seb_aux_amp_dac_set:", last_scan.seb_aux_amp_dac_set())
   # seb_aux_amp_dac_set: 7.297474631876097
   print("seb_counter_sel:", last_scan.seb_counter_sel())
   # seb_counter_sel: 1
   print("seb_bin_count_set:", last_scan.seb_bin_count_set())
   # seb_bin_count_set: 5000
   print("seb_bin_count_reg:", last_scan.seb_bin_count_reg())
   # seb_bin_count_reg: 20000
   print("seb_phase_cycle_rdbk:", last_scan.seb_phase_cycle_rdbk())
   # seb_phase_cycle_rdbk: 3
   print("seb_rf_step_set:", last_scan.seb_rf_step_set())
   # seb_rf_step_set: 0.1870379802200142
   print("seb_rf_step_reg:", last_scan.seb_rf_step_reg())
   # seb_rf_step_reg: -0.038366765173336245
   print("seb_aux_step_set:", last_scan.seb_aux_step_set())
   # seb_aux_step_set: 0.0012397955291065842
   print("seb_aux_step_reg:", last_scan.seb_aux_step_reg())
   # seb_aux_step_reg: 0.0006103608758678569
   print("seb_ionization_time_in_milliseconds:", last_scan.seb_ionization_time_in_milliseconds())
   # seb_ionization_time_in_milliseconds: 4.999999888241291
   print("seb_scan_em1:", last_scan.seb_scan_em1())
   # seb_scan_em1: -2069.6365661583154
   print("seb_scan_em1_raw:", last_scan.seb_scan_em1_raw())
   # seb_scan_em1_raw: 197
   print("seb_scan_em2:", last_scan.seb_scan_em2())
   # seb_scan_em2: 994.4167251074475
   print("seb_scan_em2_raw:", last_scan.seb_scan_em2_raw())
   # seb_scan_em2_raw: 0
   print("seb_src_a_foc_a_dac_set:", last_scan.seb_src_a_foc_a_dac_set())
   # seb_src_a_foc_a_dac_set: -39.6078431372549
   print("seb_src_b_foc_a_dac_set:", last_scan.seb_src_b_foc_a_dac_set())
   # seb_src_b_foc_a_dac_set: -39.6078431372549
   print("seb_src_a_foc_a_dac_reg:", last_scan.seb_src_a_foc_a_dac_reg())
   # seb_src_a_foc_a_dac_reg: -67.45098039215686
   print("seb_src_b_foc_a_dac_reg:", last_scan.seb_src_b_foc_a_dac_reg())
   # seb_src_b_foc_a_dac_reg: -67.45098039215686
   print("meta markers:", last_scan.get_meta_markers())
   # output omitted due to laziness, it's the same interface that's documented in the TMFile and TMPacket sections
   print("m/z values:", last_scan.m_over_z_values())
   # (long tuple of doubles)
   print("list of TICs:", last_scan.total_ion_counts())
   # list of TICs: (3680, 3882, 4092, 4100, 4147, 4119, 4103, 4021, 4214, 4105)
   print("cTIC:", last_scan.corrected_total_ion_count()) 
   # cTIC: 1715842
   print("cTIC Factor:", last_scan.corrected_total_ion_count_factor())
   # cTIC Factor: 42.40522135001076
   print("cTIC Factors:", last_scan.corrected_total_ion_count_factors())
   # cTIC Factors: ()
   print("Packet version:", last_scan.science_data_pkt_version())
   # Packet version: 1
   print("seb_is_fil_a_on:", last_scan.seb_is_fil_a_on())
   # seb_is_fil_a_on: False
   print("seb_is_fil_b_on:", last_scan.seb_is_fil_b_on())
   # seb_is_fil_b_on: True
   print("Scan mode:", last_scan.scan_mode_as_string())
   # Scan mode: EI 
   print("SEB sequence packet indexes:", last_scan.seb_sequence_pkt_indexes())
   # SEB sequence packet indexes: (68463, 68464, 68465)
   print("EM on times (ms):", last_scan.em_on_times_in_ms())
   # EM on times (ms): (600.1000052131712, 0.0)

Interface Differences Between tmread and c699util

This section is intended for those who have used tmread on SAM, LADEE, or MAVEN. My hope is that such users can use c699util just as they use tmread, using this section as a cheatsheet as needed.

   #!/usr/bin/env python3 
   import tmread, c699util 
   tmfile = tmread.get_tmfile(30410) # Give it a TID and let it find the file for us 
   c_tmfile = c699util.construct_tmfile(tmfile.filename)
   RF_AMP_MON_HKID      = 62
   # TMFile interface differences 
   # Getting a TMFile: 
   tmfile = tmread.get_tmfile(30410) # Can be passed TID or absolute filename
   c_tmfile = c699util.construct_tmfile(tmfile.filename) # requires absolute filename
   filename =   tmfile.filename 
   filename = c_tmfile.filename() 
   dir_string =   tmfile.directory_string 
   dir_string = c_tmfile.directory_string() 
   t0_in_unix_time =   tmfile.start_time().unix   # Returns TMTimestamp object
   t0_in_unix_time = c_tmfile.t0_in_unix_time() # Returns a float 
   msg_log =   tmfile.message_log 
   msg_log = c_tmfile.message_log() 
   # TMPacket interface differences 
   pkt   = tmfile[-1]
   c_pkt = c_tmfile[-1]
   # Packet type with GSE bit masked out: 
   pkt_type =   pkt.type 
   pkt_type = c_pkt.get_type() 
   # Full packet type: 
   full_pkt_type =   pkt.full_type 
   full_pkt_type = c_pkt.full_type() 
   total_length =   pkt.total_length 
   total_length = c_pkt.total_length() 
   # Doesn't included the 8 byte header and 4 byte checksum, unlike total_length 
   data_length =   pkt.length 
   data_length = c_pkt.length() 
   checksum =   pkt.checksum 
   checksum = c_pkt.checksum() 
   gse_created =   pkt.gse_created
   gse_created = c_pkt.gse_created() 
   sequence_number =   pkt.sequence 
   sequence_number = c_pkt.sequence() 
   fsw_timestamp =   pkt.raw_time 
   fsw_timestamp = c_pkt.sclk() 
   unix_timestamp =   pkt.timestamp.unix     # TMTimestamp object 
   unix_timestamp = c_pkt.unix_timestamp()   # float 
   relative_timestamp =   pkt.timestamp.relative   # TMTimestamp object 
   relative_timestamp = c_pkt.relative_timestamp() # float 
   marker_text =   pkt.marker_text
   marker_text = c_pkt.marker_text()  
   marker_id =   pkt.mkid 
   marker_id = c_pkt.marker_id() 
   msg =   pkt.message 
   msg = c_pkt.message() 
   # Housekeeping data interface: 
   data_dict = tmread.extract_tmfields(tmfile, [800])
   hkid_800_datapoints = data_dict[800]
   first_datapoint = hkid_800_datapoints[0]
   timestamp = first_datapoint.ts 
   value = first_datapoint.val 
   data_dict = tmread.extract_tmfields(c_tmfile, [800])
   hkid_800_datapoints = data_dict[800]
   first_datapoint = hkid_800_datapoints[0]
   unix_timestamp = first_datapoint.unix_timestamp
   relative_timestamp = first_datapoint.relative_timestamp 
   value = first_datapoint.value 
   # Scan interface differences 
   scan =   list(tmread.get_scans(tmfile))[-1]
   c_scan = list(c699util.get_scans(c_tmfile))[-1]
   result =   scan.timestamp.unix        # Returns a TMTimestamp object 
   result = c_scan.unix_timestamp();     # Returns a float 
   result =   scan.timestamp.relative       # Returns a TMTimestamp object 
   result = c_scan.relative_timestamp();    # Returns a float 
   result =   scan.marker_text 
   result = c_scan.marker_text(); 
   result =   scan.scanpoints   # list of MomaScanPoint objects 
   result = c_scan.counts();    # list of integers 
   result =   scan.total_ion_count
   result = c_scan.total_ion_count(); 
   result =   scan.highest_count
   result = c_scan.highest_count(); 
   result =   scan.highest_count_bin_num 
   result = c_scan.highest_count_bin_num(); 
   result =   scan.rf_amp_start 
   result = c_scan.rf_amp_start(); 
   result =   scan.rf_amp_end 
   result = c_scan.rf_amp_end(); 
   result =   scan.rf_amp_dac_start 
   result = c_scan.rf_amp_dac_start();
   result =   scan.rf_amp_dac_end 
   result = c_scan.rf_amp_dac_end(); 
   result =   scan.aux_amp_dac_start 
   result = c_scan.aux_amp_dac_start(); 
   result =   scan.aux_amp_dac_end 
   result = c_scan.aux_amp_dac_end();     
   result =   scan.total_scan_time 
   result = c_scan.total_scan_time(); 
   result =   scan.peak_counts_per_sec
   result = c_scan.peak_counts_per_sec();
   result =   scan.src_pkt_type 
   result = c_scan.src_pkt_type();
   result =   scan.num_scans 
   result = c_scan.num_scans(); 
   result = bool(scan.seb_state.num_scan_status_pkt_updates)
   result = c_scan.has_scan_status(); 
   result =   scan.seb_state.num_scan_status_pkt_updates
   result = c_scan.num_scan_status_pkts();     
   result =   scan.seb_state.scan_bin_time_readback 
   result = c_scan.seb_bin_time_readback()
   result =   scan.seb_state.scan_bin_time_readback_in_seconds 
   result = c_scan.seb_bin_time_readback_in_seconds()
   result =   scan.seb_state.special_scan_id 
   result = c_scan.seb_special_scan_id()
   result =   scan.seb_state.raw_scan_value 
   result = c_scan.seb_raw_scan_value()
   result =   scan.seb_state.scan_value 
   result = c_scan.seb_scan_value()
   result =   scan.seb_state.rf_freq 
   result = c_scan.seb_rf_freq_hz()
   result =   scan.seb_state.last_rf_amp_mon
   result = c_scan.seb_last_rf_amp_mon()
   result =   scan.seb_state.rf_amp_dac_set
   result = c_scan.seb_rf_amp_dac_set()
   result =   scan.seb_state.aux_amp_dac_set
   result = c_scan.seb_aux_amp_dac_set()
   result =   scan.seb_state.counter_sel
   result = c_scan.seb_counter_sel()
   result =   scan.seb_state.bin_count_set
   result = c_scan.seb_bin_count_set()
   result =   scan.seb_state.bin_count_reg
   result = c_scan.seb_bin_count_reg()
   result =   scan.seb_state.phase_cycle_rdbk
   result = c_scan.seb_phase_cycle_rdbk()
   result =   scan.seb_state.rf_step_set
   result = c_scan.seb_rf_step_set()
   result =   scan.seb_state.rf_step_reg
   result = c_scan.seb_rf_step_reg()
   result =   scan.seb_state.rf_step_reg
   result = c_scan.seb_aux_step_set()
   result =   scan.seb_state.aux_step_reg
   result = c_scan.seb_aux_step_reg()
   result =   scan.seb_state.ionization_time
   result = c_scan.seb_ionization_time_in_milliseconds()
   result =   scan.seb_state.scan_em1
   result = c_scan.seb_scan_em1()
   result =   scan.seb_state.scan_em2
   result = c_scan.seb_scan_em2()
   result =   scan.seb_state.srcA_foc_a_dac_set
   result = c_scan.seb_src_a_foc_a_dac_set()
   result =   scan.seb_state.srcB_foc_a_dac_set
   result = c_scan.seb_src_b_foc_a_dac_set()
   result =   scan.seb_state.srcA_foc_a_dac_reg
   result = c_scan.seb_src_a_foc_a_dac_reg()
   result =   scan.seb_state.srcB_foc_a_dac_reg
   result = c_scan.seb_src_b_foc_a_dac_reg()
   result = bool(scan.seb_state.num_hk_pkt_updates)
   result = c_scan.has_seb_hk_pkt(); 
   result =   scan.seb_state.is_emon_a
   result = c_scan.seb_is_emon_a(); 
   result =   scan.seb_state.is_emon_b
   result = c_scan.seb_is_emon_b(); 
   result =   scan.count_ions(min_bin=min_bin, max_bin=max_bin)
   result = c_scan.selected_ion_count_sum_by_bin(min_bin, max_bin); 
   result =   scan.count_ions(min_mass=min_mass, max_mass=max_mass)
   result = c_scan.selected_ion_count_sum_by_mass(min_mass, max_mass); 
   result =   scan.max_ion_count(min_bin=min_bin, max_bin=max_bin)
   result = c_scan.selected_ion_count_max_by_bin(min_bin, max_bin);
   result =   scan.max_ion_count(min_mass=min_mass, max_mass=max_mass)
   result = c_scan.selected_ion_count_max_by_mass(min_mass, max_mass);

c699util and the 699 Gnuplot module

If you use GnuplotArgumentParser (a class defined in 699util), be sure to pass use_c699util=True to the constructor, so that it will use c699util objects internally. (This is not default behavior because I don't want to break older Python scripts.)