Esempio n. 1
0
 def getModel(self, broad, asarray=False, modelIndices=False):
     """
   Calculates a model resulting from template and broadening function.
   
   Parameters
   ----------
   broad : array or matrix
       The broadening function
   asarray : bool, optional
       If True, the broadening function will be returned
       as an array instead of a matrix. The default is
       False.
   modelIndices : bool, optional
       If True, the method returns also an array of indices,
       which refer to the template, for which the model is
       calculated. Note that the model cannot be calculated
       at the edges. The default is False.
 """
     if self.des is None:
         raise(PE.PyAOrderError("You need to create a design matrix first.", \
                                solution="Use the `decompose` method."))
     if not modelIndices:
         if not asarray:
             return self.des * np.matrix(broad)
         else:
             return (self.des * np.matrix(broad)).getA()[::, 0]
     else:
         modelInd = np.arange(self.bn // 2,
                              len(self.template) - self.bn // 2)
         if not asarray:
             return (self.des * np.matrix(broad), modelInd)
         else:
             return ((self.des * np.matrix(broad)).getA()[::, 0], modelInd)
Esempio n. 2
0
 def getRVAxis(self, binsize, refWvl):
     """
   Calculate a radial velocity axis for the broadening function.
   
   .. note:: Here, it is assumed that the broadening function
             refers to a spectrum in wavelength space.
   
   Parameters
   ----------
   binsize : float
       Size of spectral bins.
   refWvl : float
       The reference wavelength.
 
   Returns
   -------
   Radial velocity axis : array
       An array containing the radial velocity shift
       pertaining to the individual bins in the
       broadening function. The unit is km/s.
 """
     if self.bn is None:
         raise(PE.PyAOrderError("The length of the broadening function has not yet been specified.", \
                                solution="Call `decompose` first, where the length (bn) is specified."))
     result = -np.arange(self.bn) + float(self.bn // 2)
     result *= binsize
     result /= refWvl
     result *= 299792.458
     return result
Esempio n. 3
0
 def getSingularValues(self):
     """
   Access the singular values.
   
   Returns
   -------
   Singular values : matrix
       The singular values.
 """
     if self.w is None:
         raise(PE.PyAOrderError("No singular values available yet.", \
                                "Use the `decompose` method first."))
     return self.w[:]
Esempio n. 4
0
 def _step(self, m):
     """
     Proceed one step of the simplex algorithm.
     """
     # Indices with lowest and highest objective function value
     h = np.argmax(self._yi)
     l = np.argmin(self._yi)
     # Barycenter (excluding the worst point)
     pb = (np.sum(self._simplex, 0) - self._simplex[h, ::]) / self._n
     # New suggestion
     ps = (1. + self.alpha) * pb - self.alpha * self._simplex[h, ::]
     ys = m.miniFunc(ps)
     if ys < self._yi[l]:
         # In this case, calculate pss
         pss = self.gamma * ps + (1. - self.gamma) * pb
         yss = m.miniFunc(pss)
         if yss < self._yi[l]:
             # Replace by pss
             self._simplex[h, ::] = pss
             self._yi[h] = yss
             return
         # Replace h by ps
         self._simplex[h, ::] = ps
         self._yi[h] = ys
         return
     # We have not produced a new minimum, and we know
     # that ys >= y[l]
     if ys < self._yi[h]:
         self._simplex[h, ::] = ps
         self._yi[h] = ys
         return
     else:
         # There is a new maximum
         pssb = self.beta * self._simplex[h, ::] + (1.0 - self.beta) * pb
         yssb = m.miniFunc(pssb)
         if yssb > self._yi[h]:
             # Contract
             pl = self._simplex[l, ::].copy()
             for i in smo.range(self._n + 1):
                 if i == l:
                     continue
                 self._simplex[i, ::] = (self._simplex[i, ::] + pl) / 2.0
                 self._yi[i] = m.miniFunc(self._simplex[i, ::])
             return
         else:
             self._simplex[h, ::] = pssb
             self._yi[h] = yssb
             return
     raise (PE.PyAOrderError(
         "Nothing done in Nelder-Mead step. If you see this, there is a coding error."
     ))
Esempio n. 5
0
 def steppar(self, pars, ranges, extractFctVal=None, quiet=False):
     """
   Allows to step a parameter through a specified range.
   
   This function steps the specified parameters through the given
   ranges. During each steps, all free parameters, except for those
   which are stepped, are fitted. The resulting contours allow
   to estimate confidence intervals.
   
   This command uses the fitting parameters specified on a call
   to the `fit` method. In particular, the same values for `x`,
   `y`, `yerr`, `minAlgo`, `miniFunc`, `fminPars`, and `fminArgs`
   are used.
   
   .. note:: You need to have carried out a fit before you can
             use `steppar`.
   
   Parameters
   ----------
   pars : string or list of strings
       The parameter(s) which are to be stepped.
   ranges : dictionary
       A dictionary mapping parameter name to range specifier.
       The latter is a list containing [lower limit, upper limit,
       no. of steps, 'lin'/'log']. The fourth entry, which
       is optional, is a string specifying whether a constant
       linear step size ('lin') or a constant logarithmic
       step size ('log') shall be used.
   quiet : boolean, optional
       If True, output will be suppressed.
   extractFctVal : callable, optional
       A function specifying how the function value is extracted
       from the fit result. If standard settings are used, the
       default of None is adequate.
   
   Returns
   -------
   Parameter steps : list
       The return value is a list of lists. Each individual list
       contains the values of the stepped parameters as the first
       entries (same order as the input `pars` list), the
       following entry is the value of the objective function
       (e.g., chi square), and the last entry is a tuple
       containing the indices of the steps of the parameter values.
       This last entry can be useful to convert the result into
       an arrow to plot, e.g., contours. 
 """
     if not self._stepparEnabled:
         raise(PE.PyAOrderError("Before you can use steppar, you must call a function, which enables its use (e.g., `fit`).", \
               solution="Call the `fit` method first and then try again."))
     if isinstance(pars, six.string_types):
         # Make it a list
         pars = [pars]
     # Check parameter consistency
     for p in pars:
         # Check existence
         tmp = self[p]
         if not p in ranges:
             raise(PE.PyAValError("There is no range for parameter: " + p, \
                                  solution="Specify a range; e.g., {'xyz':[0.5,1.9,20,'lin']}"))
     # Function to extract function value from the fit result
     if extractFctVal is None:
         self._extractFctVal = self.__extractFunctionValue
     else:
         if not hasattr(extractFctVal, "__call__"):
             raise(PE.PyAValError("`extractFctVal` needs to be callable!", \
                                  solution="Specify a function here or try to use None."))
         self._extractFctVal = extractFctVal
     # Set up ranges
     rs = []
     for par in pars:
         r = ranges[par]
         if len(r) > 4:
             # Use the axis as given
             rs.append(r)
             continue
         if len(r) < 4:
             # By default, use linear spacing
             mode = 'lin'
         else:
             if not isinstance(r[3], six.string_types):
                 raise(PE.PyAValError("If the range has 4 entries, the fourth must be a string specifying the mode.", \
                                      solution="Use either 'lin' or 'log' as the fourth entry."))
             mode = r[3]
         if mode == 'lin':
             rs.append(numpy.linspace(r[0], r[1], r[2]))
         elif mode == 'log':
             # Calculate factor
             s = numpy.power((r[1] / r[0]), 1.0 / r[2])
             rs.append(r[0] * numpy.power(s, numpy.arange(r[2])))
         else:
             raise(PE.PyAValError("Unknown mode: " + str(mode), \
                                  solution="Use either 'lin' or 'log'."))
     # Save state of object
     saveObj = self.saveState()
     saveFitResult = self.fitResult
     saveModels = {}
     for k in six.iterkeys(self._compos):
         saveModels[k] = self.models[k].copy()
     # Freeze parameters, which are affected
     self.freeze(pars)
     # Store result
     result = []
     # Loop over the axes
     nli = pyaC.NestedLoop(list(map(len, rs)))
     for index in nli:
         for i, p in enumerate(pars):
             self[p] = rs[i][index[i]]
         # Fit using previous setting
         # Note that mAA is dispensable, because self.minAlgo will be a callable.
         self.fit(None, None, minAlgo=self.minAlgo, miniFunc=self.miniFunc, \
                  *self.fminPars, **self.fminArgs)
         # Build up result
         ppr = []
         for par in pars:
             ppr.append(self[par])
         try:
             ppr.append(self._extractFctVal(self.fitResult))
         except Exception as e:
             PE.warn(PE.PyAValError("The call to the `extractFctVal` function failed. Using full output." + \
                                    "\n  Original message: " + str(e)))
             ppr.append(self.fitResult)
         if not quiet:
             print("Result from last iteration:")
             print("  ", ppr)
         ppr.append(index)
         result.append(ppr)
     # Restore old state of object
     self.restoreState(saveObj)
     self.fitResult = saveFitResult
     for k in six.iterkeys(self._compos):
         self.models[k] = saveModels[k]
     return result