14
14
from __future__ import annotations
15
15
16
16
import asyncio
17
+ from io import BytesIO
17
18
import pickle
18
19
from contextlib import suppress
19
20
from datetime import datetime
56
57
from ..site import Telescopes , default_sites
57
58
from ..topic import TOPICS , full_topic_name_to_short
58
59
59
-
60
60
topics = CfgOption ("topics" , TOPICS , list )
61
61
timeout = CfgOption ("timeout" , - 1 , float )
62
62
start_date = CfgOption (
@@ -204,7 +204,7 @@ async def consume_messages(self):
204
204
message = await self ._poll_message (timeout = timeout .value )
205
205
await self ._process_message (message )
206
206
# await self.consume_messages()
207
-
207
+
208
208
# Read several new messages to have concurrency. Otherwise, if we poll,
209
209
# only for the last alert type in topics alerts will be received.
210
210
# for message in self.consumer.consume(
@@ -230,7 +230,7 @@ async def _poll_message(self, timeout: float) -> Message | None:
230
230
"""
231
231
try :
232
232
message = await poll_message (self .consumer , timeout )
233
-
233
+
234
234
log .debug (
235
235
"ConsumeLoop._consume_message(): received message on %s" ,
236
236
datetime .now ().isoformat (),
@@ -322,7 +322,7 @@ def name_xmatch(info: TargetInfo) -> list[dict]:
322
322
except Exception as e :
323
323
log .error ("Failed to crossmatch alert by name: %s" , e )
324
324
return matched_alerts
325
-
325
+
326
326
if info .localization :
327
327
matched_alerts = await spatial_xmatch (info )
328
328
else :
@@ -359,6 +359,7 @@ def name_xmatch(info: TargetInfo) -> list[dict]:
359
359
matched_error_radii = [a ["error_radius" ] for a in matched_alerts ]
360
360
i_min = np .argmin (matched_error_radii )
361
361
matched_error_radius = matched_error_radii [i_min ]
362
+ matched_localization = matched_alerts [i_min ]["localization" ]
362
363
error_radius = info .localization .error_radius ().to_value (u .deg )
363
364
364
365
if error_radius < matched_error_radius :
@@ -369,8 +370,32 @@ def name_xmatch(info: TargetInfo) -> list[dict]:
369
370
event ,
370
371
len (matched_alerts ),
371
372
)
372
- send_obs_data = True
373
+
373
374
refines_localization = True
375
+
376
+ # If matched error radius is already small enough, no need to
377
+ # run the planner again. Since, skymap is wholy inside FOV of a
378
+ # telescope anyway.
379
+ SMALL_RADIUS = 1.5 / 60 # 1.5 arcmin
380
+ refines_small = matched_error_radius < SMALL_RADIUS
381
+
382
+ # The same, when newer sky map is fully contained inside old one
383
+ # borders, and its area not significantly smaller than the old
384
+ # one. We probably already have plans for that skymap region.
385
+ matched_moc = pickle .loads (matched_localization ).moc ()
386
+ new_moc = info .localization .moc ()
387
+ SKY_MAP_AREA_FRACTION = 0.75
388
+ new_inside_old = (
389
+ new_moc .union (matched_moc ) == new_moc
390
+ and new_moc .sky_fraction
391
+ > SKY_MAP_AREA_FRACTION * matched_moc .sky_fraction
392
+ )
393
+
394
+ if refines_small or new_inside_old :
395
+ send_obs_data = False
396
+ else :
397
+ send_obs_data = True
398
+
374
399
else :
375
400
send_obs_data = False
376
401
refines_localization = False
@@ -457,7 +482,8 @@ def name_xmatch(info: TargetInfo) -> list[dict]:
457
482
458
483
# Run planner in the separate thread, because it is a blocking function
459
484
@aiomisc .threaded
460
- def plan_func (planner : ObservationPlanner ):
485
+ def plan_func (planner : ObservationPlanner ) -> dict :
486
+ plan_dicts = {}
461
487
try :
462
488
planner .plan_observations (
463
489
epoch = now ,
@@ -471,10 +497,11 @@ def plan_func(planner: ObservationPlanner):
471
497
plan_result = planner .save_or_update_planning ()
472
498
json_plan_reg_fn , plan_data = plan_result
473
499
plan_dicts = plan_data .get ("plans" , [])
474
- return plan_dicts
475
500
except Exception as e :
476
501
log .error ("Error while planning observations: %s" , e )
477
502
503
+ return plan_dicts
504
+
478
505
# Plan only for not-empty localization skymaps
479
506
if info .localization is not None :
480
507
plan_dicts = await plan_func (planner )
@@ -496,7 +523,7 @@ def plan_func(planner: ObservationPlanner):
496
523
target_info = info ,
497
524
)
498
525
except (LookupError , TypeError , ArithmeticError ):
499
- # If registry contains site_id not presented in
526
+ # If registry contains site_id not presented in
500
527
# default_sites
501
528
pass
502
529
else :
0 commit comments