Source code for pyspex.optimize
#!/usr/bin/env python
from . import pyspex_f2py
import math
[docs]class Fit:
"""This is the parent class of all fit related commands.
:ivar stat: Fit statistics.
:vartype stat: basestring
:ivar cstat: C-statistics value.
:vartype cstat: float
:ivar chisq: Chi-squared value.
:vartype chisq: float
:ivar wstat: W-statistics value (not recommended).
:vartype wstat: float
:ivar nfree: Degrees of freedom.
:vartype nfree: int
:ivar cstatexp: Expected C-statistics value (C-stat only).
:vartype cstatexp: float
:ivar cstatrms: RMS uncertainty on expected C-stat value.
:vartype cstatrms: float
:ivar ann_rt: Simulated annealing: rt
:vartype ann_rt: float
:ivar ann_eps: Simulated annealing: eps
:vartype ann_eps: float
:ivar ann_t: Simulated annealing: t
:vartype ann_t: float
:ivar ann_vm: Simulated annealing: vm
:vartype ann_vm: float
:ivar ann_ns: Simulated annealing: ns
:vartype ann_ns: int
:ivar ann_max: Simulated annealing: max evaluations
:vartype ann_max: int
:ivar ann_print: Simulated annealing: print flag
:vartype ann_print: int
"""
def __init__(self):
self.stat = 'csta' # Fit statistics
self.meth = 'clas' # Fit method
self.cstat = 0. # C-statistics value
self.chisq = 0. # Chi-square value
self.wstat = 0. # W-statistics value
self.nfree = 0 # Degrees of freedom
self.cstatexp = 0. # Expected C-statistics value (C-stat only)
self.cstatrms = 0. # RMS uncertainty on expected C-stat value
self.ann_rt = 0. # Simulated annealing: rt
self.ann_eps = 0. # Simulated annealing: eps
self.ann_t = 0. # Simulated annealing: t
self.ann_vm = 0. # Simulated annealing: vm
self.ann_ns = 0 # Simulated annealing: ns
self.ann_max = 0 # Simulated annealing: max evaluations
self.ann_print = 0 # Print flag
# Set 'fit print 1' automatically
self.print(True)
[docs] def fit(self, niter=100):
"""Execute the SPEX fit command. The maximum number of iterations (niter) can be optionally set.
:param niter: Number of fit iterations.
:type niter: int
"""
pyspex_f2py.api_optimize_fit.api_fit(iter=float(niter))
self.update()
[docs] def set_statistic(self, stat):
"""Set the desired fit statistics.
:param stat: Abbreviation for the fit statistics to be used. For example: 'csta', 'chi2', 'wsta'.
:type stat: str
"""
pyspex_f2py.api_optimize_fit.api_fit_set_statistics(stat)
[docs] def set_statistic_inst(self, stat, inst, reg):
"""Set the desired fit statistics per instrument and region.
:param stat: Abbreviation for the fit statistics to be used. For example: 'csta', 'chi2', 'wsta'.
:type stat: str
:param inst: Instrument number.
:type inst: int
:param reg: Region number.
:type reg: int
"""
pyspex_f2py.api_optimize_fit.api_fit_set_statistics_inst(stat, inst, reg)
[docs] def get_statistic(self):
"""Get the current type of statistics being used in the fit, for example chi2, cstat or wstat."""
self.stat = pyspex_f2py.api_optimize_fit.fit_stat.view('S4').tobytes().decode('utf-8')
[docs] def set_method(self, meth):
"""Set the desired fit statistics.
:param stat: Abbreviation for the fit statistics to be used. For example: 'csta', 'chi2', 'wsta'.
:type stat: str
"""
pyspex_f2py.api_optimize_fit.api_fit_set_method(meth)
[docs] def get_method(self):
"""Get the current type of statistics being used in the fit, for example chi2, cstat or wstat."""
self.meth = pyspex_f2py.api_optimize_fit.fit_meth.view('S4').tobytes().decode('utf-8')
[docs] def set_ann(self, param, value):
"""Set the simulating annealing method parameters.
:param param: Type of annealing parameter (rt, t, eps, vm, ns, max, or print).
:type param: str
:param value: Value of the parameter (will be converted to the nearest int if necessary).
:type value: float
"""
pyspex_f2py.api_optimize_fit.api_fit_set_ann(param, value)
self.update()
[docs] def print(self, status):
"""Print each fit iteration to the console (default is True). The status variable can be either True or False,
which means printing is on or off, respectively.
:param status: Set fit to high verbosity (True is yes, False is no).
:type status: bool
"""
if status:
pyspex_f2py.api_command('fit print 1')
else:
pyspex_f2py.api_command('fit print 0')
[docs] def update(self):
"""Get the most recent statistics values from SPEX."""
pyspex_f2py.api_optimize_fit.api_fit_update()
self.cstat = pyspex_f2py.api_optimize_fit.fit_cstat
self.chisq = pyspex_f2py.api_optimize_fit.fit_chisq
self.wstat = pyspex_f2py.api_optimize_fit.fit_wstat
self.nfree = pyspex_f2py.api_optimize_fit.fit_nfree
self.cstatexp = pyspex_f2py.api_optimize_fit.fit_cstatexp
self.cstatrms = pyspex_f2py.api_optimize_fit.fit_cstatrms
self.ann_rt = float(pyspex_f2py.api_optimize_fit.fit_ann_rt)
self.ann_eps = float(pyspex_f2py.api_optimize_fit.fit_ann_eps)
self.ann_t = float(pyspex_f2py.api_optimize_fit.fit_ann_t)
self.ann_vm = float(pyspex_f2py.api_optimize_fit.fit_ann_vm)
self.ann_ns = int(pyspex_f2py.api_optimize_fit.fit_ann_ns)
self.ann_max = int(pyspex_f2py.api_optimize_fit.fit_ann_maxevl)
self.ann_print = int(pyspex_f2py.api_optimize_fit.fit_ann_print)
self.get_method()
self.get_statistic()
[docs] def show(self):
"""Print the fit statistics to the terminal."""
print("---------------------------------------------------------------------------------------------------")
if self.meth == 'clas':
print("Fit method : Classical Levenberg-Marquardt")
elif self.meth == 'simp':
print("Fit method : Simplex")
elif self.meth == 'sian':
print("Fit method : Simulated annealing method")
else:
print("Fit method : {0:s}".format(self.meth))
if self.stat == 'csta':
print("Fit statistic : C-statistic")
elif self.stat == 'chi2':
print("Fit statistic : Chi-squared statistic")
elif self.stat == 'wsta':
print("Fit statistic : W-statistic")
else:
print("Fit statistic : {0:s}".format(self.stat))
print("C-statistic : {0:#7.2f}".format(self.cstat))
print("Expected C-stat : {0:#7.2f} +/- {1:#7.2f}".format(self.cstatexp, self.cstatrms))
print("Chi-squared value : {0:#7.2f}".format(self.chisq))
print("Degrees of freedom: {0:d}".format(self.nfree))
print("W-statistic : {0:#7.2f}".format(self.wstat))
[docs]class Error:
"""Class to calculate errors for free fit parameters.
:ivar sector: Sector number of parameter
:vartype sector: int
:ivar component: Component number of parameter
:vartype component: int
:ivar parameter: Parameter name
:vartype parameter: str
:ivar value: Parameter value
:vartype value: float
:ivar lerr: Lower error boundary
:vartype lerr: float
:ivar uerr: Upper error boundary
:vartype uerr: float
:ivar lc: Is there a lower C-stat or chi**2 value found?
:vartype lc: bool
:ivar cmin: Lowest C-stat or chi**2 value
:vartype cmin: float
:ivar pmin: Parameter value for which a better C-stat or Chi**2 was found
:vartype pmin: float
:ivar dchi: Delta C-stat or chi**2 to optimize for
:vartype dchi: float
:ivar calculated: Is the error calculated?
:vartype calculated: bool
"""
def __init__(self):
self.sector = 1 # Sector number of parameter
self.component = 1 # Component number of parameter
self.parameter = '' # Parameter name
self.value = 0.0 # Parameter value
self.lerr = 0.0 # Lower error boundary
self.uerr = 0.0 # Upper error boundary
self.lc = False # Is there a lower C-stat or chi**2 value found
self.cmin = 0.0 # Lowest C-stat or chi**2 value
self.pmin = 0.0 # Parameter value for which a better C-stat or Chi**2 was found
self.dchi = 1.0 # Delta C-stat or chi**2 to optimize for
self.calculated = False # Is the error calculated?
[docs] def error(self, isect, icomp, name, dchi=None):
"""Calculate the error value for a particular parameter.
:param isect: Sector number of the parameter.
:type isect: int
:param icomp: Component number of the parameter.
:type icomp: int
:param name: Parameter name.
:type name: str
:param dchi: (Optional) :math:`\Delta\chi^2` value to optimize for (Default: 1.0, 68% errors)
:type dchi: float
"""
if dchi is not None:
ier = self.set_dchi(dchi)
if ier != 0:
print("Error setting dchi for the error calculation.")
return ier
self.sector = isect
self.component = icomp
self.parameter = name
self.calculated = True
self.lc = False
pyspex_f2py.api_optimize_error.api_error_calc(float(isect), float(icomp), name)
self.value = float(pyspex_f2py.api_optimize_error.error_par)
self.lerr = float(pyspex_f2py.api_optimize_error.error_low)
self.uerr = float(pyspex_f2py.api_optimize_error.error_up)
if pyspex_f2py.api_optimize_error.error_lc:
self.lc = True
self.cmin = float(pyspex_f2py.api_optimize_error.error_cmin)
self.pmin = float(pyspex_f2py.api_optimize_error.error_pmin)
[docs] def set_dchi(self, dchi):
"""Set the delta c-stat or delta chi**2 value that the error search should optimize for.
The default value is 1.0.
:param dchi: :math:`\Delta\chi^2` value to optimize for (Default: 1.0, 68% errors)
:type dchi: float
"""
if (dchi > 0):
ier = pyspex_f2py.api_command('error dchi ' + str(dchi))
else:
print('Error: Delta C-stat or chi**2 needs to be positive.')
ier = 1
return ier
[docs] def get_value(self):
"""Convenience function to return the parameter value and the errors.
:return: A tuple with the parameter value, lower error and upper error.
:rtype: tuple
"""
if (self.calculated):
print('Returning parameter ' + str(self.sector) + ' ' + str(self.component) + ' ' + self.parameter)
return self.value, self.lerr, self.uerr
else:
print('Error: Error is not calculated yet.')