Module stixdcpy.net
This module provides APIs to retrieve data from STIX data center Author: Hualin Xiao (hualin.xiao@fhnw.ch) Date: Sep. 1, 2021
Expand source code
#!/usr/bin/python
"""
This module provides APIs to retrieve data from STIX data center
Author: Hualin Xiao (hualin.xiao@fhnw.ch)
Date: Sep. 1, 2021
"""
import hashlib
import numpy as np
import pandas as pd
import pprint
from pathlib import Path, PurePath
from dateutil import parser as dtparser
import requests
from astropy.io import fits
from tqdm import tqdm
import logging
logger = logging.getLogger(__name__)
DOWNLOAD_PATH = Path.cwd() / 'downloads'
DOWNLOAD_PATH.mkdir(parents=False, exist_ok=True)
#HOST = 'https://datacenter.stix.i4ds.net'
HOST='http://localhost:5000'
ENDPOINTS = {
'LC': f'{HOST}/api/request/ql/lightcurves',
'HK': f'{HOST}/api/request/housekeeping',
'HK2': f'{HOST}/api/request/hk2',
'ELUT': f'{HOST}/api/request/eluts',
'EPHEMERIS': f'{HOST}/api/request/ephemeris',
'ATTITUDE': f'{HOST}/api/request/solo/attitude',
'SCIENCE': f'{HOST}/api/request/science-data/id',
'TRANSMISSION': f'{HOST}/api/request/transmission',
'FLARE_LIST': f'{HOST}/api/request/flare-list',
'STIX_POINTING': f'{HOST}/api/request/stixfov',
'FITS': f'{HOST}/api/query/fits',
'CFL_SOLVER': f'{HOST}/api/request/solve/cfl'
}
FITS_TYPES = {
'l0', 'l1', 'l2', 'l3', 'spec', 'qlspec', 'asp', 'aspect', 'lc', 'bkg',
'var', 'ffl', 'cal', 'hkmin', 'hkmax'
}
class FitsQueryResult(object):
"""
FITS query result manager
"""
def __init__(self, resp):
self.hdu_objects = []
self.result = resp
self.downloaded_fits_files = []
def __repr__(self):
return str(self.result)
def __getitem__(self, index):
return self.result[index]
def __getattr__(self, name):
if name in ['num', 'len']:
return len(self.result)
elif name == 'hduls':
return self.hdu_objects
def __len__(self):
return len(self.result)
def to_pandas(self):
"""
Convert FitsQueryResult to pandas dataframe
Returns:
pandas data frame
"""
return pd.DataFrame(self.result)
def open_fits(self):
"""
Open all the FITS files
Returns:
hdu_objcts: list
A list of HDU objects
"""
self.hdu_objects = []
for filename in self.downloaded_fits_files:
self.hdu_objects.append(fits.open(filename))
return self.hdu_objects
def fits_info(self):
"""
Print out information of the loaded specified FITS files
"""
for hdu in self.hdu_objects:
logger.info(hdu.info())
def get_fits_ids(self):
"""
Get FITS file IDs
Return
ids: list
FITS file ids
"""
return [row['fits_id'] for row in self.result]
def fetch(self):
"""
Download fits files from STIX data center
FITS files will be stored in the folder download/ in the current directory
Returns:
fits_filenames: list
List of downloaded FITS filenames
"""
if self.result:
self.downloaded_fits_files = FitsQuery.fetch(self.result)
return self.downloaded_fits_files
else:
logger.warning('WARNING: Nothing to be downloaded from stix data center!')
class FitsQuery(object):
"""
Query or Fetch FITS products from STIX data center
"""
def __init__(self):
self.fits_file_list = []
@staticmethod
def wget(url: str, desc: str, progress_bar=True):
"""Download a file from the link and save the file to a temporary file.
Downloading progress will be shown in a progress bar
Parameters:
url (str): URL
desc (str): description to be shown on the progress bar
Returns:
temporary filename
"""
stream = progress_bar
resp = requests.get(url, stream=stream)
content_type = resp.headers.get('content-type')
if content_type != 'binary/x-fits':
logger.error(resp.content)
return None
folder = DOWNLOAD_PATH
try:
fname = resp.headers.get("Content-Disposition").split(
"filename=")[1]
except AttributeError:
md5hex = hashlib.md5(url.encode('utf-8')).hexdigest()
fname = f'{md5hex}.fits'
filename = PurePath(folder, fname)
file_path = Path(filename)
if file_path.is_file():
logger.info(f'Found the data in local storage. Filename: {filename} ...')
return str(file_path)
f = open(filename, 'wb')
chunk_size = 1024
total = int(resp.headers.get('content-length', 0))
with tqdm(
desc=desc,
total=total,
unit='iB',
unit_scale=True,
unit_divisor=chunk_size,
) as bar:
for data in resp.iter_content(chunk_size=chunk_size):
size = f.write(data)
bar.update(size)
name = f.name
f.close()
return name
@staticmethod
def query(begin_utc, end_utc, product_type='lc', filter=None):
"""Query FITS products from STIX data center
Args:
start_utc (str): start time
stop_utc (str): end time
product_type (str, optional):
FITS product type. Defaults to 'lc'.
Returns:
results: FitsQueryResult
file result object
"""
if product_type not in FITS_TYPES:
raise TypeError(
f'Invalid product type! product_type can be one of {str(FITS_TYPES)}'
)
form = {'start_utc': begin_utc, 'end_utc': end_utc, 'type':product_type, 'filter':str(filter)}
url = ENDPOINTS['FITS']
res=[]
r=JSONRequest.post(url, form)
if isinstance(r, list):
res = r
elif 'error' in r:
logger.error(r['error'])
return FitsQueryResult(res)
@staticmethod
def fetch_bulk_science_by_request_id(request_id):
url = f'{HOST}/download/fits/bsd/{request_id}'
fname = FitsQuery.wget(url,
f'Downloading STIX Science data #{request_id}')
return fname
@staticmethod
def fetch(query_results):
"""
Download FITS files
Arguments
----
query_results: FitsQueryResult
FitsQueryResult object
Returns
-------
filenames: list
A list of fits filenames
"""
fits_ids = []
if isinstance(query_results, FitsQueryResult):
fits_ids = query_results.get_fits_ids()
elif isinstance(query_results, int):
fits_ids = [query_results]
elif isinstance(query_results, list):
try:
fits_ids = [row['fits_id'] for row in query_results]
except Exception as e:
pass
if not fits_ids:
try:
fits_ids = [
row for row in query_results if isinstance(row, int)
]
except:
pass
if not fits_ids:
raise TypeError('Invalid argument type')
fits_filenames = []
try:
for file_id in fits_ids:
fname = FitsQuery.get_fits(file_id)
fits_filenames.append(fname)
except Exception as e:
raise e
# self.fits_file_list=fits_filenames
return fits_filenames
@staticmethod
def get_fits(fits_id, progress_bar=True):
"""Download FITS data products from STIX data center.
Parameters:
fits_id: FITS file ID
progress_bar: show the progress bar if it is true
Returns:
A FITS hdulist object if success; None if failed
"""
url = f'{HOST}/download/fits/{fits_id}'
fname = FitsQuery.wget(url, 'Downloading data', progress_bar)
return fname
@staticmethod
def fetch_continuous_data(start_utc, end_utc, data_type):
if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']:
raise TypeError(f'Data type {data_type} not supported!')
url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}'
fname = FitsQuery.wget(url, 'Downloading data', True)
return fname
class JSONRequest(object):
"""Request json format data from STIX data center """
@staticmethod
def post(url, form):
response = requests.post(url, data=form)
data = response.json()
if 'error' in data:
if data['error']:
return None
return data
@staticmethod
def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool):
""" Request light curve from STIX data center
Parameters:
begin_utc: str
Observation start time
end_utc: str
Observation end time
ltc: bool, optional
Light time correction enabling flag. Do light time correction if True
Returns:
lightcurve: dict
A python dictionary containing light curve data
"""
form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc}
url = ENDPOINTS['LC']
return JSONRequest.post(url, form)
@staticmethod
def fetch_housekeeping(begin_utc: str, end_utc: str):
"""Fetch housekeeping data from STIX data center
Parameters:
begin_utc: Data start time
end_utc: data end time
Returns:
result: dict
housekeeping data
"""
if not begin_utc.endswith('Z'):
begin_utc += 'Z'
if not end_utc.endswith('Z'):
end_utc += 'Z'
start_unix = dtparser.parse(begin_utc).timestamp()
end_unix = dtparser.parse(end_utc).timestamp()
duration = int(end_unix) - int(start_unix)
form = {
'start_unix': start_unix,
'duration': duration,
}
url = ENDPOINTS['HK']
return JSONRequest.post(url, form)
@staticmethod
def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err):
"""compute flare location using the online flare location solver
Parameters:
cfl_counts: numpy array or list
counts recorded by the 12 CFL pixels
cfl_counts_err: numpy array or list
standard deviations of the counts recorded by the 12 CFL pixels
fluence: float
X-ray fluence in units of counts/mm2, calculated using counts recorded by other detectors
fluence_err: float
Errors in fluence in counts/mm2 units
Returns:
location: dict
CFL location, ephemeris and the chisquare map
"""
form = {
'counts': cfl_counts,
'counts_err': cfl_counts_err,
'fluence': fluence,
'fluence_err': fluence_err
}
url = ENDPOINTS['CFL_SOLVER']
return JSONRequest.post(url, form)
@staticmethod
def fetch_elut(utc):
"""Download ELUT from STIX data center
Parameters:
utc: Time
Returns: dict
object: a diction string containing elut information
"""
form = {'utc': utc}
url = ENDPOINTS['ELUT']
return JSONRequest.post(url, form)
@staticmethod
def request_ephemeris(begin_utc: str, end_utc: str, steps=1):
return JSONRequest.post(ENDPOINTS['EPHEMERIS'], {
'start_utc': begin_utc,
'end_utc': end_utc,
'steps': steps
})
@staticmethod
def request_pointing(utc: str):
return JSONRequest.post(ENDPOINTS['STIX_POINTING'], {
'utc': utc,
})
@staticmethod
def request_attitude(begin_utc: str,
end_utc: str,
steps=1,
instrument_frame='SOLO_SRF',
ref_frame='SOLO_SUN_RTN'):
form = {
'start_utc': begin_utc,
'end_utc': end_utc,
'steps': steps,
'frame1': instrument_frame,
'frame2': ref_frame
}
ret = JSONRequest.post(ENDPOINTS['ATTITUDE'], form)
return ret
@staticmethod
def fetch_science_data(_id: int):
"""fetch science data from stix data center
Parameters:
_id: int
science data unique ID, which can be found on STIX data center bulk science data web page
Returns:
science_data: dict
science data received from data center if success or None if failed
"""
return JSONRequest.post(ENDPOINTS['SCIENCE'], {
'id': _id,
})
@staticmethod
def fetch_flare_list(begin_utc: str, end_utc: str, sort: str = 'time'):
""" query and download flare list from stix data center
Parameters:
------
begin_utc: str
flare start UTC
end_utc: str
flare end UTC
sort: str
key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
Returns:
-----
flare_list: dict or None
flare list if success or None if failed.
"""
return JSONRequest.post(ENDPOINTS['FLARE_LIST'], {
'start_utc': begin_utc,
'end_utc': end_utc,
'sort': sort
})
Classes
class FitsQuery
-
Query or Fetch FITS products from STIX data center
Expand source code
class FitsQuery(object): """ Query or Fetch FITS products from STIX data center """ def __init__(self): self.fits_file_list = [] @staticmethod def wget(url: str, desc: str, progress_bar=True): """Download a file from the link and save the file to a temporary file. Downloading progress will be shown in a progress bar Parameters: url (str): URL desc (str): description to be shown on the progress bar Returns: temporary filename """ stream = progress_bar resp = requests.get(url, stream=stream) content_type = resp.headers.get('content-type') if content_type != 'binary/x-fits': logger.error(resp.content) return None folder = DOWNLOAD_PATH try: fname = resp.headers.get("Content-Disposition").split( "filename=")[1] except AttributeError: md5hex = hashlib.md5(url.encode('utf-8')).hexdigest() fname = f'{md5hex}.fits' filename = PurePath(folder, fname) file_path = Path(filename) if file_path.is_file(): logger.info(f'Found the data in local storage. Filename: {filename} ...') return str(file_path) f = open(filename, 'wb') chunk_size = 1024 total = int(resp.headers.get('content-length', 0)) with tqdm( desc=desc, total=total, unit='iB', unit_scale=True, unit_divisor=chunk_size, ) as bar: for data in resp.iter_content(chunk_size=chunk_size): size = f.write(data) bar.update(size) name = f.name f.close() return name @staticmethod def query(begin_utc, end_utc, product_type='lc', filter=None): """Query FITS products from STIX data center Args: start_utc (str): start time stop_utc (str): end time product_type (str, optional): FITS product type. Defaults to 'lc'. Returns: results: FitsQueryResult file result object """ if product_type not in FITS_TYPES: raise TypeError( f'Invalid product type! product_type can be one of {str(FITS_TYPES)}' ) form = {'start_utc': begin_utc, 'end_utc': end_utc, 'type':product_type, 'filter':str(filter)} url = ENDPOINTS['FITS'] res=[] r=JSONRequest.post(url, form) if isinstance(r, list): res = r elif 'error' in r: logger.error(r['error']) return FitsQueryResult(res) @staticmethod def fetch_bulk_science_by_request_id(request_id): url = f'{HOST}/download/fits/bsd/{request_id}' fname = FitsQuery.wget(url, f'Downloading STIX Science data #{request_id}') return fname @staticmethod def fetch(query_results): """ Download FITS files Arguments ---- query_results: FitsQueryResult FitsQueryResult object Returns ------- filenames: list A list of fits filenames """ fits_ids = [] if isinstance(query_results, FitsQueryResult): fits_ids = query_results.get_fits_ids() elif isinstance(query_results, int): fits_ids = [query_results] elif isinstance(query_results, list): try: fits_ids = [row['fits_id'] for row in query_results] except Exception as e: pass if not fits_ids: try: fits_ids = [ row for row in query_results if isinstance(row, int) ] except: pass if not fits_ids: raise TypeError('Invalid argument type') fits_filenames = [] try: for file_id in fits_ids: fname = FitsQuery.get_fits(file_id) fits_filenames.append(fname) except Exception as e: raise e # self.fits_file_list=fits_filenames return fits_filenames @staticmethod def get_fits(fits_id, progress_bar=True): """Download FITS data products from STIX data center. Parameters: fits_id: FITS file ID progress_bar: show the progress bar if it is true Returns: A FITS hdulist object if success; None if failed """ url = f'{HOST}/download/fits/{fits_id}' fname = FitsQuery.wget(url, 'Downloading data', progress_bar) return fname @staticmethod def fetch_continuous_data(start_utc, end_utc, data_type): if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']: raise TypeError(f'Data type {data_type} not supported!') url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}' fname = FitsQuery.wget(url, 'Downloading data', True) return fname
Static methods
def fetch(query_results)
-
Download FITS files Arguments
query_results
:FitsQueryResult
- FitsQueryResult object
Returns
filenames
:list
- A list of fits filenames
Expand source code
@staticmethod def fetch(query_results): """ Download FITS files Arguments ---- query_results: FitsQueryResult FitsQueryResult object Returns ------- filenames: list A list of fits filenames """ fits_ids = [] if isinstance(query_results, FitsQueryResult): fits_ids = query_results.get_fits_ids() elif isinstance(query_results, int): fits_ids = [query_results] elif isinstance(query_results, list): try: fits_ids = [row['fits_id'] for row in query_results] except Exception as e: pass if not fits_ids: try: fits_ids = [ row for row in query_results if isinstance(row, int) ] except: pass if not fits_ids: raise TypeError('Invalid argument type') fits_filenames = [] try: for file_id in fits_ids: fname = FitsQuery.get_fits(file_id) fits_filenames.append(fname) except Exception as e: raise e # self.fits_file_list=fits_filenames return fits_filenames
def fetch_bulk_science_by_request_id(request_id)
-
Expand source code
@staticmethod def fetch_bulk_science_by_request_id(request_id): url = f'{HOST}/download/fits/bsd/{request_id}' fname = FitsQuery.wget(url, f'Downloading STIX Science data #{request_id}') return fname
def fetch_continuous_data(start_utc, end_utc, data_type)
-
Expand source code
@staticmethod def fetch_continuous_data(start_utc, end_utc, data_type): if data_type not in ['hkmax', 'lc', 'var', 'qlspec', 'bkg']: raise TypeError(f'Data type {data_type} not supported!') url = f'{HOST}/create/fits/{start_utc}/{end_utc}/{data_type}' fname = FitsQuery.wget(url, 'Downloading data', True) return fname
def get_fits(fits_id, progress_bar=True)
-
Download FITS data products from STIX data center.
Parameters
fits_id: FITS file ID progress_bar: show the progress bar if it is true
Returns
A FITS hdulist object if success; None if failed
Expand source code
@staticmethod def get_fits(fits_id, progress_bar=True): """Download FITS data products from STIX data center. Parameters: fits_id: FITS file ID progress_bar: show the progress bar if it is true Returns: A FITS hdulist object if success; None if failed """ url = f'{HOST}/download/fits/{fits_id}' fname = FitsQuery.wget(url, 'Downloading data', progress_bar) return fname
def query(begin_utc, end_utc, product_type='lc', filter=None)
-
Query FITS products from STIX data center
Args
start_utc
:str
- start time
stop_utc
:str
- end time
product_type
:str
, optional
FITS product type. Defaults to 'lc'.
Returns
results
- FitsQueryResult file result object
Expand source code
@staticmethod def query(begin_utc, end_utc, product_type='lc', filter=None): """Query FITS products from STIX data center Args: start_utc (str): start time stop_utc (str): end time product_type (str, optional): FITS product type. Defaults to 'lc'. Returns: results: FitsQueryResult file result object """ if product_type not in FITS_TYPES: raise TypeError( f'Invalid product type! product_type can be one of {str(FITS_TYPES)}' ) form = {'start_utc': begin_utc, 'end_utc': end_utc, 'type':product_type, 'filter':str(filter)} url = ENDPOINTS['FITS'] res=[] r=JSONRequest.post(url, form) if isinstance(r, list): res = r elif 'error' in r: logger.error(r['error']) return FitsQueryResult(res)
def wget(url: str, desc: str, progress_bar=True)
-
Download a file from the link and save the file to a temporary file. Downloading progress will be shown in a progress bar
Parameters
url (str): URL desc (str): description to be shown on the progress bar
Returns
temporary filename
Expand source code
@staticmethod def wget(url: str, desc: str, progress_bar=True): """Download a file from the link and save the file to a temporary file. Downloading progress will be shown in a progress bar Parameters: url (str): URL desc (str): description to be shown on the progress bar Returns: temporary filename """ stream = progress_bar resp = requests.get(url, stream=stream) content_type = resp.headers.get('content-type') if content_type != 'binary/x-fits': logger.error(resp.content) return None folder = DOWNLOAD_PATH try: fname = resp.headers.get("Content-Disposition").split( "filename=")[1] except AttributeError: md5hex = hashlib.md5(url.encode('utf-8')).hexdigest() fname = f'{md5hex}.fits' filename = PurePath(folder, fname) file_path = Path(filename) if file_path.is_file(): logger.info(f'Found the data in local storage. Filename: {filename} ...') return str(file_path) f = open(filename, 'wb') chunk_size = 1024 total = int(resp.headers.get('content-length', 0)) with tqdm( desc=desc, total=total, unit='iB', unit_scale=True, unit_divisor=chunk_size, ) as bar: for data in resp.iter_content(chunk_size=chunk_size): size = f.write(data) bar.update(size) name = f.name f.close() return name
class FitsQueryResult (resp)
-
FITS query result manager
Expand source code
class FitsQueryResult(object): """ FITS query result manager """ def __init__(self, resp): self.hdu_objects = [] self.result = resp self.downloaded_fits_files = [] def __repr__(self): return str(self.result) def __getitem__(self, index): return self.result[index] def __getattr__(self, name): if name in ['num', 'len']: return len(self.result) elif name == 'hduls': return self.hdu_objects def __len__(self): return len(self.result) def to_pandas(self): """ Convert FitsQueryResult to pandas dataframe Returns: pandas data frame """ return pd.DataFrame(self.result) def open_fits(self): """ Open all the FITS files Returns: hdu_objcts: list A list of HDU objects """ self.hdu_objects = [] for filename in self.downloaded_fits_files: self.hdu_objects.append(fits.open(filename)) return self.hdu_objects def fits_info(self): """ Print out information of the loaded specified FITS files """ for hdu in self.hdu_objects: logger.info(hdu.info()) def get_fits_ids(self): """ Get FITS file IDs Return ids: list FITS file ids """ return [row['fits_id'] for row in self.result] def fetch(self): """ Download fits files from STIX data center FITS files will be stored in the folder download/ in the current directory Returns: fits_filenames: list List of downloaded FITS filenames """ if self.result: self.downloaded_fits_files = FitsQuery.fetch(self.result) return self.downloaded_fits_files else: logger.warning('WARNING: Nothing to be downloaded from stix data center!')
Methods
def fetch(self)
-
Download fits files from STIX data center FITS files will be stored in the folder download/ in the current directory
Returns:
fits_filenames: list List of downloaded FITS filenames
Expand source code
def fetch(self): """ Download fits files from STIX data center FITS files will be stored in the folder download/ in the current directory Returns: fits_filenames: list List of downloaded FITS filenames """ if self.result: self.downloaded_fits_files = FitsQuery.fetch(self.result) return self.downloaded_fits_files else: logger.warning('WARNING: Nothing to be downloaded from stix data center!')
def fits_info(self)
-
Print out information of the loaded specified FITS files
Expand source code
def fits_info(self): """ Print out information of the loaded specified FITS files """ for hdu in self.hdu_objects: logger.info(hdu.info())
def get_fits_ids(self)
-
Get FITS file IDs Return ids: list FITS file ids
Expand source code
def get_fits_ids(self): """ Get FITS file IDs Return ids: list FITS file ids """ return [row['fits_id'] for row in self.result]
def open_fits(self)
-
Open all the FITS files
Returns
hdu_objcts
- list A list of HDU objects
Expand source code
def open_fits(self): """ Open all the FITS files Returns: hdu_objcts: list A list of HDU objects """ self.hdu_objects = [] for filename in self.downloaded_fits_files: self.hdu_objects.append(fits.open(filename)) return self.hdu_objects
def to_pandas(self)
-
Convert FitsQueryResult to pandas dataframe
Returns
pandas data frame
Expand source code
def to_pandas(self): """ Convert FitsQueryResult to pandas dataframe Returns: pandas data frame """ return pd.DataFrame(self.result)
class JSONRequest
-
Request json format data from STIX data center
Expand source code
class JSONRequest(object): """Request json format data from STIX data center """ @staticmethod def post(url, form): response = requests.post(url, data=form) data = response.json() if 'error' in data: if data['error']: return None return data @staticmethod def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool): """ Request light curve from STIX data center Parameters: begin_utc: str Observation start time end_utc: str Observation end time ltc: bool, optional Light time correction enabling flag. Do light time correction if True Returns: lightcurve: dict A python dictionary containing light curve data """ form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc} url = ENDPOINTS['LC'] return JSONRequest.post(url, form) @staticmethod def fetch_housekeeping(begin_utc: str, end_utc: str): """Fetch housekeeping data from STIX data center Parameters: begin_utc: Data start time end_utc: data end time Returns: result: dict housekeeping data """ if not begin_utc.endswith('Z'): begin_utc += 'Z' if not end_utc.endswith('Z'): end_utc += 'Z' start_unix = dtparser.parse(begin_utc).timestamp() end_unix = dtparser.parse(end_utc).timestamp() duration = int(end_unix) - int(start_unix) form = { 'start_unix': start_unix, 'duration': duration, } url = ENDPOINTS['HK'] return JSONRequest.post(url, form) @staticmethod def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err): """compute flare location using the online flare location solver Parameters: cfl_counts: numpy array or list counts recorded by the 12 CFL pixels cfl_counts_err: numpy array or list standard deviations of the counts recorded by the 12 CFL pixels fluence: float X-ray fluence in units of counts/mm2, calculated using counts recorded by other detectors fluence_err: float Errors in fluence in counts/mm2 units Returns: location: dict CFL location, ephemeris and the chisquare map """ form = { 'counts': cfl_counts, 'counts_err': cfl_counts_err, 'fluence': fluence, 'fluence_err': fluence_err } url = ENDPOINTS['CFL_SOLVER'] return JSONRequest.post(url, form) @staticmethod def fetch_elut(utc): """Download ELUT from STIX data center Parameters: utc: Time Returns: dict object: a diction string containing elut information """ form = {'utc': utc} url = ENDPOINTS['ELUT'] return JSONRequest.post(url, form) @staticmethod def request_ephemeris(begin_utc: str, end_utc: str, steps=1): return JSONRequest.post(ENDPOINTS['EPHEMERIS'], { 'start_utc': begin_utc, 'end_utc': end_utc, 'steps': steps }) @staticmethod def request_pointing(utc: str): return JSONRequest.post(ENDPOINTS['STIX_POINTING'], { 'utc': utc, }) @staticmethod def request_attitude(begin_utc: str, end_utc: str, steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN'): form = { 'start_utc': begin_utc, 'end_utc': end_utc, 'steps': steps, 'frame1': instrument_frame, 'frame2': ref_frame } ret = JSONRequest.post(ENDPOINTS['ATTITUDE'], form) return ret @staticmethod def fetch_science_data(_id: int): """fetch science data from stix data center Parameters: _id: int science data unique ID, which can be found on STIX data center bulk science data web page Returns: science_data: dict science data received from data center if success or None if failed """ return JSONRequest.post(ENDPOINTS['SCIENCE'], { 'id': _id, }) @staticmethod def fetch_flare_list(begin_utc: str, end_utc: str, sort: str = 'time'): """ query and download flare list from stix data center Parameters: ------ begin_utc: str flare start UTC end_utc: str flare end UTC sort: str key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve Returns: ----- flare_list: dict or None flare list if success or None if failed. """ return JSONRequest.post(ENDPOINTS['FLARE_LIST'], { 'start_utc': begin_utc, 'end_utc': end_utc, 'sort': sort })
Static methods
def fetch_elut(utc)
-
Download ELUT from STIX data center
Parameters
utc: Time Returns: dict object: a diction string containing elut information
Expand source code
@staticmethod def fetch_elut(utc): """Download ELUT from STIX data center Parameters: utc: Time Returns: dict object: a diction string containing elut information """ form = {'utc': utc} url = ENDPOINTS['ELUT'] return JSONRequest.post(url, form)
def fetch_flare_list(begin_utc: str, end_utc: str, sort: str = 'time')
-
query and download flare list from stix data center
Parameters:
begin_utc: str flare start UTC end_utc: str flare end UTC sort: str key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve
Returns:
flare_list: dict or None flare list if success or None if failed.
Expand source code
@staticmethod def fetch_flare_list(begin_utc: str, end_utc: str, sort: str = 'time'): """ query and download flare list from stix data center Parameters: ------ begin_utc: str flare start UTC end_utc: str flare end UTC sort: str key to sort flares. It can be one of ['goes','time', 'LC0','LC1','LC2','LC3','LC4], LCi here means the i-th QL light curve Returns: ----- flare_list: dict or None flare list if success or None if failed. """ return JSONRequest.post(ENDPOINTS['FLARE_LIST'], { 'start_utc': begin_utc, 'end_utc': end_utc, 'sort': sort })
def fetch_housekeeping(begin_utc: str, end_utc: str)
-
Fetch housekeeping data from STIX data center
Parameters
begin_utc: Data start time end_utc: data end time
Returns
result
- dict
housekeeping data
Expand source code
@staticmethod def fetch_housekeeping(begin_utc: str, end_utc: str): """Fetch housekeeping data from STIX data center Parameters: begin_utc: Data start time end_utc: data end time Returns: result: dict housekeeping data """ if not begin_utc.endswith('Z'): begin_utc += 'Z' if not end_utc.endswith('Z'): end_utc += 'Z' start_unix = dtparser.parse(begin_utc).timestamp() end_unix = dtparser.parse(end_utc).timestamp() duration = int(end_unix) - int(start_unix) form = { 'start_unix': start_unix, 'duration': duration, } url = ENDPOINTS['HK'] return JSONRequest.post(url, form)
def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool)
-
Request light curve from STIX data center
Parameters
begin_utc: str Observation start time end_utc: str Observation end time ltc: bool, optional Light time correction enabling flag. Do light time correction if True
Returns
lightcurve
- dict A python dictionary containing light curve data
Expand source code
@staticmethod def fetch_light_curves(begin_utc: str, end_utc: str, ltc: bool): """ Request light curve from STIX data center Parameters: begin_utc: str Observation start time end_utc: str Observation end time ltc: bool, optional Light time correction enabling flag. Do light time correction if True Returns: lightcurve: dict A python dictionary containing light curve data """ form = {'begin': begin_utc, 'ltc': ltc, 'end': end_utc} url = ENDPOINTS['LC'] return JSONRequest.post(url, form)
def fetch_science_data(_id: int)
-
fetch science data from stix data center
Parameters
_id: int science data unique ID, which can be found on STIX data center bulk science data web page
Returns
science_data
- dict science data received from data center if success or None if failed
Expand source code
@staticmethod def fetch_science_data(_id: int): """fetch science data from stix data center Parameters: _id: int science data unique ID, which can be found on STIX data center bulk science data web page Returns: science_data: dict science data received from data center if success or None if failed """ return JSONRequest.post(ENDPOINTS['SCIENCE'], { 'id': _id, })
def post(url, form)
-
Expand source code
@staticmethod def post(url, form): response = requests.post(url, data=form) data = response.json() if 'error' in data: if data['error']: return None return data
def request_attitude(begin_utc: str, end_utc: str, steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN')
-
Expand source code
@staticmethod def request_attitude(begin_utc: str, end_utc: str, steps=1, instrument_frame='SOLO_SRF', ref_frame='SOLO_SUN_RTN'): form = { 'start_utc': begin_utc, 'end_utc': end_utc, 'steps': steps, 'frame1': instrument_frame, 'frame2': ref_frame } ret = JSONRequest.post(ENDPOINTS['ATTITUDE'], form) return ret
def request_ephemeris(begin_utc: str, end_utc: str, steps=1)
-
Expand source code
@staticmethod def request_ephemeris(begin_utc: str, end_utc: str, steps=1): return JSONRequest.post(ENDPOINTS['EPHEMERIS'], { 'start_utc': begin_utc, 'end_utc': end_utc, 'steps': steps })
def request_pointing(utc: str)
-
Expand source code
@staticmethod def request_pointing(utc: str): return JSONRequest.post(ENDPOINTS['STIX_POINTING'], { 'utc': utc, })
def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err)
-
compute flare location using the online flare location solver
Parameters
cfl_counts: numpy array or list counts recorded by the 12 CFL pixels cfl_counts_err: numpy array or list standard deviations of the counts recorded by the 12 CFL pixels fluence: float X-ray fluence in units of counts/mm2, calculated using counts recorded by other detectors fluence_err: float Errors in fluence in counts/mm2 units
Returns
location
- dict CFL location, ephemeris and the chisquare map
Expand source code
@staticmethod def solve_cfl(cfl_counts, cfl_counts_err, fluence, fluence_err): """compute flare location using the online flare location solver Parameters: cfl_counts: numpy array or list counts recorded by the 12 CFL pixels cfl_counts_err: numpy array or list standard deviations of the counts recorded by the 12 CFL pixels fluence: float X-ray fluence in units of counts/mm2, calculated using counts recorded by other detectors fluence_err: float Errors in fluence in counts/mm2 units Returns: location: dict CFL location, ephemeris and the chisquare map """ form = { 'counts': cfl_counts, 'counts_err': cfl_counts_err, 'fluence': fluence, 'fluence_err': fluence_err } url = ENDPOINTS['CFL_SOLVER'] return JSONRequest.post(url, form)