コード例 #1
0
def _format_abundances(elemental_abundances=None,
                       subtract_solar=False,
                       subtract_metallicity=0):

    if elemental_abundances is None:
        return ("0 1", 1)

    # First-pass to check the abundances and get the number of syntheses.
    elemental_abundances = elemental_abundances.copy()

    # Make sure that the abundances are specified as (atomic_number: abundance)
    for key in list(elemental_abundances.keys()):
        if isinstance(key, string_types):
            # It's an element. Convert to atomic number.
            atomic_number = element_to_atomic_number(key)
            if atomic_number in elemental_abundances.keys():
                raise ValueError(
                    "element {} has abundances specified by element and species"\
                    .format(key))
            elemental_abundances[atomic_number] = elemental_abundances.pop(key)

    sorted_atomic_numbers, max_synth = sorted(
        elemental_abundances.keys()), None
    for atomic_number in sorted_atomic_numbers:
        abundance = elemental_abundances[atomic_number]
        try:
            abundance[0]
        except (IndexError, TypeError):
            abundance = [abundance]
        abundance = np.array(abundance).flatten().copy()

        # Subtract any compositions.
        abundance -= subtract_metallicity
        if subtract_solar:
            abundance -= solar_composition(atomic_number)

        elemental_abundances[atomic_number] = abundance
        if max_synth is None or len(abundance) > max_synth:
            max_synth = len(abundance)

        if len(abundance) > 1 and len(abundance) != max_synth:
            raise ValueError("abundance entries must be fully described "
                             "or have one abundance per element (Z = {})"\
                             .format(atomic_number))

    assert 5 >= max_synth

    str_format = ["{0} {1}".format(len(sorted_atomic_numbers), max_synth)]
    for atomic_number in sorted_atomic_numbers:
        abundance = elemental_abundances[atomic_number]

        if len(abundance) == 1 and max_synth > 1:
            abundance = list(abundance) * max_synth

        _ = "      {0:3.0f} ".format(atomic_number)
        str_format.append(_ + " ".join(
            ["{0:8.3f}".format(a) for a in np.array(abundance).flatten()]))

    return ("\n".join(str_format), max_synth)
コード例 #2
0
    def _initial_guess(self, spectrum, **kwargs):
        """
        Return an initial guess about the model parameters.

        :param spectrum:
            The observed spectrum.
        """

        # Potential parameters:
        # elemental abundances, continuum coefficients, smoothing kernel,
        # velocity offset

        defaults = {
            "sigma_smooth": self.metadata["manual_sigma_smooth"],  #0.1,
            "vrad": self.metadata["manual_rv"]
        }
        p0 = []
        for parameter in self.parameter_names:
            default = defaults.get(parameter, None)
            if default is not None:
                p0.append(default)

            elif parameter.startswith("log_eps"):
                # The elemental abundances are in log_epsilon format.
                # If the value was already fit, we use that as the initial guess
                # Otherwise, we assume a scaled-solar initial value based on the stellar [M/H]

                # Elemental abundance.
                element = parameter.split("(")[1].rstrip(")")

                # Assume scaled-solar composition.
                default_value = solar_composition(element) + \
                        self.session.metadata["stellar_parameters"]["metallicity"]
                try:
                    fitted_result = self.metadata["fitted_result"]
                except KeyError:
                    p0.append(default_value)
                else:
                    value = fitted_result[0][parameter]
                    if np.isnan(value):
                        p0.append(default_value)
                    else:
                        p0.append(value)

            elif parameter.startswith("c"):
                # Continuum coefficient.
                p0.append((0, 1)[parameter == "c0"])

            else:
                raise ParallelUniverse("this should never happen")

        return np.array(p0)
