heterodyne.optimization.classical

Classical Optimization Methods for Heterodyne Scattering Analysis

This module contains multiple classical optimization algorithms for parameter estimation in heterodyne scattering analysis:

  1. Nelder-Mead Simplex: Derivative-free optimization algorithm that works well for noisy objective functions and doesn’t require gradient information, making it ideal for correlation function fitting.

  2. Gurobi Quadratic Programming: Advanced optimization using quadratic approximation of the chi-squared objective function. Particularly effective for smooth problems with parameter bounds constraints. Requires Gurobi license.

Key Features: - Consistent parameter bounds across all optimization methods - Automatic Gurobi detection and graceful fallback - Optimized configurations for different analysis modes - Comprehensive error handling and status reporting

Authors: Wei Chen, Hongrui He Institution: Argonne National Laboratory

class heterodyne.optimization.classical.ClassicalOptimizer(analysis_core, config)[source]

Bases: object

Classical optimization algorithms for parameter estimation.

This class provides robust parameter estimation using multiple optimization algorithms:

  1. Nelder-Mead simplex method: Well-suited for noisy objective functions and doesn’t require derivative information.

  2. Gurobi quadratic programming (optional): Uses quadratic approximation of the chi-squared objective function for potentially faster convergence on smooth problems with bounds constraints. Requires Gurobi license.

The Gurobi method approximates the objective function using finite differences to estimate gradients and Hessian, then solves the resulting quadratic program. This approach can be particularly effective for least squares problems where the objective function is approximately quadratic near the optimum.

Important: Both optimization methods use the same parameter bounds defined in the configuration’s parameter_space.bounds section, ensuring consistency with robust optimization and maintaining the same physical constraints across all optimization methods.

Parameters:

config (dict[str, Any])

__init__(analysis_core, config)[source]

Initialize classical optimizer.

Parameters:
run_optimization(initial_params=None, phi_angles=None, c2_experimental=None, return_tuple=False, **kwargs)[source]

Main optimization interface for CLI compatibility.

This method provides a standard interface that delegates to the appropriate optimization method.

Parameters:
  • initial_params (np.ndarray, optional) – Starting parameters for optimization

  • phi_angles (np.ndarray, optional) – Array of phi angles

  • c2_experimental (np.ndarray, optional) – Experimental correlation data

  • return_tuple (bool, default=False) – If True, return (params, result). If False, return result dict.

  • **kwargs – Additional optimization parameters

Returns:

If return_tuple=True: (parameters, result_object) If return_tuple=False: result dictionary

Return type:

tuple | dict

optimize(c2_experimental=None, phi_angles=None, t1_array=None, t2_array=None, **kwargs)[source]

Backward compatibility wrapper for optimize() method.

This method provides backward compatibility for tests that expect an optimize() method instead of run_optimization().

Parameters:
  • c2_experimental (np.ndarray, optional) – Experimental correlation data

  • phi_angles (np.ndarray, optional) – Array of phi angles

  • t1_array (np.ndarray, optional) – Array of t1 time values

  • t2_array (np.ndarray, optional) – Array of t2 time values

  • **kwargs – Additional optimization parameters

Returns:

Optimization result dictionary with keys: - ‘initial_parameters’: Initial parameter values - ‘parameters’: Optimal parameter values - ‘chi_squared’: Final chi-squared value - ‘success’: Whether optimization succeeded - Additional fields from optimization result

Return type:

dict[str, Any]

run_classical_optimization_optimized(initial_parameters=None, methods=None, phi_angles=None, c2_experimental=None)[source]

Run Nelder-Mead optimization method.

This method uses the Nelder-Mead simplex algorithm for parameter estimation. Nelder-Mead is well-suited for noisy objective functions and doesn’t require gradient information.

Parameters:
  • initial_parameters (np.ndarray, optional) – Starting parameters for optimization

  • methods (list, optional) – List of optimization methods to try

  • phi_angles (np.ndarray, optional) – Scattering angles

  • c2_experimental (np.ndarray, optional) – Experimental data

Returns:

(best_parameters, optimization_result)

Return type:

tuple

Raises:

RuntimeError – If all classical methods fail

get_available_methods()[source]

Get list of available classical optimization methods.

Returns:

List containing available optimization methods

Return type:

list[str]

validate_method_compatibility(method, has_bounds=True)[source]

Validate if optimization method is compatible with current setup.

Parameters:
  • method (str) – Optimization method name

  • has_bounds (bool) – Whether parameter bounds are defined (unused but kept for compatibility)

Returns:

True if method is supported

Return type:

