utils.databases.simbad
Getting data from SIMBAD astronomical database.
1""" 2Getting data from [SIMBAD](https://simbad.u-strasbg.fr/simbad/) 3astronomical database. 4""" 5 6from astroquery.simbad import Simbad 7from astroquery import __version__ as astroqueryVersion 8import re 9 10from typing import Optional, Any 11 12from ..logs.log import logger 13from ..databases import tap 14 15 16def findIdentificatorFromAnotherCatalogue( 17 starName: str, 18 otherIDname: str, 19 otherIDversion: Optional[str] = None, 20 withoutIDprefix: bool = True 21) -> Optional[str]: 22 """ 23 Finds object identificator from a particular catalogue. SIMBAD returns 24 a list of identificators prepended with the catalogue name, and this 25 function finds the identificator for the specified catalogue and returns 26 just the identificator. In addition to that, some catalogues have versions, 27 so it is possible to specify which one if of interest. 28 29 For instance, if you need to find the identificator for `TWA 20` star 30 in `Gaia` catalog version `DR3`, then SIMBAD will return 31 `Gaia DR3 6132146982868270976` value for it, out of which this function 32 will extract `6132146982868270976` as the result. 33 34 Example: 35 36 ``` py 37 from phab.utils.databases import simbad 38 39 otherID = simbad.findIdentificatorFromAnotherCatalogue( 40 "TWA 20", 41 "gaia", 42 "dr3" 43 ) 44 print(otherID) 45 ``` 46 """ 47 otherID = None 48 49 otherIDs = Simbad.query_objectids(starName) 50 if otherIDs is None: 51 logger.warning( 52 " ".join(( 53 "SIMBAD database doesn't have information", 54 f"about [{starName}]" 55 )) 56 ) 57 else: 58 logger.debug(f"Checking SIMBAD IDs for [{starName}]:") 59 60 # before astroquery version 0.4.8 this table had 61 # an upper-cased `ID` column key, but starting 62 # with version 0.4.8 it is now lower-cased `id` 63 # 64 # https://github.com/astropy/astropy/issues/17695 65 idColumnKey: str = "ID" 66 # or compare `astroquery.__version__` with `0.4.7` 67 if idColumnKey not in otherIDs.colnames: 68 logger.debug( 69 " ".join(( 70 "There is no upper-cased [ID] key", 71 "in the resulting table, will try", 72 "with lower-cased [id] key" 73 )) 74 ) 75 idColumnKey = idColumnKey.lower() # "id" 76 if idColumnKey not in otherIDs.colnames: 77 errorMsg = " ".join(( 78 "SIMBAD results table has neither [ID]", 79 "nor [id] column" 80 )) 81 logger.error(errorMsg) 82 if len(otherIDs.colnames) > 0: 83 logger.debug( 84 " ".join(( 85 "Here are all the columns/keys", 86 "in this table:", 87 ", ".join(otherIDs.colnames) 88 )) 89 ) 90 else: 91 logger.debug( 92 " ".join(( 93 "There are no columns/keys", 94 "in this table at all" 95 )) 96 ) 97 raise KeyError(errorMsg) 98 99 for oid in otherIDs: 100 idCandidate: str = oid[idColumnKey] 101 logger.debug(f"- {idCandidate}") 102 if otherIDname.lower() in idCandidate.lower(): 103 idToLookFor = ( 104 f"{otherIDname} {otherIDversion}" 105 if otherIDversion else otherIDname 106 ) 107 if idToLookFor.lower() in idCandidate.lower(): 108 if withoutIDprefix: 109 prefixRE = re.compile( 110 rf"{idToLookFor}\s?", 111 re.IGNORECASE 112 ) 113 otherID = prefixRE.sub("", idCandidate) 114 else: 115 otherID = idCandidate 116 break 117 return otherID 118 119 120def getObjectID(starName: str) -> Optional[int]: 121 """ 122 Finds object identificator for 123 [SIMBAD tables](http://simbad.cds.unistra.fr/simbad/tap/tapsearch.html). 124 It is stored in the `oid` field of the `basic` table. 125 126 The discovery process is to compare all the known object identificators 127 with the `main_id` field value (*also from the `basic` table*). It is 128 not clear, how exactly SIMBAD maintainers choose the main ID for an object, 129 so one has to iterate through all the identificators known to SIMBAD. 130 131 Example: 132 133 ``` py 134 from phab.utils.databases import simbad 135 from typing import Optional 136 137 oid: Optional[int] = None 138 try: 139 oid = simbad.getObjectID("A2 146") 140 except KeyError as ex: 141 print(f"Something wrong with querying SIMBAD. {repr(ex)}") 142 if oid is not None: 143 print(f"Object ID: {oid}") 144 else: 145 print("No results") 146 ``` 147 """ 148 oid: Optional[int] = None 149 150 # check if this name is already the main ID 151 logger.debug(f"Checking whether [{starName}] is already the main ID") 152 rez = tap.queryService( 153 tap.getServiceEndpoint("simbad"), 154 " ".join(( 155 "SELECT oid", 156 "FROM basic", 157 f"WHERE main_id = '{starName}'" 158 )) 159 ) 160 if rez: 161 oid = rez[0]["oid"] 162 logger.debug( 163 " ".join(( 164 f"- yes, that is already the main ID,", 165 "no need to iterate all the identificators.", 166 f"SIMBAD object ID is: {oid}" 167 )) 168 ) 169 else: 170 logger.debug( 171 " ".join(( 172 "- no, that is not the main ID, will have to iterate", 173 "all the other identificators" 174 )) 175 ) 176 ids = Simbad.query_objectids(starName) 177 if ids is None: 178 logger.warning( 179 " ".join(( 180 "SIMBAD database doesn't have information", 181 f"about [{starName}]" 182 )) 183 ) 184 else: 185 logger.debug(f"Checking SIMBAD IDs for [{starName}]:") 186 187 # before astroquery version 0.4.8 this table had 188 # an upper-cased `ID` column key, but starting 189 # with version 0.4.8 it is now lower-cased `id` 190 # 191 # https://github.com/astropy/astropy/issues/17695 192 idColumnKey: str = "ID" 193 # or compare `astroquery.__version__` with `0.4.7` 194 if idColumnKey not in ids.colnames: 195 logger.debug( 196 " ".join(( 197 "There is no upper-cased [ID] key", 198 "in the resulting table, will try", 199 "with lower-cased [id] key" 200 )) 201 ) 202 idColumnKey = idColumnKey.lower() # "id" 203 if idColumnKey not in ids.colnames: 204 errorMsg = " ".join(( 205 "SIMBAD results table has neither [ID]", 206 "nor [id] column" 207 )) 208 logger.error(errorMsg) 209 if len(ids.colnames) > 0: 210 logger.debug( 211 " ".join(( 212 "Here are all the columns/keys", 213 "in this table:", 214 ", ".join(ids.colnames) 215 )) 216 ) 217 else: 218 logger.debug( 219 " ".join(( 220 "There are no columns/keys", 221 "in this table at all" 222 )) 223 ) 224 raise KeyError(errorMsg) 225 226 for id in ids: 227 idValue: str = id[idColumnKey] 228 logger.debug(f"- {idValue}") 229 230 if idValue == starName: 231 logger.debug( 232 f"...the [{idValue}] has already been tested, skipping" 233 ) 234 continue 235 rez = tap.queryService( 236 tap.getServiceEndpoint("simbad"), 237 " ".join(( 238 "SELECT oid", 239 "FROM basic", 240 f"WHERE main_id = '{idValue}'" 241 )) 242 ) 243 if rez: 244 oid = rez[0]["oid"] 245 logger.debug( 246 " ".join(( 247 f"The [{idValue}] is the main ID for", 248 f"[{starName}], SIMBAD object ID is: {oid}" 249 )) 250 ) 251 break 252 return oid 253 254 255def getStellarParameter( 256 starName: str, 257 table: str, 258 param: str 259) -> Optional[tuple[Any, str]]: 260 """ 261 A convenience function for querying SIMBAD for a stellar parameter: 262 263 1. Finds SIMBAD's object ID by the star name 264 (*with `utils.databases.simbad.getObjectID`*); 265 2. Queries for a stellar parameter by that object ID 266 (*with `utils.databases.tap.getStellarParameterFromSimbadByObjectID`*). 267 268 Example: 269 270 ``` py 271 from phab.utils.databases import simbad 272 273 starName = "PPM 725297" 274 param = "period" 275 rez = simbad.getStellarParameter( 276 starName, 277 "mesVar", 278 param 279 ) 280 if rez: 281 val = rez[0] 282 ref = rez[1] 283 print(f"Value: {val}, reference: {ref}") 284 else: 285 print(f"SIMBAD doesn't have data about [{param}] parameter of [{starName}] object") 286 ``` 287 """ 288 rez: Optional[tuple[Any, str]] = None 289 290 oid = getObjectID(starName) 291 if oid: 292 # logger.debug( 293 # f"Found the following object ID for [{starName}]: {oid}" 294 # ) 295 rez = tap.getStellarParameterFromSimbadByObjectID( 296 oid, 297 table, 298 param 299 ) 300 301 return rez
17def findIdentificatorFromAnotherCatalogue( 18 starName: str, 19 otherIDname: str, 20 otherIDversion: Optional[str] = None, 21 withoutIDprefix: bool = True 22) -> Optional[str]: 23 """ 24 Finds object identificator from a particular catalogue. SIMBAD returns 25 a list of identificators prepended with the catalogue name, and this 26 function finds the identificator for the specified catalogue and returns 27 just the identificator. In addition to that, some catalogues have versions, 28 so it is possible to specify which one if of interest. 29 30 For instance, if you need to find the identificator for `TWA 20` star 31 in `Gaia` catalog version `DR3`, then SIMBAD will return 32 `Gaia DR3 6132146982868270976` value for it, out of which this function 33 will extract `6132146982868270976` as the result. 34 35 Example: 36 37 ``` py 38 from phab.utils.databases import simbad 39 40 otherID = simbad.findIdentificatorFromAnotherCatalogue( 41 "TWA 20", 42 "gaia", 43 "dr3" 44 ) 45 print(otherID) 46 ``` 47 """ 48 otherID = None 49 50 otherIDs = Simbad.query_objectids(starName) 51 if otherIDs is None: 52 logger.warning( 53 " ".join(( 54 "SIMBAD database doesn't have information", 55 f"about [{starName}]" 56 )) 57 ) 58 else: 59 logger.debug(f"Checking SIMBAD IDs for [{starName}]:") 60 61 # before astroquery version 0.4.8 this table had 62 # an upper-cased `ID` column key, but starting 63 # with version 0.4.8 it is now lower-cased `id` 64 # 65 # https://github.com/astropy/astropy/issues/17695 66 idColumnKey: str = "ID" 67 # or compare `astroquery.__version__` with `0.4.7` 68 if idColumnKey not in otherIDs.colnames: 69 logger.debug( 70 " ".join(( 71 "There is no upper-cased [ID] key", 72 "in the resulting table, will try", 73 "with lower-cased [id] key" 74 )) 75 ) 76 idColumnKey = idColumnKey.lower() # "id" 77 if idColumnKey not in otherIDs.colnames: 78 errorMsg = " ".join(( 79 "SIMBAD results table has neither [ID]", 80 "nor [id] column" 81 )) 82 logger.error(errorMsg) 83 if len(otherIDs.colnames) > 0: 84 logger.debug( 85 " ".join(( 86 "Here are all the columns/keys", 87 "in this table:", 88 ", ".join(otherIDs.colnames) 89 )) 90 ) 91 else: 92 logger.debug( 93 " ".join(( 94 "There are no columns/keys", 95 "in this table at all" 96 )) 97 ) 98 raise KeyError(errorMsg) 99 100 for oid in otherIDs: 101 idCandidate: str = oid[idColumnKey] 102 logger.debug(f"- {idCandidate}") 103 if otherIDname.lower() in idCandidate.lower(): 104 idToLookFor = ( 105 f"{otherIDname} {otherIDversion}" 106 if otherIDversion else otherIDname 107 ) 108 if idToLookFor.lower() in idCandidate.lower(): 109 if withoutIDprefix: 110 prefixRE = re.compile( 111 rf"{idToLookFor}\s?", 112 re.IGNORECASE 113 ) 114 otherID = prefixRE.sub("", idCandidate) 115 else: 116 otherID = idCandidate 117 break 118 return otherID
Finds object identificator from a particular catalogue. SIMBAD returns a list of identificators prepended with the catalogue name, and this function finds the identificator for the specified catalogue and returns just the identificator. In addition to that, some catalogues have versions, so it is possible to specify which one if of interest.
For instance, if you need to find the identificator for TWA 20
star
in Gaia
catalog version DR3
, then SIMBAD will return
Gaia DR3 6132146982868270976
value for it, out of which this function
will extract 6132146982868270976
as the result.
Example:
from phab.utils.databases import simbad
otherID = simbad.findIdentificatorFromAnotherCatalogue(
"TWA 20",
"gaia",
"dr3"
)
print(otherID)
121def getObjectID(starName: str) -> Optional[int]: 122 """ 123 Finds object identificator for 124 [SIMBAD tables](http://simbad.cds.unistra.fr/simbad/tap/tapsearch.html). 125 It is stored in the `oid` field of the `basic` table. 126 127 The discovery process is to compare all the known object identificators 128 with the `main_id` field value (*also from the `basic` table*). It is 129 not clear, how exactly SIMBAD maintainers choose the main ID for an object, 130 so one has to iterate through all the identificators known to SIMBAD. 131 132 Example: 133 134 ``` py 135 from phab.utils.databases import simbad 136 from typing import Optional 137 138 oid: Optional[int] = None 139 try: 140 oid = simbad.getObjectID("A2 146") 141 except KeyError as ex: 142 print(f"Something wrong with querying SIMBAD. {repr(ex)}") 143 if oid is not None: 144 print(f"Object ID: {oid}") 145 else: 146 print("No results") 147 ``` 148 """ 149 oid: Optional[int] = None 150 151 # check if this name is already the main ID 152 logger.debug(f"Checking whether [{starName}] is already the main ID") 153 rez = tap.queryService( 154 tap.getServiceEndpoint("simbad"), 155 " ".join(( 156 "SELECT oid", 157 "FROM basic", 158 f"WHERE main_id = '{starName}'" 159 )) 160 ) 161 if rez: 162 oid = rez[0]["oid"] 163 logger.debug( 164 " ".join(( 165 f"- yes, that is already the main ID,", 166 "no need to iterate all the identificators.", 167 f"SIMBAD object ID is: {oid}" 168 )) 169 ) 170 else: 171 logger.debug( 172 " ".join(( 173 "- no, that is not the main ID, will have to iterate", 174 "all the other identificators" 175 )) 176 ) 177 ids = Simbad.query_objectids(starName) 178 if ids is None: 179 logger.warning( 180 " ".join(( 181 "SIMBAD database doesn't have information", 182 f"about [{starName}]" 183 )) 184 ) 185 else: 186 logger.debug(f"Checking SIMBAD IDs for [{starName}]:") 187 188 # before astroquery version 0.4.8 this table had 189 # an upper-cased `ID` column key, but starting 190 # with version 0.4.8 it is now lower-cased `id` 191 # 192 # https://github.com/astropy/astropy/issues/17695 193 idColumnKey: str = "ID" 194 # or compare `astroquery.__version__` with `0.4.7` 195 if idColumnKey not in ids.colnames: 196 logger.debug( 197 " ".join(( 198 "There is no upper-cased [ID] key", 199 "in the resulting table, will try", 200 "with lower-cased [id] key" 201 )) 202 ) 203 idColumnKey = idColumnKey.lower() # "id" 204 if idColumnKey not in ids.colnames: 205 errorMsg = " ".join(( 206 "SIMBAD results table has neither [ID]", 207 "nor [id] column" 208 )) 209 logger.error(errorMsg) 210 if len(ids.colnames) > 0: 211 logger.debug( 212 " ".join(( 213 "Here are all the columns/keys", 214 "in this table:", 215 ", ".join(ids.colnames) 216 )) 217 ) 218 else: 219 logger.debug( 220 " ".join(( 221 "There are no columns/keys", 222 "in this table at all" 223 )) 224 ) 225 raise KeyError(errorMsg) 226 227 for id in ids: 228 idValue: str = id[idColumnKey] 229 logger.debug(f"- {idValue}") 230 231 if idValue == starName: 232 logger.debug( 233 f"...the [{idValue}] has already been tested, skipping" 234 ) 235 continue 236 rez = tap.queryService( 237 tap.getServiceEndpoint("simbad"), 238 " ".join(( 239 "SELECT oid", 240 "FROM basic", 241 f"WHERE main_id = '{idValue}'" 242 )) 243 ) 244 if rez: 245 oid = rez[0]["oid"] 246 logger.debug( 247 " ".join(( 248 f"The [{idValue}] is the main ID for", 249 f"[{starName}], SIMBAD object ID is: {oid}" 250 )) 251 ) 252 break 253 return oid
Finds object identificator for
SIMBAD tables.
It is stored in the oid
field of the basic
table.
The discovery process is to compare all the known object identificators
with the main_id
field value (also from the basic
table). It is
not clear, how exactly SIMBAD maintainers choose the main ID for an object,
so one has to iterate through all the identificators known to SIMBAD.
Example:
from phab.utils.databases import simbad
from typing import Optional
oid: Optional[int] = None
try:
oid = simbad.getObjectID("A2 146")
except KeyError as ex:
print(f"Something wrong with querying SIMBAD. {repr(ex)}")
if oid is not None:
print(f"Object ID: {oid}")
else:
print("No results")
256def getStellarParameter( 257 starName: str, 258 table: str, 259 param: str 260) -> Optional[tuple[Any, str]]: 261 """ 262 A convenience function for querying SIMBAD for a stellar parameter: 263 264 1. Finds SIMBAD's object ID by the star name 265 (*with `utils.databases.simbad.getObjectID`*); 266 2. Queries for a stellar parameter by that object ID 267 (*with `utils.databases.tap.getStellarParameterFromSimbadByObjectID`*). 268 269 Example: 270 271 ``` py 272 from phab.utils.databases import simbad 273 274 starName = "PPM 725297" 275 param = "period" 276 rez = simbad.getStellarParameter( 277 starName, 278 "mesVar", 279 param 280 ) 281 if rez: 282 val = rez[0] 283 ref = rez[1] 284 print(f"Value: {val}, reference: {ref}") 285 else: 286 print(f"SIMBAD doesn't have data about [{param}] parameter of [{starName}] object") 287 ``` 288 """ 289 rez: Optional[tuple[Any, str]] = None 290 291 oid = getObjectID(starName) 292 if oid: 293 # logger.debug( 294 # f"Found the following object ID for [{starName}]: {oid}" 295 # ) 296 rez = tap.getStellarParameterFromSimbadByObjectID( 297 oid, 298 table, 299 param 300 ) 301 302 return rez
A convenience function for querying SIMBAD for a stellar parameter:
- Finds SIMBAD's object ID by the star name
(with
utils.databases.simbad.getObjectID
); - Queries for a stellar parameter by that object ID
(with
utils.databases.tap.getStellarParameterFromSimbadByObjectID
).
Example:
from phab.utils.databases import simbad
starName = "PPM 725297"
param = "period"
rez = simbad.getStellarParameter(
starName,
"mesVar",
param
)
if rez:
val = rez[0]
ref = rez[1]
print(f"Value: {val}, reference: {ref}")
else:
print(f"SIMBAD doesn't have data about [{param}] parameter of [{starName}] object")