コード例 #3
0
    def minimisation_function(stellar_parameters, *args):
        """The function we want to minimise (e.g., calculates the quadrature
        sum of all minimizable variables.)
        
        stellar_parameters : [teff, vt, logg, feh]
        """

        params_to_optimize, all_sampled_points, total_tolerance, individual_tolerances, use_nlte_grid = args

        # Old way:
        #teff, vt, logg, feh = [initial_guess[0], stellar_parameters[0], initial_guess[2], stellar_parameters[1]]

        # First set all to initial_guess, then replace the ones with a "True" value
        params_list = initial_guess
        next_param = 0
        for pi, p in enumerate(params_to_optimize):
            if p == True:
                params_list[pi] = stellar_parameters[next_param]
                next_param += 1

        teff, vt, logg, feh = params_list

        photosphere = photosphere_interpolator(teff, logg, feh)
        photosphere.meta["stellar_parameters"]["microturbulence"] = vt

        ## TODO: ADJUST ABUNDANCES TO ASPLUND?
        abundances = rt.abundance_cog(photosphere, transitions, twd=twd)
        transitions["abundance"] = abundances

        out = utils.equilibrium_state(transitions[idx_I],
                                      ("expot", "reduced_equivalent_width"))
        dAdchi = out[26.0]['expot'][0]
        dAdREW = out[26.0]['reduced_equivalent_width'][0]
        dFe = np.mean(abundances[idx_I]) - np.mean(abundances[idx_II])
        # E. Holmbeck changed dM to be w.r.t. FeII abundances.
        dM = np.mean(abundances[idx_II]) - (feh + solar_composition("Fe"))

        results = np.array([dAdchi, dAdREW, 0.1 * dFe, 0.1 * dM])
        acquired_total_tolerance = np.sum(results**2)

        point = list(np.array([teff, vt, logg, feh]) *
                     params_to_optimize) + list(results * params_to_optimize)
        all_sampled_points.append(point)

        logger.info(
            "Atmosphere with Teff = {0:.0f} K, vt = {1:.2f} km/s, logg = {2:.2f}, [Fe/H] = {3:.2f}, [alpha/Fe] = {4:.2f}"
            " yields sum {5:.1e}:\n\t\t\t[{6:.1e}, {7:.1e}, {8:.1e}, {9:.1e}]".
            format(teff, vt, logg, feh, 0.4, acquired_total_tolerance,
                   *results))
        return results[params_to_optimize]
コード例 #4
0
    def minimisation_function(stellar_parameters, *args):
        """The function we want to minimise (e.g., calculates the quadrature
        sum of all minimizable variables.)
        
        stellar_parameters : [teff, logg, vt, feh]
        """

        teff, logg, vt, feh = stellar_parameters
        sampled_points, total_tolerance, individual_tolerances, use_nlte_grid = args

        if teff < parameter_ranges["teff"][0] or teff > parameter_ranges["teff"][1] or \
           logg < parameter_ranges["logg"][0] or logg > parameter_ranges["logg"][1] or \
           vt < parameter_ranges["vt"][0] or vt > parameter_ranges["vt"][1] or \
           feh < parameter_ranges["[Fe/H]"][0] or feh > parameter_ranges["[Fe/H]"][1] or \
           np.isnan(teff) or np.isnan(logg) or np.isnan(vt) or np.isnan(feh):
            #return np.array([np.nan, np.nan, np.nan, np.nan])
            return np.array([np.inf, np.inf, np.inf, np.inf])

        photosphere = photosphere_interpolator(teff, logg, feh, alphafe)
        photosphere.meta["stellar_parameters"]["microturbulence"] = vt

        abundances = rt.abundance_cog(photosphere, transitions, twd=twd)
        transitions["abundance"] = abundances

        ## Calculate slopes and differences that are being minimized
        x, y = transitions[idx_expot]["expot"], abundances[idx_expot]
        dAdchi, b_expot, medy, stdy, stdm_expot, N = utils.fit_line(x, y, None)

        x, y = transitions[idx_rew]["reduced_equivalent_width"], abundances[
            idx_rew]
        dAdREW, b_rew, medy, stdy, stdm_rew, N = utils.fit_line(x, y, None)

        dFe = np.mean(abundances[idx_I]) - np.mean(abundances[idx_II])
        dM = np.mean(abundances[idx_MH]) - (feh + solar_composition("Fe"))

        # Some metric has been imposed here. Could make it depend on the slope standard error, but that seems not stable.
        results = np.array([dAdchi, dAdREW, 0.1 * dFe, 0.1 * dM])
        acquired_total_tolerance = np.sum(results**2)

        point = [teff, logg, vt, feh] + list(results)
        sampled_points.append(point)

        acquired_total_tolerance = np.sum(results**2)
        logger.debug(
            "Atmosphere with Teff = {0:.0f} K, logg = {2:.2f}, vt = {1:.2f} km/s, [Fe/H] = {3:.2f}, [alpha/Fe] = {4:.2f}"
            " yields sum {5:.1e}:\n\t\t\t[{6:.1e}, {7:.1e}, {8:.1e}, {9:.1e}]".
            format(teff, logg, vt, feh, alphafe, acquired_total_tolerance,
                   *results))
        return results