bool

get_method_recommendations()[source]

Get method recommendations based on problem characteristics.

Returns:

Dictionary mapping scenarios to recommended methods

Return type:

dict[str, list[str]]

validate_parameters(parameters, method_name='')[source]

Validate physical parameters and bounds.

Parameters:
  • parameters (np.ndarray) – Model parameters to validate

  • method_name (str) – Name of optimization method for logging (currently unused)

Returns:

(is_valid, reason_if_invalid)

Return type:

tuple[bool, str]

create_objective_function(phi_angles, c2_experimental, method_name='Classical')[source]

Create objective function for optimization.

Parameters:
  • phi_angles (np.ndarray) – Scattering angles

  • c2_experimental (np.ndarray) – Experimental correlation data

  • method_name (str) – Name for logging purposes

Returns:

Objective function for optimization

Return type:

callable

run_single_method(method, objective_func, initial_parameters, bounds=None, method_options=None)[source]

Run a single optimization method.

Parameters:
  • method (str) – Optimization method name

  • objective_func (callable) – Objective function to minimize

  • initial_parameters (np.ndarray) – Starting parameters

  • bounds (list[tuple[float, float]], optional) – Parameter bounds

  • method_options (dict[str, Any], optional) – Method-specific options

Returns:

(success, result_or_exception)

Return type:

tuple[bool, OptimizeResult | Exception]

analyze_optimization_results(results)[source]

Analyze and summarize optimization results from Nelder-Mead method.

Parameters:

results (list[tuple[str, bool, OptimizeResult | Exception]]) – List of (method_name, success, result_or_exception) tuples (typically one entry for Nelder-Mead)

Returns:

Analysis summary including best method, convergence stats, etc.

Return type:

dict[str, Any]

get_parameter_bounds(effective_param_count=None)[source]

Extract parameter bounds from configuration (unused by Nelder-Mead).

This method is kept for compatibility but is not used by Nelder-Mead optimization since it doesn’t support explicit bounds.

Parameters:

effective_param_count (int, optional) – Number of parameters to use (always 14 for heterodyne model)

Returns:

List of (min, max) bounds for each parameter

Return type:

list[tuple[float, float]]

compare_optimization_results(results)[source]

Compare optimization results (typically just Nelder-Mead).

Parameters:

results (list[tuple[str, OptimizeResult | Exception]]) – List of (method_name, result) tuples (typically one entry for Nelder-Mead)

Returns:

Comparison summary with rankings and statistics

Return type:

dict[str, Any]

get_optimization_summary(best_params, best_result, total_time, method_name='unknown')[source]

Generate comprehensive optimization summary.

Parameters:
  • best_params (np.ndarray) – Best parameters found

  • best_result (OptimizeResult) – Best optimization result

  • total_time (float) – Total optimization time in seconds

  • method_name (str)

Returns:

Comprehensive optimization summary

Return type:

dict[str, Any]

reset_optimization_counter()[source]

Reset the global optimization counter.

get_optimization_counter()[source]

Get current optimization counter value.

Return type:

int

heterodyne.optimization.classical.run_classical_optimization_optimized(analyzer, initial_params, phi_angles=None, c2_experimental=None, **kwargs)[source]

Optimized classical optimization function.

This is a module-level convenience function that creates a ClassicalOptimizer instance and runs the optimization.

Parameters:
  • analyzer (HeterodyneAnalysisCore) – Analysis core instance

  • initial_params (array-like) – Initial parameter values for optimization

  • phi_angles (array-like, optional) – Angular positions for analysis

  • c2_experimental (array-like, optional) – Experimental correlation data

  • **kwargs – Additional optimization parameters

Returns:

Optimization results (optimized_params, optimization_result)

Return type:

tuple

heterodyne.optimization.classical.run_classical_optimization_optimized_full_signature(analysis_core, config, initial_parameters=None, methods=None, phi_angles=None, c2_experimental=None)[source]

Module-level wrapper for classical optimization with full signature.

This function provides a convenient interface for running classical optimization without explicitly instantiating the ClassicalOptimizer class.

Parameters:
  • analysis_core (HeterodyneAnalysisCore) – Core analysis engine instance

  • config (dict[str, Any]) – Configuration dictionary

  • initial_parameters (np.ndarray, optional) – Starting parameters for optimization

  • methods (list[str], optional) – List of optimization methods to try

  • phi_angles (np.ndarray, optional) – Scattering angles

  • c2_experimental (np.ndarray, optional) – Experimental data

Returns:

(best_parameters, optimization_result)

Return type:

tuple