def get_barlow_params(events, params): ''' get unweighted histograms and normalization factors for barlow LH :type events: a dictionary :param events: baseline events from all dtypes :type params: a dictionary :param params: minimizer start values by user :return unhistos: a dictionary unhistos: unweighted histograms for all dtypes :return norms: a dictionary norms: normalization factors ''' unhistos, norms = Map({}), Map({}) edges = info.get_edges() for dtype in events: ## get unweighted histograms weights = np.ones(len(events[dtype].reco.e)) H, H2 = member.get_histogram(edges, weights=weights) unhistos[dtype] = Map({'H': H, 'H2': H2}) ## get the normalization factor key = 'atmmu' if 'muon' in dtype else 'noise' if 'noise' in dtype else 'numu' norm = params['norm_nutau'] if 'nutau' in dtype else \ params['norm_nc'] if 'nc' in dtype else 1 norm *= params['norm_' + key] norms[dtype] = norm return unhistos, norms
def set_weighters(self, params, matter=True, oscnc=False): ''' set weighters for each member into self. weighters per data type (for all systematic sets) probmaps per numu / nue / nutau (for both CC and NC and all systematic sets) :type params: a dictionary :param params: values of floating parameters :type matter: boolean :param matter: if True, include matter effect :type oscnc: boolean :param oscnc: if True, oscillate NC events ''' weighters = Map({}) pmaps = self.probmaps if hasattr(self, 'probmaps') else Map({}) for dtype in self._dtypes: pmap = pmaps [dtype[:-2]] if 'nu' in dtype and \ dtype[:-2] in pmaps \ else None weighters[dtype] = self._baseline[dtype].get_weighter( params, matter=matter, oscnc=oscnc, pmap=pmap) if 'nu' in dtype: pmaps[dtype[:-2]] = weighters[dtype].probmap self.weighters = weighters self.probmaps = pmaps
def get_hplanes (self, nuparams, matter=True, oscnc=False, verbose=1): ''' collect hyperplane objects from all data types Note: hyperplanes are based upon systematic histograms weighted by the seeded MC values in nuparams :param nuparams (`Nuparams`): user settings of floating parameters :param matter (bool) : If True, include matter effect :param oscnc (bool) : If True, oscillate NC events :param verbose (int) : If 0, no printout If 1, print out basic info If 2, print out info within chi2 fit :return hplanes (dict): hyperplane objects for all members ''' ## collect systematic histograms params = nuparams.extract_params ('seeded') ## only for neutrinos and muons dtypes = [ dtype for dtype in self.members if dtype[:2] in ['nu', 'mu'] ] ## collect systematic information syshistos = Map ({}) if self.verbose > 1: print ('#### collecting sys histograms') for dtype in dtypes: if self.verbose > 1: print ('#### -- {0}'.format (dtype)) hparams = nuparams.get_hplaned_dparams (dtype) syshistos[dtype] = self.collect_sys_histograms (dtype, params, hparams, matter=matter, oscnc=oscnc) if self.verbose > 1: print ('####') ## special treatment for nunc nc = sorted ([ dtype for dtype in dtypes if 'nc' in dtype ]) if len (nc) > 0: dtypes = sorted ([ dtype for dtype in dtypes if not 'nc' in dtype ] + ['nunc']) ## collect hyperplane objects hplanes = Map ({}) ## get hplanes if self.verbose > 1: print ('#### collecting hplanes') for dtype in dtypes: if self.verbose > 1: print ('#### -- {0}'.format (dtype)) hparams = nuparams.get_hplaned_dparams (dtype) ## hyperplane is built only if at least one discrete parameter if len (hparams) == 0: hplanes[dtype] = None; continue expparams = nuparams.get_exp_dparams (dtype) histos = self.merge_nunc (dtype, syshistos, nc) hplanes[dtype] = HyperPlane (dtype, histos, expparams, hparams, verbose=verbose) if self.verbose > 1: print ('####') return hplanes
def _collect_sys_members (self, dtype, hparam, default, has_bulkice): ''' collect all set members for a specific data type and a specific discrete parameter :param hparam (str): name of the discrete systematics :param dtype (str): name of the given member :param default (dict): keys:default values of discrete systematics :param has_bulkice (bool): If True, include bulk ice off axis points :return members (`Map`): dictionary with all `Members` objects ''' set_members = Map ({}) sets = get_sets (dtype, hparam, has_bulkice=has_bulkice) for s in sets: setid, setvalues = self._get_setvalues (s, dtype, hparam, default) isdef = self._check_setid (setid, default) ## don't waste time if it is the default set and already stored if setid in set_members: if not defid == setid: message = 'Library:' + fname + \ ' : WARNING : setid (' + setid + \ ') already exist in the dictionary !' print ('{0}'.format (message)) continue set_members [setid] = Member (dtype, self.ppath, ranges=self._ranges, baseline=False, isdragon=self.isdragon, sysvalues=setvalues) return set_members
def collect_base_histograms(self, params, matter=True, oscnc=False): ''' get all baseline histograms from all members Note: You might want to have weighters set defined otherwise, it will do it here. :type params: a dictionary :param params: values of floating parameters :type matter: boolean :param matter: if True, include matter effect :type oscnc: boolean :param oscnc: if True, oscillate NC events :return histos: a dictionary histos: all baseline histograms ''' start_time = time.time() ## collect baseline histograms histos = Map({}) for dtype in self._dtypes: if self._verbose > 1: print('#### -- {0}'.format(dtype)) member = self._baseline[dtype] histos[dtype] = self._get_histogram(member, params, isbaseline=True, matter=matter, oscnc=oscnc) if self._verbose > 1: print('####') dtime = (time.time() - start_time) / 60. return histos
def merge_nunc(self, dtype, histos, ncdtypes): ''' merge any nc members into one histogram :type dtype: a string :param dtype: name of data type :type histos: a dictionary :param histos: histograms of all discrete sets from all dtypes :type ncdtypes: a list :param ncdtypes: nc data type :return refvalues: a dictionary refvalues: reference values of the discrete parameters :return histos: a dictionary histos: all systematic histograms from this data type ''' ## return if not nunc if not 'nc' in dtype: return histos[dtype] ## massage nc nchistos = Map({}) for setid in histos[ncdtypes[0]]: nchistos[setid] = { 'H': sum([histos[ncdtype][setid]['H'] for ncdtype in ncdtypes]), 'H2': sum([histos[ncdtype][setid]['H2'] for ncdtype in ncdtypes]) } return nchistos
def apply_hplanes(self, bhistos, hplanes, params): ''' multiply hyperplane factor to each member template :type bhistos: a dictionary :param bhistos: all baseline histograms :type hplanes: a dictionary :param hplanes: hyperplane objects for all data types :type params: a dictionary :param params: values of floating parameters :return mhistos: a dictionary mhistos: modified baseline histograms ''' mhistos = Map({}) for dtype in self._dtypes: hplane = hplanes['nunc'] if 'nc' in dtype else \ hplanes[dtype] if dtype in hplanes else None ## if no hyperplane, histo same base histo if not hplane: mhistos[dtype] = bhistos[dtype] continue factors = hplane.apply(params) mhistos[dtype] = { 'H': bhistos[dtype]['H'] * factors, 'H2': bhistos[dtype]['H2'] * factors**2 } return mhistos
def collect_base_histograms (self, params, matter=True, oscnc=False): ''' get all baseline histograms from all members Note: You might want to have weighters set defined otherwise, it will do it here. :param params (dict): values of floating parameters :param matter (bool): If True, include matter effect :param oscnc (bool): If True, oscillate NC events :return histos (dict): all baseline histograms ''' histos = Map ({}) for dtype in self.members: if self.verbose > 1: print ('#### -- {0}'.format (dtype)) member = self._baseline [dtype] histos [dtype] = self._get_histogram (member, params, isbaseline=True, matter=matter, oscnc=oscnc) if self.verbose > 1: print ('####') return histos
def _get_histogram (self, member, params, isbaseline=False, matter=True, oscnc=False): ''' get one histogram from one member :param member (`Member`): a member instance :param params (dict): values of floating parameters :param isbaseline (bool): If True , use self.weighters If False, redefine weighters for sys sets :param matter (bool): If True, include matter effect :param oscnc (bool): If True, oscillate NC events :return hdict (dict): histogram from this member {'H' = histogram weighted by weights, 'H2' = variance of H } ''' dtype = member.dtype if isbaseline: ## BASELINE: weighters in self if not hasattr (self, 'weighters'): self.set_weighters (params, matter=matter, oscnc=oscnc) weighter = self.weighters [dtype] else: ## NOT BASELINE: one-time weighter pmap = self.probmaps[dtype[:-2]] if 'nu' in dtype else None weighter = member.get_weighter (params, matter=matter, oscnc=oscnc, pmap=pmap) weights = member.get_weights (params, weighter=weighter) H, H2 = member.get_histogram (self.edges, weights=weights) return Map ({'H':H, 'H2':H2})
def _get_sys_histograms(self, dtype, params, hparams, default, matter=True, oscnc=False): ''' get all systematic histograms of a data type. :type dtype: a string :param dtype: name of data type :type params: a dictionary :param params: values of floating parameters :type hparams: a list :param hparams: discrete parameters to be included in hplane :type default: a dictionary :param default: keys/default values of discrete systematics :type matter: boolean :param matter: if True, include matter effect :type oscnc: boolean :param oscnc: if True, oscillate NC events :return histos: a dictionary histos: all systematic histograms ''' histos = Map({}) has_bulkice = 'scattering' in hparams and 'absorption' in hparams for hp in sorted(hparams): if self._verbose > 1: print('#### -- {0}'.format(hp)) ## get member of this discrete param members = self._collect_sys_members(dtype, hp, default, has_bulkice) ## get histogram from each set for setid in members: if self._verbose > 1: print('#### -- {0}'.format(setid)) # check if it is default set isdef = self._check_setid(setid, default) # don't waste time on redoing default set if isdef and setid in histos: continue # get histogram of this setid histos[setid] = self._get_histogram(members[setid], params, isbaseline=False, matter=matter, oscnc=oscnc) # define normalization factor if isdef: norm = np.sum(histos[setid]['H']) # apply normalization factor if coin set if hp == 'coin': hsum = np.sum(histos[setid]['H']) factor = norm / hsum if hsum else 1.0 histos[setid]['H'] *= factor if self._verbose > 1: print('####') return histos
def ts_func (self, dm31, theta23, theta13, nyears, gamma, nue_numu_ratio, muon_flux, barr_nu_nubar, barr_nubar_ratio, barr_uphor_ratio, norm_noise, norm_numu, norm_nc, norm_atmmu, norm_nugen, norm_nugenHE, norm_corsika, norm_nutau, domeff, holeice, forward, coin, absorption, scattering, axm_res, axm_qe, DISa_nu, DISa_nubar, spe_corr): ''' determine ts value. This function will be looped many many times. ''' ### recognize, check, and print parameters local = locals () params = {} for p in local: if p in self._nuparams.get_all_params (): params[p] = local[p] self._check_params (params) ### update histogram with these params uhistos = self._lib.collect_base_histograms (params) uhistos = self._lib.apply_hplanes (uhistos, self._temp.hplanes, params) uhistos = self._lib.scale_histos (uhistos, params) template = Map ({ 'H':sum ([uhistos[dtype]['H'] for dtype in uhistos]), 'H2':sum ([uhistos[dtype]['H2'] for dtype in uhistos]) }) ### calculate test statistics self._LH.set_histos (uhistos) rawts, bints, As = self._LH.get_ts () ### add prior terms ts = self._add_penalties (rawts, params) ### print outs if self._verbose > 3: self._print_rates (uhistos, template, rawts) ### save results if needed if ts < self.tsvalue: self.tsvalue = ts self.bestfit = Map ({ 'H':template['H'], 'H2':template['H2'], 'ts':bints }) self.barlow_As = As ### update internal parameter values self._params = params return ts
def __init__ (self, nuparams, params, lib, LH, temp, fparams=None, verbose=1): ''' initialize fitter class :type nuparams: a Nuparams object :param nuparams: users setting of nuisance parameters :type params: a dictionary :param params: values of parameters :type lib: a Library object :param lib: info of all members / dtypes involved :type LH: a Likelihood object :param LH: likelihood for minimization :type temp: a Template object :param temp: template objects for printing histogram rates :type fparams: a numpy array / list :param fparams: osc parmaeters to be fixed :type verbose: int :param verbose: If 0: no printout. If 1: minimum printout. If 2: print iteration, oscparams blinded. If 3: print iteration, unblinded. If 4: print info per bin per iteration; oscparams unblineded ''' print ('#### ##################################################') print ('#### ################### Fitter #######################') print ('####') self._nuparams = nuparams self._params = params self._lib, self._LH, self._temp = lib, LH, temp self._fparams = fparams self._verbose = verbose ## define holders self.bestfit = Map ({'H':[], 'H2':[], 'ts':[]}) self.tsvalue = np.inf self.barlow_As = None ## print info if self._verbose > 1: self._print_header () ## minimize ! self.results = self._minimize () print ('#### ##################################################')
def apply_cut (self, ddict, cut): ''' apply cut to a dictionary :param ddict (`Map`): dictionary containing all events :param cut (np.array of bool): boolean to select events :return cdict (`Map`): dictionary containing selected events ''' cdict = Map({}) for key in ddict.keys(): ### deal with arrays cdict[key] = toolbox.chop (ddict[key], cut) ### deal with arrays in dictionary if toolbox.is_dict (ddict[key]): cdict[key] = Map ({}) for skey in ddict[key].keys(): cdict[key][skey] = toolbox.chop (ddict[key][skey], cut) return cdict
def _collect_base_members (self): ''' collect all baseline members :return members (`Map`): dictionary with all `Members` objects ''' members = Map ({}) for dtype in self.members: members[dtype] = Member (dtype, self.ppath, ranges=self._ranges, isdragon=self.isdragon, baseline=True) return members
def _collect_base_members(self): ''' collect all baseline members :return members: a Map object members: contains all members objects ''' members = Map({}) for dtype in self._dtypes: members[dtype] = Member(dtype, self._pdictpath, ranges=self._ranges, baseline=True) return members
def _get_histogram(self, member, params, isbaseline=False, matter=True, oscnc=False): ''' get one histogram from one member :type member: a Member object :param member: events to be histogrammed :type params: a dictionary :param params: values of floating parameters :type isbaseline: boolean :param isbaseline: if True, use self.weighters if False, redefine weighters for sys sets :type matter: boolean :param matter: if True, include matter effect :type oscnc: boolean :param oscnc: if True, oscillate NC events :return hdict: a dictionary hdict: 'H' = histogram weighted by weight 'H2' = histogram weighted by weight**2 ''' dtype = member.get_dtype() if isbaseline: ## BASELINE: weighters in self if not hasattr(self, 'weighters'): self.set_weighters(params, matter=matter, oscnc=oscnc) weighter = self.weighters[dtype] else: ## NOT BASELINE: one-time weighter pmap = self.probmaps[dtype[:-2]] if 'nu' in dtype else None weighter = member.get_weighter(params, matter=matter, oscnc=oscnc, pmap=pmap) weights = member.get_weights(params, weighter=weighter) H, H2 = member.get_histogram(self._edges, weights=weights) return Map({'H': H, 'H2': H2})
def _get_totalmc (self, histos): ''' get total mc from histograms of all data types :type histos: dictionary :param histos: {'numucc': {'H':[], 'H2':[]}, 'nuecc' : {'H':[], 'H2':[]}, ...} :return totalmc: a dictionary totalmc: total MC {'H':[], 'H2':[]} ''' mc = Map ({'H':np.zeros (self._shape), 'H2':np.zeros (self._shape)}) for i, dtype in enumerate (self._dtypes): mc['H'] += histos[dtype]['H'] mc['H2'] += histos[dtype]['H2'] return mc
def collect_events(lib, dtypes): ''' collect baseline events. :type lib: a Library object :param lib: contains events for all members :type dtypes: a list or numpy array :param dtypes: datatypes involved :return events: a dictionary / Map events: baseline events for all dtypes ''' events = Map({}) for dtype in dtypes: events[dtype] = lib._baseline[dtype]._events return events
def get_data(self, params, fitdata, diff): ''' obtain data histogram :type params: dictionary :param params: values of floating parameters :type fitdata: boolean :param fitdata: If True, fit to real data :type diff: boolean :param diff: If True, injected is different from seeded :retrun H: a multi-dimensional array H: data histogram in counts :return H2: a multi-dimensional array H2: variance of data histogram ''' if fitdata: ## If fitdata, fit to real data data = Member('data', self.ppath, ranges=self.get_ranges()) weights = data.get_weights(params) H, H2 = data.get_histogram(self.edges, weights=weights) ## scaled by factors (in counts) norm = seconds_per_year * params['nyears'] H *= norm H2 *= norm**2 elif diff: ## If injected and seeded are different, build data histogram ## library and baseline histograms from the injected param lib, bhistos = self.get_baseline_histograms(params) ## get template with injected data mhisto, temp = self.get_template(params, lib, bhistos) H, H2 = temp['H'], temp['H2'] else: ## If none of the above, copy mc template from baseline H, H2 = self.template['H'], self.template['H2'] ## store and print data histogram self.dhisto = Map({'H': H, 'H2': H2}) self._print_rates('data', self.dhisto) return self.dhisto
def read_nuparams (self): ''' Read text file and store information :return: a dictionary of user's parameter settings ''' params = Map({}) textfile = open (self._textfile, "r") # open text file # loop through each line in the text file for line in (raw.strip().split() for raw in textfile): # skip this line if no character or first character is # if not line or line[0][0]=='#': continue pname = line[0] # check cont or disc values to be used values = disc_values if pname in discrete_parameters else cont_values params[pname] = read_param (values, self._isinverted, line) textfile.close() # close text file return params
def scale_histos (self, histos, params): ''' scale histograms by appropriate factors :param histos (dict): histograms to be scaled :param params (dict): values of floating parameters :return shistos (dict): scaled histograms ''' shistos = Map ({}) for dtype in histos: ## get the normalization factor key = 'atmmu' if 'muon' in dtype else \ 'noise' if 'noise' in dtype else 'numu' norm = params['norm_nutau'] if 'nutau' in dtype else \ params['norm_nc'] if 'nc' in dtype else 1. norm *= params['norm_'+key]*seconds_per_year*params['nyears'] ## scale this histogram shistos[dtype] = {'H' : histos[dtype]['H'] * norm, 'H2': histos[dtype]['H2'] * norm**2} return shistos
def get_histos(params, filenames): ''' get a set of histograms with either lower or upper sigmas :type params: list :param params: a list of parameter names :type sigma: list :param sigma: a list of filenames with histograms :return results: dictionary results: cascade and track chi / percentage {'param': {'cascade':[], 'track':[]} } ''' results = Map({}) for param in params: logger.info('#### -- {0}'.format(param)) filename = [filename for filename in filenames if param in filename] ### check filename length; must be 1. if not len(filename) == 1: message = 'histoeffect:get_histos :: ' + param + \ ' has a file length of '+str (len (filename)) raise InvalidArguments(message) ### get histograms with open(filename[0], 'rb') as f: histo = cPickle.load(f) f.close() histo = cPickle.loads(histo) ### calculate comparisons in cascade/track results[param] = compare(histo.template, histo.dhisto) edges = { 'x': np.log10(histo.edges['e']), 'y': np.cos(histo.edges['z'])[::-1] } logger.info('#### ') return results, edges
def _collect_sys_members(self, dtype, hparam, default, has_bulkice): ''' collect all set members for a specific data type and a specific discrete parameter :type hparam: a string :param hparam: name of the discrete systematics :type dtype: a string :param dtype: name of the data type :type default: a dictionary :param default: keys/default values of discrete systematics :type has_bulkice: a boolean :param has_bulkice: if True, include bulk ice off axis points :return members: a Map object members: 99contains all members objects ''' set_members = Map({}) sets = get_sets(dtype, hparam, has_bulkice=has_bulkice) for s in sets: setid, setvalues = self._get_setvalues(s, dtype, hparam, default) isdef = self._check_setid(setid, default) ## don't waste time if it is the default set and already stored if setid in set_members: if not defid == setid: message = 'Library:'+fname+' : WARNING : setid (' + \ setid + ') already exist in the dictionary !' print('{0}'.format(message)) continue set_members[setid] = Member(dtype, self._pdictpath, ranges=self._ranges, baseline=False, sysvalues=setvalues) return set_members
def __init__ (self, dhisto, method, verbose=1): ''' initialize likelihood object :type dhisto: dictionary :param dhisto: data histogram {'H':[], 'H2':[]} :type method: string :param method: 'barlow', 'poisson', 'chi2', 'modchi2' :type verbose: int :param verbose: If 0, no print out If 1, basic print out If 4, detailed print out per bin ''' self._dhisto = dhisto self._method = method self._verbose = verbose self._shape, self._nbins = self._set_params () self._dhisto = Map ({ 'H':self._dhisto.H.flatten (), 'H2':self._dhisto.H2.flatten () })
def merge_nunc (self, dtype, histos, ncdtypes): ''' merge all nc members into one histogram :param dtype (str) : name of this data type :param histos (`Map`): histograms of all discrete sets from all dtypes :param ncdtypes (list) : names of all NC members :return nchistos (`Map`): merged NC histograms ''' ## return if not nunc if not 'nc' in dtype: return histos[dtype] ## massage nc nchistos = Map ({}) for setid in histos[ncdtypes[0]]: nchistos[setid] = {'H': sum ([ histos[ncdtype][setid]['H'] for ncdtype in ncdtypes ]), 'H2': sum ([ histos[ncdtype][setid]['H2'] for ncdtype in ncdtypes ]) } return nchistos
########################################### #### start fitter ########################################### start_time = time.time() ## perform fit fit = Fitter(nuparams, params, lib, LH, temp, fparams=fparams, verbose=verbose) ## dump output output = { 'bints': fit.bestfit.ts, 'ts': fit.results.fval, 'params': convert_to_dict(fit.results.values), 'errors': convert_to_dict(fit.results.errors), 'histos': Map({ 'H': fit.bestfit.H, 'H2': fit.bestfit.H2 }), 'barlow_As': fit.barlow_As } with open(outfile, 'wb') as f: cPickle.dump(output, f, protocol=2) f.close() ## print results if fitter doesn't if verbose < 4: print_result(output) print('#### fitting takes {0} minuites.'.format( (time.time() - start_time) / 60.))
def read_param (values, isinverted, *args): ''' A function to interprete a line defined for a given parameter Parameters ---------- :value :list :either cont_values or disc_values :isinverted :boolean :if true, dm31 is inverted :*args :an array :a split line from nuparam_textfile For a continuous param ---------------------- required: [0] : name ; [1] : seeded; [2] : injected ; [3] : included ; [4] : value ; [5] : lower_limit; [6] : upper_limit; [7] : error optional: [8] : prior ; [9] : penalty For a discrete param -------------------- required: [0] : name ; [1] : nu_func ; [2] : mu_func ; [3] : seeded ; [4] : injected; [5] : hplaned ; [6] : included ; [7] : value ; [8] : lower_limit; [9] : upper_limit; [10]: error optional: [11]: prior ; [12]: penalty Returns ------- :pdict :a Map object :a dictionary with user's setting for this parameter Note ---- Ordering of parameters and columns in textfile are set to be the same. Example ------- In[0]: from misc import read_param, disc_values, cont_values, discrete_parameters In[1]: textfile = open ('nuisance_textfiles/nuparams_template.txt', "r") In[2]: for line in (raw.strip().split() for raw in textfile): -----: if not line or line[0][0]=='#': continue -----: break In[3]: values = disc_values if line[0] in discrete_parameters else cont_values In[4]: this_param = read_param (values, True, line) ''' param = Map ({}) args = args[0] ## check length of arguments if not (len(args) == len(values) or len(args) == len(values)-2): message = 'nuparams:read_param :: ' + args[0] + ' ('+str(len(values)) + \ '): unexpected number of arguements (' + str (len(args)) + ')' raise InvalidArguments (message) ## loop through each arguement for index, value in enumerate (values): ## skip first column (name) #if index==0: continue ## skip prior / penalty if not given if index in np.arange (len (values))[-2:] and len(args) == len(values)-2: continue vname, vtype = value setting = args[index] if index==0 or 'func' in vname else f(args[index]) ## check if type is correct if not vtype == type (setting): message = 'nuparams:read_param :: ' + args[0] + ' ' + vname + ' ('+ vtype + \ '): unexpected arguement type (' + type(setting) + ')' raise InvalidArguments (message) ## check if correct function name for nu/mu_func if 'func' in vname: if not setting in ['linear', 'parabola', 'exp']: message = 'nuparams:read_param :: ' + args[0] + ' ' + vname + \ ': unexpected function name (' + type(setting) + ')' raise InvalidArguments (message) ## modify values if inverted if isinverted and args[0]=='dm31': if vname in ['seeded', 'injected', 'value', 'lower_limit', 'upper_limit']: setting *= -1. ## put into param param[vname] = setting param['isdiscrete'] = values==disc_values ## if inverted, reverse dm31 limit if isinverted and args[0]=='dm31': limits = (param['lower_limit'], param['upper_limit']) param['lower_limit'], param['upper_limit'] = limits[1], limits[0] return param