@@ -185,6 +185,11 @@ def _initialize_fresh(self):
185185 self .converged = False
186186 self .termination_reason = "Unknown"
187187 self .gp_info = {} # Store GP and classifier information
188+
189+ # Best point information (for getdist minimum files)
190+ self .best_point = None
191+ self .best_loglike = None
192+ self .best_iteration = None
188193
189194 def _load_existing_results (self , output_file : str ) -> Optional [Dict [str , Any ]]:
190195 """
@@ -518,18 +523,22 @@ def finalize(self,
518523 logz_dict : Optional [Dict [str , float ]] = None ,
519524 converged : bool = False ,
520525 termination_reason : str = "Max iterations reached" ,
521- gp_info : Optional [Dict [str , Any ]] = None ):
526+ gp_info : Optional [Dict [str , Any ]] = None ,
527+ best_point : Optional [np .ndarray ] = None ,
528+ best_loglike : Optional [float ] = None ,
529+ best_iteration : Optional [int ] = None ):
522530 """
523531 Finalize the results with final samples and metadata.
524532
525533 Args:
526- samples: Final parameter samples [n_samples, n_params]
527- weights: Sample weights [n_samples]
528- loglikes: Log-likelihood values [n_samples]
534+ samples_dict: Dictionary with 'x', 'weights', 'logl' keys for final samples
529535 logz_dict: Final evidence information
530536 converged: Whether the run converged
531537 termination_reason: Reason for termination
532538 gp_info: Dictionary containing GP and classifier information
539+ best_point: Best point found (physical parameter space)
540+ best_loglike: Best log-likelihood value
541+ best_iteration: Iteration where best point was found
533542 """
534543 self .end_time = time .time ()
535544
@@ -550,8 +559,15 @@ def finalize(self,
550559 self .converged = converged
551560 self .termination_reason = termination_reason
552561 self .gp_info = gp_info or {}
562+
563+ # Store best point information
564+ self .best_point = best_point
565+ self .best_loglike = best_loglike
566+ self .best_iteration = best_iteration
553567
554568 log .info (f"Finalized BOBE results: converged={ converged } , reason={ termination_reason } " )
569+ if best_point is not None and best_loglike is not None :
570+ log .info (f"Best point: logL={ best_loglike :.6f} at iteration { best_iteration } " )
555571
556572 # Save all results
557573 self .save_all_formats ()
@@ -668,6 +684,9 @@ def save_all_formats(self):
668684
669685 # Timing data
670686 self .save_timing_data ()
687+
688+ # GetDist minimum files (best point)
689+ self .save_minimum_files ()
671690
672691 def save_main_results (self ):
673692 """Save main comprehensive results file."""
@@ -702,6 +721,66 @@ def save_chain_files(self, samples_dict: Optional[Dict[str, np.ndarray]] = None,
702721 getdist_samples .saveAsText (root = output_file , make_dirs = True )
703722 log .info (f"Saved GetDist format files to { output_file } " )
704723 log .info ("Created: .txt (chain), .paramnames (parameter info), .ranges (parameter bounds)" )
724+
725+ def save_minimum_files (self ):
726+ """
727+ Save best point in GetDist minimum format.
728+
729+ Creates two files:
730+ - .minimum.txt: Simple table with best point
731+ - .minimum: Formatted text with parameter details
732+ """
733+ if self .best_point is None or self .best_loglike is None :
734+ log .debug ("No best point data available, skipping minimum files" )
735+ return
736+
737+ best_point = np .atleast_1d (self .best_point )
738+
739+ if len (best_point ) != self .ndim :
740+ log .warning (f"Best point dimension { len (best_point )} != { self .ndim } , skipping minimum files" )
741+ return
742+
743+ minuslogpost = - self .best_loglike
744+ chi_sq = 2.0 * minuslogpost
745+
746+ # Write .minimum.txt file (simple table format)
747+ minimum_txt_file = f"{ self .save_path } .minimum.txt"
748+ try :
749+ with open (minimum_txt_file , 'w' ) as f :
750+ # Header line
751+ header = "# weight minuslogpost"
752+ for param_name in self .param_names :
753+ header += f" { param_name :>13s} "
754+ f .write (header + "\n " )
755+
756+ # Data line (weight is always 1 for single best point)
757+ line = f" 1 { minuslogpost :13.7f} "
758+ for val in best_point :
759+ line += f" { val :13.8e} "
760+ f .write (line + "\n " )
761+
762+ log .info (f"Saved minimum table to { minimum_txt_file } " )
763+ except Exception as e :
764+ log .warning (f"Failed to save .minimum.txt file: { e } " )
765+
766+ # Write .minimum file (formatted text with labels)
767+ minimum_file = f"{ self .save_path } .minimum"
768+ try :
769+ with open (minimum_file , 'w' ) as f :
770+ # Header with likelihood info
771+ f .write (f" -log(Like) = { minuslogpost :.12f} \n " )
772+ f .write (f" chi-sq = { chi_sq :.12f} \n " )
773+ f .write ("\n " )
774+
775+ # Parameter list with index, value, name, and LaTeX label
776+ for i , (param_name , param_label , val ) in enumerate (zip (
777+ self .param_names , self .param_labels , best_point ), start = 1 ):
778+ # Format: index (right-aligned, width 5), value (scientific), name, label
779+ f .write (f"{ i :>5d} { val :.9e} { param_name :40s} { param_label } \n " )
780+
781+ log .info (f"Saved minimum point details to { minimum_file } " )
782+ except Exception as e :
783+ log .warning (f"Failed to save .minimum file: { e } " )
705784
706785
707786 def save_summary_stats (self ):
0 commit comments