update: new table format (retrocompatible), bug correction and plotting ability

This commit is contained in:
Yael-II
2024-12-01 16:31:14 +01:00
parent d985b82d22
commit d5a01d2023
8 changed files with 540 additions and 192 deletions

View File

@@ -2,8 +2,10 @@
Astronomical Observation Tools (Astrobs Tools) is composed of: Astronomical Observation Tools (Astrobs Tools) is composed of:
- SCOPE: a code to get the sky coordinate limits from observation constraints; - SCOPE: a code to get the sky coordinate limits from observation constraints;
- EQUATOR: a software to organize targets before observations. - EQUATOR: a software to organize targets before observations;
and the following extractors:
- HPMS: High Proper Motion Stars (Simbad Extractor);
- NGC: New General Catalogue (VizieR Extractor);
## Requirements ## Requirements
@@ -57,24 +59,19 @@ Then, select the action you wish to perform.
Available commands (not case sensitive): Available commands (not case sensitive):
- `help`, `h`, `?`: show this page - `help`, `h`, `?`: show this page
- `quit`, `exit`, `q`: quit the current code - `quit`, `exit`, `q`: quit the current code (WARNING: this does not save the current state!)
(WARNING: this does not save the current state!)
- `write`, `save`: write the current table in a file - `write`, `save`: write the current table in a file
(no options available yet) (no options available yet)
- `read [filename]`, `open [filename]`: loads the file "filename" - `read [filename]`, `open [filename]`, `load`: loads the file "filename" in the current table (no additional options available yet)
in the current table (no additional options available yet)
- `calibration`, `calib`: adds a calibration in the target list - `calibration`, `calib`: adds a calibration in the target list
- `simbad [object name]`, `object [object name]`: - `simbad [object name]`, `object [object name]`:
add an object from simbad add an object from simbad
- `search [ra] [dec] [radius]`, `region [ra] [dec] [radius]`: - `search [ra] [dec] [radius]`, `region [ra] [dec] [radius]`: search a region centred on the ra/dec coordinates, with a given radius (ra is given in hour, dec in degree and the radius is any specified unit,, e.g. `search 01:03:40 35:40:20 30'`)
search a region centred on the ra/dec coordinates,
with a given radius (coordinates should be expressed as
`12h30m30s`, `90d30m30s` or `90.555d`)
- `manual [name] -s [seq]`, `add [name] -s [seq]`: manually add a target (only the name and the sequence are available for now) - `manual [name] -s [seq]`, `add [name] -s [seq]`: manually add a target (only the name and the sequence are available for now)
- `sidereal`, `st`: computes the sidereal time for each target
- `sequence`, `seq`: computes the sequence order for each - `sequence`, `seq`: computes the sequence order for each
target target
- `check`: check if all targets are in the observation field - `check`: check if all targets are in the observation field
- plot, graph: creates a graph with all the targets observation date and time
General actions: General actions:
- `cancel`, `back`: cancels the current action - `cancel`, `back`: cancels the current action
@@ -82,3 +79,7 @@ General actions:
- `no`, `n`, `0`, or anything else: no - `no`, `n`, `0`, or anything else: no
- `all`, `*`: select all - `all`, `*`: select all
- `done`, `ok`: confirm, save the current state and quit - `done`, `ok`: confirm, save the current state and quit
## Extractors (HPMS, NGC)
Extractors are small codes to query databases in order to extract a table of potential targets. Using them is often straightforward, and their result is always written in the `Output/` directory.

View File

@@ -1,10 +1,14 @@
import SCOPE_v2_2 import SCOPE_v2_2
import EQUATOR_v1_1 import EQUATOR_v1_1
import HPMS_v1
import NGC_v1
QUIT = ["QUIT", "EXIT", "Q"] QUIT = ["QUIT", "EXIT", "Q"]
DONE = ["DONE", "OK"] DONE = ["DONE", "OK"]
SCOPE = ["SCOPE", "S", "1"] SCOPE = ["SCOPE", "S", "1"]
EQUATOR = ["EQUATOR", "E", "2"] EQUATOR = ["EQUATOR", "E", "2"]
HPMS = ["HPMS", "H", "3"]
NGC = ["NGC", "N", "4"]
stop = False stop = False
first = True first = True
@@ -28,6 +32,14 @@ while not stop:
+ "\tEQUATOR: " + "\tEQUATOR: "
+ "\033[0m" + "\033[0m"
+ "Equator Queries simbAd to create Tables of Objects") + "Equator Queries simbAd to create Tables of Objects")
print("\033[32m"
+ "\tHPMS: "
+ "\033[0m"
+ "High Proper Motion Stars (Simbad Extractor)")
print("\033[32m"
+ "\tNGC: "
+ "\033[0m"
+ "New General Catalogue (VizieR Extractor)")
choice = input("\033[32m" + "Choice: " + "\033[0m") choice = input("\033[32m" + "Choice: " + "\033[0m")
if choice.upper() in DONE + ["", " "]: if choice.upper() in DONE + ["", " "]:
@@ -44,6 +56,18 @@ while not stop:
+"\033[0m") +"\033[0m")
first = True first = True
EQUATOR_v1_1.main() EQUATOR_v1_1.main()
elif choice.upper() in HPMS:
print("\033[35m"
+ "{:^80}".format("=== [ HPMS (Simbad Extractor) ] ===")
+"\033[0m")
first = True
HPMS_v1.main()
elif choice.upper() in NGC:
print("\033[35m"
+ "{:^80}".format("=== [ NGC (VizieR Extractor) ] ===")
+"\033[0m")
first = True
NGC_v1.main()
elif choice.upper() in QUIT: elif choice.upper() in QUIT:
stop = True stop = True
else: else:

View File

@@ -50,7 +50,7 @@ def main():
if ans.upper() in QUIT: if ans.upper() in QUIT:
stop = True stop = True
toolbox.resolve_input(ans, targets, config) toolbox.resolve_input(ans, targets, config)
targets.pprint() targets.pprint_all()
return 0 return 0
if __name__ == "__main__": if __name__ == "__main__":

104
Source/HPMS_v1.py Normal file
View File