コード例 #5
0
    def minimisation_function(stellar_parameters, *args):
        """The function we want to minimise (e.g., calculates the quadrature
        sum of all minimizable variables.)
        
        stellar_parameters : [teff, vt, logg, feh]
        """
        ## "Global" vars: transitions, idx_I, idx_II, photosphere_interpolator

        teff, vt, logg, feh = stellar_parameters
        #if teff < parameter_ranges["teff"][0] or teff > parameter_ranges["teff"][1] or \
        #        vt < parameter_ranges["vt"][0] or vt > parameter_ranges["vt"][1] or \
        #        logg < parameter_ranges["logg"][0] or logg > parameter_ranges["logg"][1] or \
        #        feh < parameter_ranges["[Fe/H]"][0] or feh > parameter_ranges["[Fe/H]"][1]:
        #    return np.array([np.nan, np.nan, np.nan, np.nan])

        all_sampled_points, total_tolerance, individual_tolerances, use_nlte_grid = args

        #if not (5 > vt > 0):
        #    return np.array([np.nan, np.nan, np.nan, np.nan])

        photosphere = photosphere_interpolator(teff, logg, feh)
        photosphere.meta["stellar_parameters"]["microturbulence"] = vt

        ## TODO: ADJUST ABUNDANCES TO ASPLUND?
        abundances = rt.abundance_cog(photosphere, transitions, twd=twd)
        transitions["abundance"] = abundances

        ## Calculate slopes and differences that are being minimized
        out = utils.equilibrium_state(transitions[idx_I],
                                      ("expot", "reduced_equivalent_width"))
        dAdchi = out[26.0]['expot'][0]
        dAdREW = out[26.0]['reduced_equivalent_width'][0]
        dFe = np.mean(abundances[idx_I]) - np.mean(abundances[idx_II])
        dM = np.mean(abundances[idx_I]) - (feh + solar_composition("Fe"))
        results = np.array([dAdchi, dAdREW, 0.1 * dFe, 0.1 * dM])
        acquired_total_tolerance = np.sum(results**2)

        point = [teff, vt, logg, feh] + list(results)
        all_sampled_points.append(point)

        logger.info(
            "Atmosphere with Teff = {0:.0f} K, vt = {1:.2f} km/s, logg = {2:.2f}, [Fe/H] = {3:.2f}, [alpha/Fe] = {4:.2f}"
            " yields sum {5:.1e}:\n\t\t\t[{6:.1e}, {7:.1e}, {8:.1e}, {9:.1e}]".
            format(teff, vt, logg, feh, 0.4, acquired_total_tolerance,
                   *results))
        return results
