def fit(self, conf = False): ui.ignore(None, None) ui.notice(self.start, self.stop) self.set_source() ui.fit(1) if conf: ui.conf() res = ui.get_fit_results() for line in (self.H2lines + self.nonH2lines): sourcename = line['source'].split('.')[1] print sourcename for p in ['pos', 'fwhm', 'ampl']: n = '{0}.{1}'.format(sourcename, p) _place_val(line, p, ui.get_par(n).val) self.const = ui.get_par('c1.c0').val self.redchi2 = res.rstat if conf: res = ui.get_conf_results() for line in (self.H2lines + self.nonH2lines): sourcename = line['source'].split('.')[1] for p in ['pos', 'fwhm', 'ampl']: n = '{0}.{1}'.format(sourcename, p) parmin, parmax = _parminmax(res, n) line[p+'_max'] = parmax line[p+'_min'] = parmin # deal with error on const parmin, parmax = _parminmax(res, 'c1.c0') self.const_min = parmin self.const_max = parmax
def center_psf(self): """Set ``xpos`` and ``ypos`` of the PSF to the dataspace center.""" import sherpa.astro.ui as sau try: ny, nx = sau.get_data().shape for _ in ['psf1', 'psf2', 'psf3']: par = sau.get_par(_ + '.xpos') par.val = nx / 2. par = sau.get_par(_ + '.ypos') par.val = ny / 2. except: raise Exception('PSF is not centered.')
def _set_val(model, argstring, val): '''Set the value of a Sherpa model parameter Parameters ---------- model : sherpa model instance argstring : string name of the parameter, e.g. 'kT' or 'norm' val : string or number Value to be set. Can be number or string of the form 'f 1234' which set the parameter to 1234 and freezes it. ''' par = ui.get_par(model.name+'.'+argstring) if isinstance(val, basestring): if val[0] == '"': val = val[1:-1] val = val.strip('" \t').strip("' \t").split() par.frozen = False for v in val: print v if v == 'f': par.frozen = True elif _isfloat(v): par.val = float(v) else: raise ValueError('Not valid format to set a parameter {0}'.format(v)) else: par.frozen = False par.val = val
def fit(self): """ Do a fit of the model parameters using the "onion-peeling" method: - First fit the outside shell model using the outer annulus spectrum - Freeze the model parameters for the outside shell - Fit the next inward shell / annulus and freeze those parameters - Repeat until all datasets have been fit and all shell parameters determined. - Return model parameters to original thawed/frozen status :rtype: None """ thawed = [] # Parameter objects that are not already frozen for annulus in reversed(range(self.nshell)): dataids = [x['id'] for x in self.datasets if x['annulus'] == annulus] print 'Fitting', dataids SherpaUI.fit(*dataids) for model_comp in self.model_comps: name = model_comp['name'] if model_comp['shell'] == annulus: # Remember parameters that are currently thawed for par in [SherpaUI.get_par('%s.%s'%(name, x)) for x in SherpaUI.get_model_pars(name)]: if not par.frozen: thawed.append(par) print 'Freezing', model_comp['name'] SherpaUI.freeze(model_comp['name']) # Unfreeze parameters for par in thawed: print 'Thawing', par.fullname par.thaw()
def _get_parameter_value(name, val): """Return a numeric value given one of: a number a model parameter (something with a .val field) a string nameing a model parameter The name field is used in any error message, val is the value to decode. Raises an ValueError if unable to retrieve a number. If val is not a string or without a .val field then we just return val. We do not throw an error. """ # Could try isinstance(val, sherpa.models.parameter.Parameter) # here instead, but stick with hasattr for now # if hasattr(val, "val"): return val.val elif isinstance(val, str): try: return ui.get_par(val).val except ArgumentErr: raise ValueError( "Name of {0} argument does not appear to be a model parameter: '{1}'" .format(name, val)) else: return val
def test_user_model_stat_docs(): """ This test reproduces the documentation shown at: http://cxc.harvard.edu/sherpa4.4/statistics/#userstat and: http://cxc.harvard.edu/sherpa/threads/user_model/ I tried to be as faithful as possible to the original, although the examples in thedocs are not completely self-contained, so some changes were necessary. I changed the numpy reference, as it is imported as `np` here, and added a clean up of the environment before doing anything. For the model, the difference is that I am not importing the function from an external module, plus the dataset is different. Also, the stats docs do not perform a fit. """ def my_stat_func(data, model, staterror, syserror=None, weight=None): # A simple function to replicate χ2 fvec = ((data - model) / staterror)**2 stat = fvec.sum() return (stat, fvec) def my_staterr_func(data): # A simple staterror function return np.sqrt(data) def myline(pars, x): return pars[0]*x + pars[1] x = [1, 2, 3] y = [4, 5, 6.01] ui.clean() ui.load_arrays(1, x, y) ui.load_user_stat("mystat", my_stat_func, my_staterr_func) ui.set_stat(eval('mystat')) ui.load_user_model(myline, "myl") ui.add_user_pars("myl", ["m", "b"]) ui.set_model(eval('myl')) ui.fit() assert ui.get_par("myl.m").val == approx(1, abs=0.01) assert ui.get_par("myl.b").val == approx(3, abs=0.01)
def conf(self): """ Run conf on each of the model parameters using the "onion-peeling" method: - First conf the outside shell model using the outer annulus spectrum - Freeze the model parameters for the outside shell - get confidences for the next inward shell / annulus and freeze those parameters - Repeat until all datasets have been conf()-ed and all shell-by-shell error parameters determined. - Return model parameters to original thawed/frozen status - WARNING: This ignores the correlations between parameters :rtype: None """ thawed = [] # Parameter objects that are not already frozen conf_results = [] this_conf_result = [] for annulus in reversed(range(self.nshell)): dataids = [x['id'] for x in self.datasets if x['annulus'] == annulus] print 'Getting shell-by-shell confidence for dataset ', dataids SherpaUI.conf(*dataids) this_conf_result = SherpaUI.get_conf_results() conf_results.insert(0, this_conf_result) for model_comp in self.model_comps: name = model_comp['name'] if model_comp['shell'] == annulus: # Remember parameters that are currently thawed for par in [SherpaUI.get_par('%s.%s'%(name, x)) for x in SherpaUI.get_model_pars(name)]: if not par.frozen: thawed.append(par) print 'Freezing', model_comp['name'] SherpaUI.freeze(model_comp['name']) # Unfreeze parameters for par in thawed: print 'Thawing', par.fullname par.thaw() return conf_results
def test_341(): """ The original reporter of bug #341 had a special implementation that should be captured by this test. The implementation has a proxy model that takes care of updating the actual model when it is evaluated. During a recent refactoring of the Stat and Fit code (PR #287) a regression was introduced by short-circuiting the evaluation of the model. """ class ExampleModel(object): """ Class to define model """ def __init__(self, x, y): self.x = np.array(x) self.y = np.array(y) self.parvals = [1, 2] self.parnames = ("m", "b") def calc_stat(self): return float(np.sum(np.abs(self.y - self.model()))) def model(self): return self.parvals[0] * self.x + self.parvals[1] class CalcModel(object): """ Class to update model parameters """ def __init__(self, model): self.model = model def __call__(self, pars, x): self.model.parvals = pars return np.ones_like(x) class CalcStat(object): """ Class to determine fit statistic """ def __init__(self, model): self.model = model def __call__(self, _data, _model, *args, **kwargs): fit_stat = self.model.calc_stat() return fit_stat, np.ones(1) xdata = [1, 2, 3] ydata = [4, 5, 6] newmodel = ExampleModel(xdata, ydata) dummy_data = np.zeros(1) dummy_times = np.arange(1) ui.load_arrays(1, dummy_times, dummy_data) method = 'simplex' ui.set_method(method) ui.load_user_model(CalcModel(newmodel), 'simplemodel') ui.add_user_pars('simplemodel', newmodel.parnames) ui.set_model(1, 'simplemodel') calc_stat = CalcStat(newmodel) ui.load_user_stat('customstat', calc_stat, lambda x: np.ones_like(x)) ui.set_stat(eval('customstat')) ui.fit(1) assert ui.get_par("simplemodel.m").val == approx(1, abs=0.00001) assert ui.get_par("simplemodel.b").val == approx(3, abs=0.00001)