@@ -0,0 +1,104 @@
import os
from astroquery.simbad import Simbad
from astrobs_v1_toolbox import read_cfg
OUT_DIR = "./Output/"
QUIT = ["QUIT", "EXIT", "Q"]
def get_HPMS(filename: str,
directory: str = OUT_DIR,
extension: str = ".cfg",
pm_max: float = 800.0,
pm_min: float = 30.0,
mag_max: float = 8.5,
mag_min: float = 13.0) -> tuple:
config = read_cfg(filename, directory, extension)
date = config["SUN_SET"][:10]
constraint = config["CONSTRAINT"]
loc = config["LOCATION"]
query_hpms_high = """SELECT TOP 20
main_id,
ra,
dec,
pmra,
pmdec,
SQRT(pmra*pmra + pmdec*pmdec) as "PM",
filter,
flux
FROM basic JOIN flux ON oid=oidref
WHERE {where}
AND SQRT(pmra*pmra + pmdec*pmdec) > {pm}
AND flux > {mag_max} AND flux < {mag_min}
AND filter='V'
ORDER BY "PM" DESC;
""".format(where = constraint,
pm = pm_max,
mag_max = mag_max,
mag_min = mag_min)
query_hpms_low = """SELECT TOP 20
main_id,
ra,
dec,
pmra,
pmdec,
SQRT(pmra*pmra + pmdec*pmdec) as "PM",
filter,
flux
FROM basic JOIN flux ON oid=oidref
WHERE {where}
AND SQRT(pmra*pmra + pmdec*pmdec) > {pm}
AND flux > {mag_max} AND flux < {mag_min}
AND filter='V'
ORDER BY "PM" ASC;
""".format(where = constraint,
pm = pm_min,
mag_max = mag_max,
mag_min = mag_min)
hpms_high = Simbad.query_tap(query_hpms_high)
hpms_low = Simbad.query_tap(query_hpms_low)
hpms_high.write("{}{}_{}_hpms_high.xml".format(directory, date, loc),
format="votable",
overwrite=True)
hpms_low.write("{}{}_{}_hpms_low.xml".format(directory, date, loc),
format="votable",
overwrite=True)
print("\033[36m" + "High Proper Motion Stars: Highest 20" + "\033[0m")
hpms_high.pprint()
print("\033[36m" + "High Proper Motion Stars: Limiting 20" + "\033[0m")
hpms_low.pprint()
return 0
def main(directory: str = OUT_DIR,
extension: str = ".cfg") -> tuple:
filelist = [fname for fname in os.listdir(directory) if extension in fname]
print("\033[32m"
+ "Select a configuration"
+ "\033[0m")
for i in range(len(filelist)):
print("\033[32m"
+ "\t{}. ".format(i+1)
+ "\033[0m"
+ "{}".format(filelist[i][:-4]))
try:
answer = input("\033[32m" + "Choice: " + "\033[0m")
if answer in QUIT:
return 0
selection = int(answer) - 1
filename = filelist[selection][:-4]
except Exception as e:
print("\033[91m"
+ ("Error! Input value not recognized, "
"selected the last location instead")
+ "\033[0m")
selection = -1
filename = filelist[selction][:-4]
get_HPMS(filename)
return None
if __name__ == "__main__":
main()

107
Source/NGC_v1.py Normal file
View File

@@ -0,0 +1,107 @@
import os
from astroquery.vizier import Vizier
from astrobs_v1_toolbox import read_cfg, create_table
import astropy.coordinates as coord
import astropy.units as u
OUT_DIR = "./Output/"
QUIT = ["QUIT", "EXIT", "Q"]
obj_type_list = """\t\033[32m1. \033[0mOpen Cluster
\t\033[32m2. \033[0mGlobular Cluster
\t\033[32m3. \033[0mDiffuse Nebula
\t\033[32m4. \033[0mPlanetary Nebula 9 Object in Small Magellanic Cloud
\t\033[32m5. \033[0mGalaxy
\t\033[32m6. \033[0mCluster associated with nebulosity
\t\033[32m7. \033[0mNon existent
\t\033[32m8. \033[0mObject in Large Magellanic Cloud
\t\033[32m0. \033[0mUnverified southern object
\t\033[32m(blank). \033[0mAny"""
def get_NGC(filename: str,
obj_type: int = None,
directory: str = OUT_DIR,
extension: str = ".cfg"):
if obj_type == None:
obj_type = ">0"
Vizier.clear_cache()
config = read_cfg(filename, directory, extension)
date = config["SUN_SET"][:10]
loc = config["LOCATION"]
NGC = Vizier(catalog="VII/1B",
columns=["NGC", "Type", "_RAJ2000", "_DEJ2000", "+Mag"])
objects = NGC.query_constraints(RA1975 = config["RA_CONST"],
DE1975 = config["DE_CONST"],
Mag = "<999",
Type = str(obj_type))[0]
table = create_table()
for i in range(len(objects)):
mag = "Mag: {}".format(objects["Mag"][i])
ra = "{}".format(coord.Angle(objects["_RAJ2000"][i],
unit=u.degree).to_string(u.hourangle,
sep=":",
pad=True))
dec = "{}".format(coord.Angle(objects["_DEJ2000"][i],
unit=u.degree).to_string(u.degree,
alwayssign=True,
sep=":",
pad=True))
name = "NGC {}".format(objects["NGC"][i])
table.add_row({"seq": 0,
"name": name,
"main_id": name,
"ra": ra,
"dec": dec,
"notes": mag})
table.write("{}{}_{}_ngc.xml".format(directory, date, loc),
format="votable",
overwrite=True)
table.pprint()
return None
def main(directory: str = OUT_DIR,
extension: str = ".cfg") -> tuple:
filelist = [fname for fname in os.listdir(directory) if extension in fname]
print("\033[32m"
+ "Select a configuration"
+ "\033[0m")
for i in range(len(filelist)):
print("\033[32m"
+ "\t{}. ".format(i+1)
+ "\033[0m"
+ "{}".format(filelist[i][:-4]))
try:
answer = input("\033[32m" + "Choice: " + "\033[0m")
if answer in QUIT:
return 0
selection = int(answer) - 1
filename = filelist[selection][:-4]
except Exception as e:
print("\033[91m"
+ ("Error! Input value not recognized, "
"selected the last location instead")
+ "\033[0m")
selection = -1
filename = filelist[selction][:-4]
print("\033[32m"
+ "Select a type of object"
+ "\033[0m")
print("\033[32m" + obj_type_list + "\033[32m")
try:
answer = input("\033[32m" + "Choice: " + "\033[0m")
if answer in QUIT:
return 0
if answer in [" ", ""]:
obj_type = None
obj_type = int(answer)
except Exception as e:
obj_type = None
get_NGC(filename, obj_type)
return 0
if __name__ == "__main__":
main()

