def setSuffix(selforcls, newSuffix): if newSuffix is None: return testfor( isString(newSuffix) and len(newSuffix) > 0, SuffixError, "Parameter suffix has to be some text!") selforcls._suffix = newSuffix
def setGenerator(selforcls, newGenerator): if isinstance(newGenerator, type): testfor(issubclass(newGenerator, NumberGenerator), ParameterGeneratorError, "NumberGenerator type expected!") else: newGenerator = RandomUniform selforcls._generator = newGenerator
def setValue(selforcls, newValue): testfor(newValue is not None, DefaultValueError, "Default value is mandatory!") if selforcls._value == newValue: return # no update necessary selforcls._value = newValue if isCallable(selforcls.onValueUpdate()): selforcls.onValueUpdate()()
def setValue(selforcls, newValue, clip=True): if newValue is None: return # ignore testfor(isNumber(newValue), DefaultValueError, u"A value has to be numerical! ({})".format(newValue)) if clip: # clip to min/max values: newValue = selforcls.clip(newValue) super(ParameterNumerical, selforcls).setValue(newValue)
def setValueRange(self, newRange): testfor(isList(newRange), ValueRangeError, "A value range for a string type parameter has to be a list!") testfor(all([isString(v) for v in newRange]), ValueRangeError, "A value range for a string has to be a list of strings!") self._valueRange = newRange if not (self.value() in self.valueRange()): # where are the default values? self.setValue(self.valueRange()[0])
def __call__(self, dataset): if self.model is None: logging.warning("No model set!") return # start log file writing testfor(isinstance(dataset, DataSet), Exception, "{cls} requires a DataSet!".format(cls=type(self))) self._outFn = OutputFilename(dataset) fn = self._outFn.filenameVerbose("log", "this log") logFile = logging.FileHandler(fn, encoding="utf8") widgetHandler = log.getWidgetHandlers()[0] log.replaceHandler(widgetHandler) # remove everything else log.addHandler(logFile) try: # show last lines about pdf output from separate thread widgetHandler.widget.addWatchDir(self._outFn.outDir) except AttributeError: pass self._writeSettings(dict(), dataset) if self.nolog: # refers to the widgethandler log.removeHandler(widgetHandler) #set data in the algorithm self._algo.data = dataset # write HDF5, show exceptions traceback, if any try: self.hdfStore(self._outFn.filenameVerbose( "hdf5archive", "Complete state of the calculation", extension='.hdf5'), rootLocation="mcsasentry") except Exception as e: import traceback print(traceback.format_exc()) self._algo.calc() if self.nolog: log.addHandler(widgetHandler) if isList(self._algo.result) and len(self._algo.result): res = self._algo.result[0] # quick hack for now, will get fixed with Parameter design for p in self.model.activeParams(): self._writeDistrib(p) self._writeStatistics(p) self._updateSeries(dataset, self.model) # plotting last so stats were already calculated if res is not None: self._writeFit(res) self._writeContribs(res) self._algo.plot(outputFilename=self._outFn, autoClose=self._algo.autoClose()) else: logging.info("No results available!") log.removeHandler(logFile)
def setDecimals(selforcls, newDecimals): if newDecimals is not None: testfor( isNumber(newDecimals) and newDecimals >= 0, DecimalsError, "Parameter decimals has to be a positive number!") else: start, end = selforcls._valueRange newDecimals = round(math_log10(math_fabs(end - start))) newDecimals = max(newDecimals, 0) newDecimals = min(newDecimals, sys.float_info.max_10_exp) selforcls._decimals = int(newDecimals)
def setParams(cls, *parameters): """Expects a list of ParameterBase classes/types and sets them as class attributes to this class. They will become instances later, please see __init__()""" cls._parameters = [] for i, p in enumerate(parameters): testfor( isinstance(p, type) and issubclass(p, ParameterBase), AlgorithmParameterError, "{name}: Expected a " "ParameterBase type for parameter {index}, got {type}!".format( name=cls.__name__, index=i, type=p)) cls.setParam(p)
def __init__(self): """Creates instances from defined parameters and replaces the class attributes accordingly.""" testfor( self._name is not None, AlgorithmNameError, "No name provided! " "Set up {name} by calling factory() first.".format( name=type(self).__name__)) testfor( self._parameters is not None, AlgorithmParameterError, "Parameters not configured! " "Set up {name} by calling factory() first.".format( name=type(self).__name__)) paramTypes = self.params() self._parameters = None for ptype in paramTypes: self.setParam(ptype())
def test(cls, filename): """Regression test of a scattering model. File names are expected to contain the parameter values which produce the provided intensity. Otherwise implement fixTestParams() for the particular model. - *filename*: Name of the file in cls.testDataDir to test against. - *cls.testRelErr*: Acceptable mean of relative error against reference intensity. Default: 1e-5 - *cls.testVolExp*: Volume compensation exponent, sets the amount of volume contribution the intensity is scaled by. - *cls.testDataDir*: Directory of test data relative to program dir. Default: "testdata" """ return # this does not work anymore relerr = getattr(cls, "testRelErr", 1e-5) datadir = getattr(cls, "testDataDir", "testdata") volumeExponent = getattr(cls, "testVolExp", 1.0) filename = os.path.abspath(os.path.join(datadir, filename)) #dataset = SASData.load(filename) if dataset is None: return model = cls() testParams = model.getParametersFromFilename(dataset.filename) model.update(testParams) # intensity how it's calculated in SASfit intensity = (model.vol(None, compensationExponent = volumeExponent) * model._formfactor(dataset, None))**2. # computing the relative error to reference data delta = abs((dataset.f.binnedData - intensity) / dataset.f.binnedData) dmax = argmax(delta) testfor(delta.mean() < relerr, AssertionError, "Could not verify {model} intensity against\n'{fn}'," "\nmean(delta): {mean} >= relErr: {relerr}" "\nQ, Int_ref, Int_calc, Delta around dmax({dmax}):" "\n{data}" .format(model = cls.name(), fn = filename, mean = delta.mean(), relerr = relerr, dmax = dmax, data = hstack(( dataset.x0.binnedData.reshape(-1, 1), dataset.f.binnedData.reshape(-1, 1), intensity.reshape(-1, 1), delta.reshape(-1, 1)))[max(0, dmax-4):dmax+5] ) )
def getParametersFromFilename(cls, filename): """Derives model parameters for testing from reference data file.""" pnames = os.path.splitext(os.path.basename(filename))[0] pnames = pnames.split("-") errorMsg = ("Could not infer {model} parameters from '{fn}'!" .format(model = cls.name(), fn = filename)) testfor(len(pnames) > cls.paramCount(), NameError, errorMsg) # exclude the base name at front pnames = tuple(enumerate(pnames[1:])) # store all values by index for reference in fixTestParams() result = dict(pnames) # map values to parameter names beginning at front for i, valueStr in pnames: try: p = cls.param(i) # raises IndexError eventually result[p.name()] = p.dtype(valueStr) except IndexError: continue return result
def _makeEntry(self, name, dtype, value, minmax=None, widgetType=None, parent=None, decimals=None, **kwargs): testfor( name not in self.keys, KeyError, "Input widget '{w}' exists already in '{s}'".format( w=name, s=self.objectName())) if widgetType is None: if dtype is float: widgetType = SciEntryBox else: widgetType = self.getInputWidget(dtype) if parent is None: parent = self widget = widgetType(parent, **kwargs) widget.setObjectName(name) if decimals is not None: # set precision before the value is set widget.setDecimals(decimals) if dtype is bool: widget.setCheckable(True) widget.setChecked(value) else: widget.setAlignment(Qt.AlignRight | Qt.AlignVCenter) if isList(minmax) and len(minmax): widget.setMinimum(min(minmax)) widget.setMaximum(max(minmax)) widget.setValue(value) # update tooltip with help text about valid input values decimals = getattr(widget, "decimals", None) if decimals is not None: decimals = decimals() try: SciEntryBox.updateToolTip(widget, decimals) except: pass # for non-float input widgets self.connectInputWidgets(widget) return widget
def setDisplayValues(selforcls, newDisplayValues): if newDisplayValues is None: return testfor(isMap(newDisplayValues), DisplayValuesError, "Expected a display value mapping of numbers to text!") testfor(all([isNumber(v) for v in newDisplayValues.keys()]), DisplayValuesError, "Display value keys have to be numbers!") testfor(all([isString(s) for s in newDisplayValues.values()]), DisplayValuesError, "Display values have to be text!") # TODO: also add reverse lookup selforcls._displayValues = newDisplayValues
def setValueRange(selforcls, newRange): testfor(isList(newRange), ValueRangeError, "A value range is mandatory for a numerical parameter!") testfor( len(newRange) == 2, ValueRangeError, "A value range has to consist of two values!") testfor(all([isNumber(v) for v in newRange]), ValueRangeError, "A value range has to consist of numbers only!") minVal, maxVal = min(newRange), max(newRange) # minVal = max(minVal, -sys.float_info.max) # maxVal = min(maxVal, sys.float_info.max) # avoid inf/nan showing up somewhere # otherwise, inf might be ok if UI elements support it (going in&out) minVal = max(minVal, -1e200) # as good as -inf?... maxVal = min(maxVal, 1e200) # as good as inf?... selforcls._valueRange = minVal, maxVal # apply limits to value: selforcls.setValue(selforcls.clip())
def setStepping(selforcls, newStepping): if newStepping is None: return testfor(isNumber(newStepping), SteppingError, "Parameter has to be a number!") selforcls._stepping = newStepping
def __init__(self): self._path = self._getPath() testfor( self._path is not None and os.path.isfile(self._path), OSError, "{name}: '{path}' not found!".format(name=self._name, path=self._path))