@@ -1093,6 +1093,17 @@ def refresh_priorities(self, ref_e: float | None) -> None:
10931093 """
10941094 if ref_e is not None :
10951095 self ._current_ref_e = ref_e
1096+
1097+
1098+ if self ._heap :
1099+ new_heap = []
1100+ for old_priority , task_id , task in self ._heap :
1101+
1102+ new_priority = self ._calculate_priority (task )
1103+ new_heap .append ((new_priority , task_id , task ))
1104+
1105+ heapq .heapify (new_heap )
1106+ self ._heap = new_heap
10961107
10971108 def export_queue_status (self ) -> list [dict ]:
10981109 return [
@@ -3359,7 +3370,10 @@ def _run_autots(self, task: ExplorationTask, run_dir: str) -> list[str]:
33593370 break
33603371
33613372 # ── Step 3: join after the queue is empty — never deadlocks ──────
3362- proc .join ()
3373+ proc .join (timeout = 120 )
3374+ if proc .is_alive ():
3375+ proc .terminate ()
3376+ proc .join (timeout = 10 )
33633377
33643378 if tag == "err" :
33653379 # payload is a formatted traceback string (see _autots_worker_with_queue).
@@ -3375,14 +3389,7 @@ def _run_autots(self, task: ExplorationTask, run_dir: str) -> list[str]:
33753389 # ------------------------------------------------------------------
33763390
33773391 def _flush_node_energy_updates (self ) -> None :
3378- """Apply pending energy backfill updates accumulated during the iteration.
3379-
3380- When :meth:`_find_or_register_node` matches an incoming structure to an
3381- existing :class:`EQNode` but that node was registered without energy or
3382- free-energy data (e.g. the seed structure optimisation did not perform
3383- thermochemistry), the new non-null values are queued in
3384- ``_pending_node_updates``. This method applies all queued updates in
3385- one batch, then clears the queue.
3392+ """Apply all accumulated node energy backfills.
33863393
33873394 Design decisions (confirmed with user):
33883395 * Called once per iteration, just before ``graph.save()``.
@@ -3410,6 +3417,14 @@ def _flush_node_energy_updates(self) -> None:
34103417 if new_e is not None and node .energy is None :
34113418 node .energy = new_e
34123419 changed .append (f"energy={ new_e :.10f} Ha" )
3420+
3421+ # BUGFIX: Remove the node from the un-evaluated list so it no longer
3422+ # bypasses the O(log N) energy window check in nodes_in_energy_window()
3423+ # before the next _rebuild_indexes() call.
3424+ try :
3425+ self .graph ._node_none_ids .remove (node_id )
3426+ except ValueError :
3427+ pass
34133428
34143429 new_g = updates .free_energy
34153430 if new_g is not None and node .free_energy is None :
@@ -3419,7 +3434,8 @@ def _flush_node_energy_updates(self) -> None:
34193434 if changed :
34203435 logger .info (
34213436 "_flush_node_energy_updates: EQ%d updated — %s" ,
3422- node_id , " " .join (changed ),
3437+ node_id ,
3438+ " " .join (changed ),
34233439 )
34243440 else :
34253441 logger .debug (
@@ -3429,6 +3445,7 @@ def _flush_node_energy_updates(self) -> None:
34293445 )
34303446
34313447 self ._pending_node_updates .clear ()
3448+
34323449 # Node energies may have changed; invalidate the cached reference energy
34333450 # via the public method instead of touching the private cache directly.
34343451 self .graph .invalidate_energy_cache ()
0 commit comments