View File

@@ -257,6 +257,26 @@ def main():
else: else:
comp_symb = "||" comp_symb = "||"
comp_text = "OR" comp_text = "OR"
constraint = ("((ra < {} {} ra > {})"
" AND "
"(dec < {} AND dec > {}))").format(
a_west.degree,
comp_text,
a_east.degree,
dec_upper.degree,
dec_lower.degree)
ra_const = "< " \
+ a_west.to_string(unit=u.hourangle, sep=":", pad=True) \
+ " {} ".format(comp_symb) \
+ "> " \
+ a_east.to_string(unit=u.hourangle, sep=":", pad=True)
de_const = "< " \
+ dec_upper.to_string(unit=u.degree, sep=":", pad=True) \
+ " && " \
+ "> " \
+ dec_lower.to_string(unit=u.degree, sep=":", pad=True)
# * Output # * Output
print("") print("")
print("\033[36m" print("\033[36m"
@@ -266,11 +286,11 @@ def main():
print("\033[36m" print("\033[36m"
+ "\tlat: " + "\tlat: "
+ "\033[0m" + "\033[0m"
+ obs_lat.to_string()) + obs_lat.to_string(unit=u.degree))
print("\033[36m" print("\033[36m"
+ "\tlon: " + "\tlon: "
+ "\033[0m" + "\033[0m"
+ obs_lon.to_string()) + obs_lon.to_string(unit=u.degree))
print("\033[36m" print("\033[36m"
+ "Observation" + "Observation"
+ "\033[0m") + "\033[0m")
@@ -285,63 +305,66 @@ def main():
print("\033[36m" print("\033[36m"
+ "\tbegin sidereal time: " + "\tbegin sidereal time: "
+ "\033[0m" + "\033[0m"
+ st.to_string(unit=u.hour)) + st.to_string(unit=u.hourangle,
sep=":",
pad=True))
print("\033[36m" print("\033[36m"
+ "\t end sidereal time: " + "\t end sidereal time: "
+ "\033[0m" + "\033[0m"
+ (st + obs_sky_rotation).wrap_at(24*u.h).to_string(unit=u.hour)) + (st + obs_sky_rotation).wrap_at(24*u.h).to_string(unit=u.hour,
sep=":",
pad=True))
print("\033[36m" print("\033[36m"
+ "\t sky rotation: " + "\t sky rotation: "
+ "\033[0m" + "\033[0m"
+ obs_sky_rotation.to_string(unit=u.hour)) + obs_sky_rotation.to_string(unit=u.hourangle,
sep=":",
pad=True))
print("\033[36m" print("\033[36m"
+ "Sky coordinates window" + "Sky coordinates window"
+ "\033[0m") + "\033[0m")
print("\033[36m" print("\033[36m"
+ "\t east ra: " + "\t east ra: "
+ "\033[0m" + "\033[0m"
+ a_east.to_string(unit=u.hour)) + a_east.to_string(unit=u.hourangle,
sep=":",
pad=True))
print("\033[36m" print("\033[36m"
+ "\t west ra: " + "\t west ra: "
+ "\033[0m" + "\033[0m"
+ a_west.to_string(unit=u.hour)) + a_west.to_string(unit=u.hourangle,
sep=":",
pad=True))
print("\033[36m" print("\033[36m"
+ "\tupper dec: " + "\tupper dec: "
+ "\033[0m" + "\033[0m"
+ dec_upper.to_string(unit=u.degree)) + dec_upper.to_string(unit=u.degree,
sep=":",
pad=True,
alwayssign=True))
print("\033[36m" print("\033[36m"
+ "\tlower dec: " + "\tlower dec: "
+ "\033[0m" + "\033[0m"
+ dec_lower.to_string(unit=u.degree)) + dec_lower.to_string(unit=u.degree,
sep=":",
pad=True,
alwayssign=True))
print("\033[36m" print("\033[36m"
+ "Simbad query constraints: " + "Simbad query constraints: "
+ "\033[0m" + "\033[0m"
+ "WHERE (ra < {} {} ra > {}) AND (dec < {} AND dec > {}))".format( + "WHERE "
a_west.degree, + constraint)
comp_text,
a_east.degree,
dec_upper.degree,
dec_lower.degree))
print("\033[36m" print("\033[36m"
+ "Vizier query constraints:" + "Vizier query constraints:"
+ "\033[0m") + "\033[0m")
print("\033[36m" print("\033[36m"
+ "\tRA: " + "\tRA: "
+ "\033[0m" + "\033[0m"
+ "< " + ra_const)
+ a_west.to_string(unit=u.hour, sep=":")
+ " {} ".format(comp_symb)
+ "> "
+ a_east.to_string(unit=u.hour, sep=":"))
print("\033[36m" print("\033[36m"
+ "\tDE: " + "\tDE: "
+ "\033[0m" + "\033[0m"
+ "< " + de_const)
+ dec_upper.to_string(unit=u.degree, sep=":")
+ " && "
+ "> "
+ dec_lower.to_string(unit=u.degree, sep=":"))
print("") print("")
print("\033[32m" print("\033[32m"
+ "Write output to file ? [yes/no]" + "Write output to file ? [yes/no]"
@@ -357,9 +380,9 @@ def main():
file.write("LOCATION: ") file.write("LOCATION: ")
file.write(obs_short + "\n") file.write(obs_short + "\n")
file.write("LAT: ") file.write("LAT: ")
file.write(obs_lat.to_string() + "\n") file.write(obs_lat.to_string(unit=u.degree) + "\n")
file.write("LON: ") file.write("LON: ")
file.write(obs_lon.to_string() + "\n") file.write(obs_lon.to_string(unit=u.degree) + "\n")
file.write("SUN_SET: ") file.write("SUN_SET: ")
file.write(sun_set.to_string() + "\n") file.write(sun_set.to_string() + "\n")
file.write("SUN_SET_CIVIL: ") file.write("SUN_SET_CIVIL: ")
@@ -381,18 +404,39 @@ def main():
file.write("OBS_END: ") file.write("OBS_END: ")
file.write(obs_end_time.to_string() + "\n") file.write(obs_end_time.to_string() + "\n")
file.write("ST_BEGIN: ") file.write("ST_BEGIN: ")
file.write(st.to_string(unit=u.hour) + "\n") file.write(st.to_string(unit=u.hourangle,
sep=":",
pad=True) + "\n")
file.write("ST_END: ") file.write("ST_END: ")
file.write((st + obs_sky_rotation).wrap_at( file.write((st + obs_sky_rotation).wrap_at(
24*u.h).to_string(unit=u.hour) + "\n") 24*u.h).to_string(unit=u.hourangle,
sep=":",
pad=True) + "\n")
file.write("WINDOW_EAST: ") file.write("WINDOW_EAST: ")
file.write(a_east.to_string(unit=u.hour) + "\n") file.write(a_east.to_string(unit=u.hourangle,
sep=":",
pad=True) + "\n")
file.write("WINDOW_WEST: ") file.write("WINDOW_WEST: ")
file.write(a_west.to_string(unit=u.hour) + "\n") file.write(a_west.to_string(unit=u.hourangle,
sep=":",
pad=True) + "\n")
file.write("WINDOW_UPPER: ") file.write("WINDOW_UPPER: ")
file.write(dec_upper.to_string(unit=u.degree) + "\n") file.write(dec_upper.to_string(unit=u.degree,
sep=":",
pad=True,
alwayssign=True) + "\n")
file.write("WINDOW_LOWER: ") file.write("WINDOW_LOWER: ")
file.write(dec_lower.to_string(unit=u.degree) + "\n") file.write(dec_lower.to_string(unit=u.degree,
sep=":",
pad=True,
alwayssign=True) + "\n")
file.write("CONSTRAINT: ")
file.write(constraint + "\n")
file.write("RA_CONST: ")
file.write(ra_const + "\n")
file.write("DE_CONST: ")
file.write(de_const + "\n")
print("\033[34m" print("\033[34m"
+ "File saved in the {} directory ".format(OUT_DIR) + "File saved in the {} directory ".format(OUT_DIR)
+ "with the name {}_{}.cfg".format(obs_date, obs_short) + "with the name {}_{}.cfg".format(obs_date, obs_short)

View File

@@ -5,6 +5,7 @@
@ Observatory of Strasbourg @ Observatory of Strasbourg
""" """
import numpy as np import numpy as np
import matplotlib.pyplot as plt
import astropy.time as time import astropy.time as time
import astropy.coordinates as coord import astropy.coordinates as coord
import astropy.units as u import astropy.units as u
@@ -18,7 +19,7 @@ DONE = ["DONE", "OK"]
QUIT = ["QUIT", "EXIT", "Q"] QUIT = ["QUIT", "EXIT", "Q"]
CANCEL = ["CANCEL", "BACK", "UNDO"] CANCEL = ["CANCEL", "BACK", "UNDO"]
WRITE = ["WRITE", "SAVE"] WRITE = ["WRITE", "SAVE"]
READ = ["READ", "OPEN"] READ = ["READ", "OPEN", "LOAD"]
CALIB = ["CALIB", "CALIBRATION"] CALIB = ["CALIB", "CALIBRATION"]
SIMBAD = ["SIMBAD", "OBJECT"] SIMBAD = ["SIMBAD", "OBJECT"]
REGION = ["SEARCH", "REGION"] REGION = ["SEARCH", "REGION"]
@@ -26,9 +27,12 @@ MANUAL = ["MANUAL", "ADD"]
ST = ["SIDEREAL", "ST"] ST = ["SIDEREAL", "ST"]
SEQ = ["SEQUENCE", "SEQ"] SEQ = ["SEQUENCE", "SEQ"]
CHECK = ["CHECK"] CHECK = ["CHECK"]
PLOT = ["PLOT", "GRAPH"]
HELP = ["HELP", "H", "?"] HELP = ["HELP", "H", "?"]
FIGURE_DPI = 100
OUT_DIR = "./Output/" OUT_DIR = "./Output/"
DEFAULT_CONFIG = """# Default config DEFAULT_CONFIG = """# Default config
LOCATION: None LOCATION: None
LAT: 0d00m00s LAT: 0d00m00s
@@ -45,10 +49,11 @@ OBS_BEGIN: 1970-01-01 12:00:00.000
OBS_END: 1970-01-01 12:00:00.000 OBS_END: 1970-01-01 12:00:00.000
ST_BEGIN: 12h00m0s ST_BEGIN: 12h00m0s
ST_END: 12h00m00s ST_END: 12h00m00s
WINDOW_EAST: 0h00m00s WINDOW_EAST: 00:00:00.0
WINDOW_WEST: 23h59m59s WINDOW_WEST: 23:59:59.9
WINDOW_UPPER: 90d00m00s WINDOW_UPPER: +90:00:00.0
WINDOW_LOWER: -90d00m00s WINDOW_LOWER: -90:00:00.0
CONSTRAINT: ' ' LIKE ' '
""" """
COLS = ["seq", COLS = ["seq",
@@ -56,10 +61,6 @@ COLS = ["seq",
"main_id", "main_id",
"ra", "ra",
"dec", "dec",
"n_exp",
"t_exp",
"st_begin",
"st_end",
"notes"] "notes"]
UNITS = ["", # SEQ UNITS = ["", # SEQ
@@ -67,10 +68,6 @@ UNITS = ["", # SEQ
"", # MAIN_ID "", # MAIN_ID
"h", # RA "h", # RA
"deg", # DEC "deg", # DEC
"", # N_EXP
"s", # T_EXP
"h", # ST_BEGIN
"deg", # ST_END
""] ""]
TYPES = [np.int_, # SEQ TYPES = [np.int_, # SEQ
@@ -78,10 +75,6 @@ TYPES = [np.int_, # SEQ
np.str_("<U64"), # MAIN_ID np.str_("<U64"), # MAIN_ID
coord.angles.core.Angle, # RA coord.angles.core.Angle, # RA
coord.angles.core.Angle, # DEC coord.angles.core.Angle, # DEC
np.int_, # N_EXP
u.quantity.Quantity, # T_EXP
coord.angles.core.Angle, # ST_BEGIN
coord.angles.core.Angle, # ST_END
np.str_("<U512")] np.str_("<U512")]
def check_window(table: Table, def check_window(table: Table,
@@ -106,12 +99,12 @@ def check_window(table: Table,
return True return True
if line["dec"] == "": if line["dec"] == "":
return True return True
ra = coord.Angle(line["ra"]) ra = coord.Angle(line["ra"], unit=u.hourangle)
dec = coord.Angle(line["dec"]) dec = coord.Angle(line["dec"], unit=u.degree)
east = coord.Angle(config["WINDOW_EAST"]) east = coord.Angle(config["WINDOW_EAST"], unit=u.hourangle)
west = coord.Angle(config["WINDOW_WEST"]) west = coord.Angle(config["WINDOW_WEST"], unit=u.hourangle)
upper = coord.Angle(config["WINDOW_UPPER"]) upper = coord.Angle(config["WINDOW_UPPER"], unit=u.degree)
lower = coord.Angle(config["WINDOW_LOWER"]) lower = coord.Angle(config["WINDOW_LOWER"], unit=u.degree)
if east <= west: if east <= west:
if ra < east or ra > west: if ra < east or ra > west:
print("\033[93m" print("\033[93m"
@@ -213,7 +206,7 @@ def select_obj(table: Table,
elif answer in HELP: elif answer in HELP:
print("") print("")
print_help() print_help()
elif answer in ALL: elif answer.upper() in ALL:
for i in range(len(line)): for i in range(len(line)):
name = line[i]["name"] name = line[i]["name"]
while name in table["name"]: while name in table["name"]:
@@ -247,10 +240,6 @@ def add_manual(table: Table,
main_id: np.str_ = "", main_id: np.str_ = "",
ra: coord.angles.core.Angle = None, ra: coord.angles.core.Angle = None,
dec: coord.angles.core.Angle = None, dec: coord.angles.core.Angle = None,
n_exp: np.int_ = 0,
t_exp: u.quantity.Quantity = 0*u.s,
obj_begin: coord.angles.core.Angle = None,
obj_end: coord.angles.core.Angle = None,
notes: np.str_ = "") -> Table: notes: np.str_ = "") -> Table:
""" """
This function allows the user to add manually an entry to the table. This function allows the user to add manually an entry to the table.
@@ -270,34 +259,25 @@ def add_manual(table: Table,
obj_end_str = "" obj_end_str = ""
if type(ra) == coord.angles.core.Angle: if type(ra) == coord.angles.core.Angle:
ra_str = ra.to_string(unit=u.hour) ra_str = ra.to_string(unit=u.hourangle,
sep=":",
pad=True)
elif type(ra) == str: elif type(ra) == str:
ra_str = ra ra_str = ra
if type(dec) == coord.angles.core.Angle: if type(dec) == coord.angles.core.Angle:
dec_str = dec.to_string(unit=u.degree) dec_str = dec.to_string(unit=u.degree,
sep=":",
pad=True,
alwayssign=True)
elif type(dec) == str: elif type(dec) == str:
dec_str = dec dec_str = dec
if type(obj_begin) == coord.angles.core.Angle:
obj_begin_str = obj_begin.to_string()
elif type(obj_begin) == str:
obj_begin_str = obj_begin
if type(obj_end) == coord.angles.core.Angle:
obj_end_str = obj_end.to_string()
elif type(obj_end) == str:
obj_end_str = obj_end
table.add_row([seq, table.add_row([seq,
name, name,
main_id, main_id,
ra_str, ra_str,
dec_str, dec_str,
n_exp,
t_exp.to_value(u.s),
obj_begin_str,
obj_end_str,
notes]) notes])
check_window(table, config, -1) check_window(table, config, -1)
return table return table
@@ -306,8 +286,6 @@ def add_calib(table: Table,
config: dict = None, config: dict = None,
seq: np.int_ = 0, seq: np.int_ = 0,
name: np.str_ = "CALIB", name: np.str_ = "CALIB",
n_exp: np.int_ = 0,
t_exp: u.quantity.Quantity = 0*u.s,
notes: np.str_ = "") -> Table: notes: np.str_ = "") -> Table:
""" """
Add a calibration line to the table. Add a calibration line to the table.
@@ -329,8 +307,6 @@ def add_calib(table: Table,
"CALIBRATION", "CALIBRATION",
"", "",
"", "",
n_exp,
t_exp.to_value(u.s),
"", "",
"", "",
notes]) notes])
@@ -342,10 +318,6 @@ def add_simbad(table: Table,
config: dict, config: dict,
seq: np.int_ = 0, seq: np.int_ = 0,
name: np.str_ = "", name: np.str_ = "",
n_exp: np.int_ = 0,
t_exp: u.quantity.Quantity = 0*u.s,
obj_begin: coord.angles.core.Angle = None,
obj_end: coord.angles.core.Angle = None,
notes: np.str_ = "") -> Table: notes: np.str_ = "") -> Table:
""" """
Add a target imported from Simbad using astroquery.Simbad: Add a target imported from Simbad using astroquery.Simbad:
@@ -377,38 +349,26 @@ def add_simbad(table: Table,
except KeyError: except KeyError:
ra = coord.Angle(obj["RA"][i], unit=u.degree) ra = coord.Angle(obj["RA"][i], unit=u.degree)
dec = coord.Angle(obj["DEC"][i], unit=u.degree) dec = coord.Angle(obj["DEC"][i], unit=u.degree)
ra_str = ra.to_string(unit=u.hour) ra_str = ra.to_string(unit=u.hourangle,
dec_str = dec.to_string(unit=u.degree) sep=":",
obj_begin_str = "" pad=True)
obj_end_str = "" dec_str = dec.to_string(unit=u.degree,
sep=":",
if type(obj_begin) == coord.angles.core.Angle: pad=True,
obj_begin_str = obj_begin.to_string() alwayssign=True)
elif type(obj_begin) == str:
obj_begin_str = obj_begin
if type(obj_end) == coord.angles.core.Angle:
obj_end_str = obj_end.to_string()
elif type(obj_end) == str:
obj_end_str = obj_end
table.add_row([seq, table.add_row([seq,
name, name,
main_id, main_id,
ra_str, ra_str,
dec_str, dec_str,
n_exp,
t_exp.to_value(u.s),
obj_begin_str,
obj_end_str,
notes]) notes])
name = "" name = ""
check_window(table, config) check_window(table, config)
return table return table
def read_cfg(filename:str, def read_cfg(filename: str,
directory:str = OUT_DIR, directory: str = OUT_DIR,
extension:str = ".cfg") -> dict: extension: str = ".cfg") -> dict:
""" """
Read the configuration file Read the configuration file
@params: @params:
@@ -450,31 +410,6 @@ def read_cfg(filename:str,
for i in range(len(params_index))} for i in range(len(params_index))}
return config return config
def set_st_window(table: Table,
config: dict):
"""
This function computes the sidereal time window of observation for all
targets in the table, assuming an observation around the meridian.
@params:
- table: the target table
- config: the configuration dictionary
@return:
- table: the updated table
"""
before = coord.Angle(config["ST_BEGIN"]) \
- coord.Angle(config["WINDOW_EAST"])
after = coord.Angle(config["WINDOW_WEST"]) \
- coord.Angle(config["ST_END"])
for i in range(len(table)):
if not table[i]["main_id"] in SPECIAL:
table[i]["st_begin"] = (coord.Angle(table[i]["ra"]) \
- before).wrap_at(24*u.h).to_string()
table[i]["st_end"] = (coord.Angle(table[i]["ra"]) \
+ after).wrap_at(24*u.h).to_string()
else:
continue
return table
def set_seq(table: str, def set_seq(table: str,
config: dict, config: dict,
stack: bool = False): stack: bool = False):
@@ -485,12 +420,13 @@ def set_seq(table: str,
@params: @params:
- table: the target table - table: the target table
- config: the configuration dictionary - config: the configuration dictionary
- stack: if True, the first target is indexed with 1 (the last target is indexed with -1, if necessary) - stack: if True, the first target is indexed with 1
(the last target is indexed with -1, if necessary)
@returns: @returns:
- table: the updated table - table: the updated table
""" """
window_east = coord.Angle(config["WINDOW_EAST"]).degree window_east = coord.Angle(config["WINDOW_EAST"], unit=u.hourangle).degree
window_west = coord.Angle(config["WINDOW_WEST"]).degree window_west = coord.Angle(config["WINDOW_WEST"], unit=u.hourangle).degree
dupl_seq = np.argwhere( dupl_seq = np.argwhere(
np.unique(table["seq"], return_counts=True)[1] > 1).flatten() np.unique(table["seq"], return_counts=True)[1] > 1).flatten()
index_dupl = np.argwhere(np.any( index_dupl = np.argwhere(np.any(
@@ -508,23 +444,13 @@ def set_seq(table: str,
order_table = table[index] order_table = table[index]
table["seq"][index] = np.full(len(index), 0) table["seq"][index] = np.full(len(index), 0)
order_table.add_columns( order_table.add_columns(
[coord.Angle(order_table["ra"]).degree], [coord.Angle(order_table["ra"], unit=u.hourangle).degree],
names=["RA_DEG"]) names=["ra_deg"])
if window_east <= window_west: w_before = np.argwhere(order_table["ra_deg"] < window_east)
order_table.sort("RA_DEG")
else : order_table["ra_deg"][w_before] += 360
w1 = np.argwhere( order_table.sort("ra_deg")
order_table["RA_DEG"] > (window_east + window_west)/2)
w2 = np.argwhere(
order_table["RA_DEG"] <= (window_east + window_west)/2)
order = np.zeros(len(order_table))
order[w1] = 1
order[w2] = 2
order_table.add_columns(
[order],
names=["ORDER"])
order_table.sort("RA_DEG")
order_table.sort("ORDER")
i = 0 i = 0
seq = 0 seq = 0
while i < len(order_table): while i < len(order_table):
@@ -654,28 +580,33 @@ def read_table(filename: str,
format=format_) format=format_)
for i in range(len(data)): for i in range(len(data)):
line = data[i] line = data[i]
if "seq" in line.columns: seq = int(line["seq"])
else: seq=0
if "name" in line.columns: name = line["name"] if "name" in line.columns: name = line["name"]
else: name = "{}_{}".format(filename, i) else: name = "{}_{}".format(filename, i)
if "main_id" in line.columns: main_id = line["main_id"] if "main_id" in line.columns: main_id = line["main_id"]
else: main_id = name else: main_id = name
if "ra" in line.columns: if "ra" in line.columns:
if "h" not in str(line["ra"]): if ":" not in str(line["ra"]) \
ra = coord.Angle("{}d".format(line["ra"])).to_string(unit=u.hour) and str(line["ra"]).upper() not in ["", " ", "NONE"]:
ra = coord.Angle("{}d".format(line["ra"])).to_string(
unit=u.hourangle,
sep=":",
pad=True
)
else: ra = line["ra"] else: ra = line["ra"]
else: ra = "" else: ra = ""
if "dec" in line.columns: if "dec" in line.columns:
if "d" not in str(line["dec"]): if ":" not in str(line["dec"]) \
dec = coord.Angle("{}d".format(line["dec"])).to_string(unit=u.degree) and str(line["dec"]).upper() not in ["", " ", "NONE"]:
dec = coord.Angle("{}d".format(line["dec"])).to_string(
unit=u.degree,
sep=":",
pad=True,
alwayssign=True
)
else: dec = line["dec"] else: dec = line["dec"]
else: dec = "" else: dec = ""
if "n_exp" in line.columns: n_exp = line["n_exp"]
else: n_exp = 0
if "t_exp" in line.columns: t_exp = line["t_exp"]
else: t_exp = 0.
if "st_begin" in line.columns: st_begin = line["st_begin"]
else: st_begin = ""
if "st_end" in line.columns: st_end = line["st_end"]
else: st_end = ""
if "notes" in line.columns: notes = line["notes"] if "notes" in line.columns: notes = line["notes"]
else: notes = "" else: notes = ""
while name in table["name"]: while name in table["name"]:
@@ -685,15 +616,11 @@ def read_table(filename: str,
if col not in COLS: if col not in COLS:
notes += " & {}: {}".format(col, line[col]) notes += " & {}: {}".format(col, line[col])
table.add_row({"seq": 0, table.add_row({"seq": seq,
"name": name, "name": name,
"main_id": main_id, "main_id": main_id,
"ra": ra, "ra": ra,
"dec": dec, "dec": dec,
"n_exp": n_exp,
"t_exp": t_exp,
"st_begin": st_begin,
"st_end": st_end,
"notes": notes}) "notes": notes})
except Exception as e: except Exception as e:
@@ -701,8 +628,136 @@ def read_table(filename: str,
+ ("Error! File cannot be loaded " + ("Error! File cannot be loaded "
"from the {} directory").format(directory) "from the {} directory").format(directory)
+ "\033[0m") + "\033[0m")
print(e)
return create_table() return create_table()
return table return table
def make_plot(table: Table,
config: dict) -> int:
"""
Make an observation plot of the targets
@params:
- table: the target table
- config: the configuration dictionary
@returns:
- 0
"""
def get_timestamp(datetime, ref):
return (datetime - ref)/np.timedelta64(1, 's')
def get_time(timestamp, ref):
return timestamp*np.timedelta64(1, 's') + ref
if "YII_light_1" in plt.style.available: plt.style.use("YII_light_1")
plt.rcParams["figure.dpi"] = FIGURE_DPI
plt.rcParams["figure.facecolor"] = "#121212"
plt.rcParams['axes.facecolor'] = '#216576'
COLOR = 'DDDDDD'
plt.rcParams['text.color'] = COLOR
plt.rcParams['axes.labelcolor'] = COLOR
plt.rcParams['xtick.color'] = COLOR
plt.rcParams['ytick.color'] = COLOR
fig, ax = plt.subplots(1)
ax.set_title("Location: {}".format(config["LOCATION"]))
sun_set = np.datetime64(config["SUN_SET"])
sun_civil = np.datetime64(config["SUN_SET_CIVIL"])
sun_nautical = np.datetime64(config["SUN_SET_NAUTICAL"])
sun_astronomical = np.datetime64(config["SUN_SET_ASTRONOMICAL"])
sun_rastronomical = np.datetime64(config["SUN_RISE_ASTRONOMICAL"])
sun_rnautical = np.datetime64(config["SUN_RISE_NAUTICAL"])
sun_rcivil = np.datetime64(config["SUN_RISE_CIVIL"])
sun_rise = np.datetime64(config["SUN_RISE"])
obs_begin = np.datetime64(config["OBS_BEGIN"])
obs_end = np.datetime64(config["OBS_END"])
timestamp_set = get_timestamp(sun_set, obs_begin)
timestamp_civil = get_timestamp(sun_civil, obs_begin)
timestamp_nautical = get_timestamp(sun_nautical, obs_begin)
timestamp_astronomical = get_timestamp(sun_astronomical, obs_begin)
timestamp_rastronomical = get_timestamp(sun_rastronomical, obs_begin)
timestamp_rnautical = get_timestamp(sun_rnautical, obs_begin)
timestamp_rcivil = get_timestamp(sun_rcivil, obs_begin)
timestamp_rise = get_timestamp(sun_rise, obs_begin)
timestamp_begin = get_timestamp(obs_begin, obs_begin)
timestamp_end = get_timestamp(obs_end, obs_begin)
st_begin = coord.Angle(config["ST_BEGIN"], unit=u.hourangle).degree
st_end = coord.Angle(config["ST_END"], unit=u.hourangle).degree
window_east = coord.Angle(config["WINDOW_EAST"], unit=u.hourangle).degree
window_west = coord.Angle(config["WINDOW_WEST"], unit=u.hourangle).degree
if st_end < st_begin:
st_end += 360
slope = (timestamp_end - timestamp_begin)/(st_end - st_begin)
def compute_timestamp(st, a=slope, sb=st_begin, hb=timestamp_begin):
return (st-sb) * a + hb
def compute_st(timestamp, a=slope, sb=st_begin, hb=timestamp_begin):
return (timestamp-hb) / a + sb
N = len(table)
# Night times
ax.axvspan(sun_set, sun_rise, color="k", alpha=0.2)
ax.axvspan(sun_civil, sun_rcivil, color="k", alpha=0.4)
ax.axvspan(sun_nautical, sun_rnautical, color="k", alpha=0.6)
ax.axvspan(sun_astronomical, sun_rastronomical, color="k", alpha=0.8)
# Observation time
ax.axvspan(obs_begin, obs_end, color="C0", alpha=0.3)
# Observation range
if st_begin < window_east:
st_begin += 360
if window_west < st_end:
window_west += 360
a_before = st_begin - window_east
a_after = window_west - st_end
plot_colors = ["#ED1C24", "#E8BD0F"]
N_colors = len(plot_colors)
N_same = 4
# Targets
for i in range(N):
ra = coord.Angle(table["ra"][i], unit=u.hourangle).degree
if ra > window_west:
ra -= 360
ra_before = ra + a_before
ra_after = ra - a_after
h = compute_timestamp(ra)
h_before = compute_timestamp(ra_before)
h_after = compute_timestamp(ra_after)
time_ra = get_time(h, obs_begin)
time_before = get_time(h_before, obs_begin)
time_after = get_time(h_after, obs_begin)
color_index = (i // N_same) % N_colors
color = plot_colors[color_index]
ax.plot([time_before, time_after], [i,i], color=color, marker="|")
ax.scatter([time_ra], [i], s=5, color=color)
ax.text(time_after, i, table["name"][i] + " ",
horizontalalignment="right", verticalalignment="center")
ra_text = table["ra"][i]
dec_text = table["dec"][i]
ax.text(time_before, i, " {}{}".format(ra_text, dec_text))
ax.set_xlabel("Observation date and time (UTC)")
ax.set_yticks(range(N), table["seq"])
plt.show(block=False)
# obs_time = np.arange(sun_set, sun_rise, dtype="datetime64[m]")
return 0
def print_help(): def print_help():
hilfe = ("\033[36m" hilfe = ("\033[36m"
"Help will be always given to those who ask for it [1].\n" "Help will be always given to those who ask for it [1].\n"
@@ -712,7 +767,7 @@ def print_help():
"(WARNING: this does not save the current state!)\n" "(WARNING: this does not save the current state!)\n"
"\t- write, save: write the current table in a file " "\t- write, save: write the current table in a file "
"(no options available yet)\n" "(no options available yet)\n"
"\t- read [filename], open [filename]: " "\t- read [filename], open [filename], load [filename]: "
"loads the file \"filename\" " "loads the file \"filename\" "
"in the current table (no additional options available yet)\n" "in the current table (no additional options available yet)\n"
"\t- calibration, calib: adds a calibration in the target list\n" "\t- calibration, calib: adds a calibration in the target list\n"
@@ -720,16 +775,18 @@ def print_help():
"add an object from simbad\n" "add an object from simbad\n"
"\t- search [ra] [dec] [radius], region [ra] [dec] [radius]: " "\t- search [ra] [dec] [radius], region [ra] [dec] [radius]: "
"search a region centred on the ra/dec coordinates, " "search a region centred on the ra/dec coordinates, "
"with a given radius (coordinates should be expressed as " "with a given radius (ra is given in hour, dec in degree "
"12h30m30s, 90d30m30s or 90.555d)\n" "and the radius in any specified unit, "
"\t- manual [name] [seq (optional)], " "e.g. search 01:03:40 +35:40:20 30\')\n"
"add [name] [seq (optional)]: " "\t- manual [name] -s [seq (optional)], "
"add [name] -s [seq (optional)]: "
"manually add a target (only the name the sequence are " "manually add a target (only the name the sequence are "
"available for now)\n" "available for now)\n"
"\t- sidereal, st: computes the sidereal time for each target\n"
"\t- sequence, seq: computes the sequence order for each " "\t- sequence, seq: computes the sequence order for each "
"target\n" "target\n"
"\t- check: check if all targets are in the observation field\n" "\t- check: check if all targets are in the observation field\n"
"\t- plot, graph: creates a graph with all the targets "
"observation date and time"
"\n" "\n"
"General actions: \n" "General actions: \n"
"\t- cancel, back: cancels the current action\n" "\t- cancel, back: cancels the current action\n"
@@ -742,9 +799,10 @@ def print_help():
"\033[0m") "\033[0m")
print(hilfe) print(hilfe)
return None return None
def resolve_input(text: str, def resolve_input(text: str,
table: Table, table: Table,
config: dict): config: dict) -> Table:
""" """
Resolve the input to execute the expected function in an Resolve the input to execute the expected function in an
interactive way interactive way
@@ -772,7 +830,9 @@ def resolve_input(text: str,
select_obj(table, swap_table, config) select_obj(table, swap_table, config)
elif args[0].upper() in REGION: elif args[0].upper() in REGION:
name = " ".join(args[1]+" "+args[2]) name = " ".join(args[1]+" "+args[2])
region = coord.SkyCoord(ra=args[1], dec=args[2]) ra = coord.Angle(args[1], unit=u.hourangle)
dec = coord.Angle(args[2], unit=u.degree)
region = coord.SkyCoord(ra=ra, dec=dec)
radius = coord.Angle(args[3]) radius = coord.Angle(args[3])
obj = Simbad.query_region(region, radius) obj = Simbad.query_region(region, radius)
swap_table = add_simbad(swap_table, obj, config) swap_table = add_simbad(swap_table, obj, config)
@@ -791,12 +851,12 @@ def resolve_input(text: str,
add_manual(table, config, seq, name) add_manual(table, config, seq, name)
elif args[0].upper() in CALIB: # TODO ajouter args elif args[0].upper() in CALIB: # TODO ajouter args
add_calib(table, config) add_calib(table, config)
elif args[0].upper() in ST:
set_st_window(table, config)
elif args[0].upper() in SEQ: # FIXME marche bien une fois mais pas deux ?? elif args[0].upper() in SEQ: # FIXME marche bien une fois mais pas deux ??
set_seq(table, config) set_seq(table, config)
elif args[0].upper() in CHECK: elif args[0].upper() in CHECK:
check_window(table, config) check_window(table, config)
elif args[0].upper() in PLOT:
make_plot(table, config)
elif args[0].upper() in HELP: elif args[0].upper() in HELP:
print_help() print_help()
elif args[0].upper() in QUIT: elif args[0].upper() in QUIT:

View File

@@ -4,16 +4,24 @@ astroquery==0.4.7
beautifulsoup4==4.12.3 beautifulsoup4==4.12.3
certifi==2024.8.30 certifi==2024.8.30
charset-normalizer==3.4.0 charset-normalizer==3.4.0
contourpy==1.3.1
cycler==0.12.1
fonttools==4.55.0
html5lib==1.1 html5lib==1.1
idna==3.10 idna==3.10
jaraco.classes==3.4.0 jaraco.classes==3.4.0
jaraco.context==6.0.1 jaraco.context==6.0.1
jaraco.functools==4.1.0 jaraco.functools==4.1.0
keyring==25.5.0 keyring==25.5.0
kiwisolver==1.4.7
matplotlib==3.9.3
more-itertools==10.5.0 more-itertools==10.5.0
numpy==2.1.3 numpy==2.1.3
packaging==24.2 packaging==24.2
pillow==11.0.0
pyerfa==2.0.1.5 pyerfa==2.0.1.5
pyparsing==3.2.0
python-dateutil==2.9.0.post0
pyvo==1.6 pyvo==1.6
PyYAML==6.0.2 PyYAML==6.0.2
requests==2.32.3 requests==2.32.3