def __init__(self, resp, pmodel): # check if response model has convolve method if not hasattr(resp, "convolve"): raise(PE.PyAAlgorithmFailure("Response model has no method 'convolve'.", \ where="ConvolutionModel::__init__")) if not isinstance(pmodel, OneDFit): raise(PE.PyAAlgorithmFailure("Physical model must be derived from OneDFit", \ where="ConvolutionModel::__init__")) # Copy the input models self.response = copy.deepcopy(resp) self.pmodel = copy.deepcopy(pmodel) if isinstance(self.response, OneDFit): # The response is also a funcFit model and, therefore, could # already contribute fitting parameters # # Change root name to "Response" self.response.setRootName("Response") # Ensure unique parameter names self._combineRemapping(self.response, self.pmodel) # List of parameters for the this (the convolved) model parameters = list(self.response.parameters()) + list( self.pmodel.parameters()) else: # List of parameters for the this (the convolved) model parameters = list(self.pmodel.parameters()) # Set up funcFit model and assign OneDFit.__init__(self, parameters) # Define root name if self.pmodel.naming._root == "": # Use default rn = "model" else: rn = self.pmodel.naming._root self.setRootName("Conv-" + rn)
def _readData(self): """ """ # Determine number of planets in the csv file r = csv.DictReader(self._fs.requestFile(self.dataFileName, 'rt', gzip.open), delimiter=',') for nplanets, x in enumerate(r): pass # Reinitialize csv file r = csv.DictReader(self._fs.requestFile(self.dataFileName, 'rt', gzip.open), delimiter=',') # Determine data types for numpy recarray from columns # and initialize dtype = [(self._columns[x][0], self._columns[x][3]) for x in range(len(self._columns))] self.data = np.recarray((nplanets + 1, ), dtype=dtype) colnotfilled = [ self._columns[x][0] for x in six.iterkeys(self._columns) ] for i, x in enumerate(r): for k, v in six.iteritems(x): # Remove hash and white spaces from column names k = k.strip('#') k = k.strip() # Translate csv column name into internal column name if k in self._ident: key = self._ident[k] else: key = k if len(v) == 0: v = None # Accept only expected fields if not key in self.data.dtype.names: continue try: colnotfilled.remove(key) except ValueError: # Ignoring already removed value pass self.data[key][i] = v if len(colnotfilled) > 0: PE.warn( PE.PyAAlgorithmFailure( "Not all columns could be filled with data. The following columns must not be used: " + ", ".join(colnotfilled), where="ExoplanetEU", solution= "The format of the data base must be checked. Please consider issuing a bug report via github." ))
def selectWalkers(self, ws): """ Select walkers for emcee chains. Parameters ---------- ws : list or array of integers The walker to be considered in the analysis. Counting starts at zero. """ self._selectedWalker = np.array(ws, dtype=np.int) if self.dbtype == "emcee": # Apply burn-in to individual walkers self._loadEMCEEChain(burn=self.burn) else: raise(PE.PyAAlgorithmFailure("Walkers can only be selected for emcee data bases. Current data base type: " + str(self.dbtype)))
def fit(self, m, ds, objf="chisqr", initDelta=None, maxIter=1e4, callback=None, nmCritLim=None): """ Carry out the model fit. After the iteration, the `iterCount` attribute contains the number of iterations. The `maxIterReached` attribute flag is False, if the maximum number of iterations has not been reached and True otherwise. Parameters ---------- m : Instance of OneDFit The model to be fitted. ds : Instance of FufDS The data. objf : string The objective function to be used. Possible choices are "chisqr" (default), "sqrdiff", and "cash79". initDelta : dictionary, optional A dictionary mapping parameter names to the initial step width. This can be very useful, if the starting values are zero or very small. The here defined step will be added to the starting value to construct the simplex. maxIter : int, optional The maximum number of iterations. The default is 10000. nmCritLim : float, optional Critical value for stopping criterion. The default is 1e-8. callback : callable, optional If not None, "callback" will be called with the three parameters: number of iteration (int), current best parameter set (array), and current simplex (array). Returns ------- Best-fit values : dictionary Maps parameter name to the best-fit value. """ # Stopping criterion if not nmCritLim is None: self.nmCritLim = nmCritLim # Number of free parameters self._n = m.numberOfFreeParams() # Set objective function m.setObjectiveFunction(objf) # Assign data object m._fufDS = ds # Names of free parameters (order guaranteed) self._fpns = m.freeParamNames() # Initial simplex self._initSimplex(m, initDelta) # MaxIter flag self.maxIterReached = False self.iterCount = 0 while (not self._stopCrit()) and (self.iterCount < maxIter): self.iterCount += 1 self._step(m) if callback is not None: l = np.argmin(self._yi) callback(self.iterCount, self._simplex[l, ::], self._simplex) # Find the optimum parameter set l = np.argmin(self._yi) m.pars.setFreeParams(self._simplex[l, ::]) # Evaluate model so that model attribute holds the best match m.evaluate(ds.x) if self.iterCount == maxIter: self.maxIterReached = True PE.warn( PE.PyAAlgorithmFailure( "The maximum number of iterations has been reached.\n" + "The fit may be inappropriate.", where="NelderMead", solution=[ "Increase number of iterations.", "Change starting values.", "Change algorithm parameters (e.g., alpha, beta, gamma)." ])) # Return a dictionary with the best-bit parameters return dict(zip(self._fpns, self._simplex[l, ::]))
def teffToColor_nop(self, band, teff, feH, stype="ms", noRaise=False): """ Converts effective temperature into color according to Eq. 1. This method inverts Eq. 1. Note that the equation is parabolic in the color (i.e., X). Therefore, there are two solutions of which the one falling within the validity ranges specified in Tables 4 and 5 of RM05 is selected. If none or both of the solutions are valid, an exception is raised. Parameters ---------- band : string Band identifier. teff : float Effective temperature in K. feH : float Metallicity stype : string, {ms, g} Type of star (main sequence or giant). noRaise : boolean, optional If True, no exceptions will be raised, but warnings will be given Both candidate solutions will be returned in this case. Returns ------- X : float Color in the specified band. """ self._checkBand(band) self._checkST(stype) if stype == "ms": dat = self._tab2 datp = self._tab4 else: dat = self._tab3 datp = self._tab5 # Use warnings of 'noRaise' is True if noRaise: raiser = PE.warn else: def throw(x): raise (x) raiser = throw # Row of coefficients in the table. j = self._bands.index(band) c = dat[j, 0] + dat[j, 4] * feH + dat[j, 5] * feH**2 - 5040. / teff a13p = dat[j, 1] + dat[j, 3] * feH a2 = dat[j, 2] sq = np.sqrt(a13p**2 - 4. * a2 * c) X = [(-a13p + sq) / (2. * a2), (-a13p - sq) / (2. * a2)] # Get validity ranges to decide, which solution is correct mj = j * 4 + self._resolveMetallicityIndex(feH) xmin = datp[mj, 1] xmax = datp[mj, 2] xin = [False] * 2 for i in smo.range(2): if X[i] >= xmin and X[i] <= xmax: xin[i] = True if sum(xin) == 2: raiser(PE.PyAAlgorithmFailure("No unique solution in inversion of teff-color relation.", \ where="teffToColor_nop",\ solution="Consider carefully(!) using 'noRaise'.")) # Only relevant if 'noRaise' is True return tuple(X) if sum(xin) == 0: raiser(PE.PyAAlgorithmFailure("No valid solution in inversion of teff-color relation.\n" + \ "Band: " + str(band) + ", Range of validity: %.4e - %.4e" % (xmin, xmax) + \ ", candidate solutions: %.4e and %.4e" % tuple(X) + ", Input Teff: %5.1f" % teff, \ where="teffToColor_nop",\ solution="Consider carefully(!) using 'noRaise'.")) # Only relevant if 'noRaise' is True return tuple(X) if xin[0]: return X[0] else: return X[1]