コード例 #6
0
    def update_stellar_parameter_state_table(self):
        """ Update the text labels """
        ## Note: this uses self.measurement_model to get a good list of measurements.
        ##       So, have to call measurement_model.reset() before doing this
        ## Note: I have scrapped the Ti I/II in favor of hardcoding.

        ## Get data
        # species, abundance, expot, rew
        acceptable = self.measurement_model.get_data_column("is_acceptable")
        not_upper_limit = np.logical_not(
            self.measurement_model.get_data_column("is_upper_limit"))
        species = self.measurement_model.get_data_column("species")
        abundance = self.measurement_model.get_data_column("abundances")
        expot = self.measurement_model.get_data_column("expot")
        rew = self.measurement_model.get_data_column(
            "reduced_equivalent_width")
        ii1 = acceptable & (not_upper_limit) & (np.round(species, 1) == 26.0)
        ii2 = acceptable & (not_upper_limit) & (np.round(species, 1) == 26.1)
        chi1, eps1, REW1 = expot[ii1], abundance[ii1], rew[ii1]
        chi2, eps2, REW2 = expot[ii2], abundance[ii2], rew[ii2]

        finite = np.isfinite(chi1 * eps1 * REW1)
        chi1, eps1, REW1 = chi1[finite], eps1[finite], REW1[finite]
        finite = np.isfinite(chi2 * eps2 * REW2)
        chi2, eps2, REW2 = chi2[finite], eps2[finite], REW2[finite]

        ## Fit lines
        try:
            mchi1, bchi1, med1, eXH1, emchi1, N1 = utils.fit_line(chi1, eps1)
        except Exception as e:
            logger.debug(e)
            mchi1, bchi1, med1, eXH1, emchi1, N1 = np.nan, np.nan, np.nan, np.nan, np.nan, len(
                eps1)
        try:
            mREW1, bREW1, med1, eXH1, emREW1, N1 = utils.fit_line(REW1, eps1)
        except Exception as e:
            logger.debug(e)
            mREW1, bREW1, med1, eXH1, emREW1, N1 = np.nan, np.nan, np.nan, np.nan, np.nan, len(
                eps1)
        try:
            mchi2, bchi2, med2, eXH2, emchi2, N2 = utils.fit_line(chi2, eps2)
        except Exception as e:
            logger.debug(e)
            mchi2, bchi2, med2, eXH2, emchi2, N2 = np.nan, np.nan, np.nan, np.nan, np.nan, len(
                eps2)
        try:
            mREW2, bREW2, med2, eXH2, emREW2, N2 = utils.fit_line(REW2, eps2)
        except Exception as e:
            logger.debug(e)
            mREW2, bREW2, med2, eXH2, emREW2, N2 = np.nan, np.nan, np.nan, np.nan, np.nan, len(
                eps2)

        ## Update table
        XH1 = med1 - solar_composition(26.0)
        XH2 = med2 - solar_composition(26.1)
        self.state_fe1_N.setText(u"Fe I ({})".format(N1))
        self.state_fe1_XH.setText(u"{:.2f} ± {:.2f}".format(XH1, eXH1))
        self.state_fe1_dAdchi.setText(u"{:.3f} ± {:.3f}".format(mchi1, emchi1))
        self.state_fe1_dAdREW.setText(u"{:.3f} ± {:.3f}".format(mREW1, emREW1))
        self.state_fe2_N.setText(u"Fe II ({})".format(N2))
        self.state_fe2_XH.setText(u"{:.2f} ± {:.2f}".format(XH2, eXH2))
        self.state_fe2_dAdchi.setText(u"{:.3f} ± {:.3f}".format(mchi2, emchi2))
        self.state_fe2_dAdREW.setText(u"{:.3f} ± {:.3f}".format(mREW2, emREW2))
        return None
コード例 #7
0
ファイル: base.py プロジェクト: andycasey/smhr
 def abundances_to_solar(self):
     """ Return [X/H] if fit, else None """
     abunds = self.abundances
     if abunds is None: return None
     elems = self.elements
     return [AX - solar_composition(X) for AX, X in zip(abunds, elems)]