예제 #1
0
class ezIsoch(Isochrone):
    """ Trying to make something that is easy to manipulate
    This class is basically a proxy to a table (whatever format works best)
    and tries to keep things coherent.
    """
    def __init__(self, source, interp=False):
        super().__init__()
        self.name = "<auto>"
        self.source = source
        self._load_table_(self.source)
        # round because of precision noise
        self.logages = np.unique(np.round(self.data["logA"], 6))
        self.ages = np.round(10**self.logages)
        self.Z = np.unique(np.round(self.data["Z"], 6))
        self.interpolation(interp)

    def selectWhere(self, *args, **kwargs):
        return self.data.selectWhere(*args, **kwargs)

    def interpolation(self, b=None):
        if b is not None:
            if hasattr(self, "interp"):
                print("Do not use interpolation yet, at your own risks!!")
            self.interp = bool(b)
        else:
            return self.interp

    def _load_table_(self, source):
        self.data = Table(self.source).selectWhere("*", "isfinite(logA)")

    def __getitem__(self, key):
        return self.data[key]

    def _get_t_isochrone(self,
                         age,
                         metal=None,
                         FeH=None,
                         masses=None,
                         *args,
                         **kwargs):
        """ Retrieve isochrone from the original source
            internal use to adapt any library
        """
        # make sure unit is in years and then only give the value (no units)
        _age = int(units.Quantity(age, units.year).value)

        #        if hasUnit(age):
        #            _age = int(age.to('yr').magnitude)
        #        else:
        #            _age = int(age * inputUnit.to('yr').magnitude)

        _logA = np.log10(_age)

        assert (metal
                is not None) | (FeH is not None), "Need a chemical par. value."

        if (metal is not None) & (FeH is not None):
            print("Warning: both Z & [Fe/H] provided, ignoring [Fe/H].")

        if metal is None:
            metal = self.FeHtometal(FeH)

        if self.interpolation():
            # Do the actual nd interpolation

            # Maybe already exists?
            if (metal in self.Z) & (_age in self.ages):
                t = self.selectWhere(
                    "*",
                    "(round(Z, 6) == {0}) & (round(logA, 6) == {1})".format(
                        metal, _logA),
                )
                if t.nrows > 0:
                    return t
            # apparently not
            # find 2 closest metal values
            ca1 = self.ages <= _age
            ca2 = self.ages > _age
            cz1 = self.Z <= metal
            cz2 = self.Z > metal
            if metal in self.Z:
                # perfect match in metal, need to find ages
                if _age in self.ages:
                    return self.selectWhere(
                        "*",
                        "(round(Z, 6) == {0}) & (round(logA, 6) == {1})".
                        format(metal, _logA),
                    )
                elif (True in ca1) & (True in ca2):
                    # bracket on _age: closest values
                    a1, a2 = (
                        np.log10(max(self.ages[ca1])),
                        np.log10(min(self.ages[ca2])),
                    )
                    iso = self.selectWhere(
                        "*",
                        "(Z == 0.02) & ( (abs(logA - {0}) < 1e-4) | (abs(logA - {1}) < 1e-4 )  )"
                        .format(a1, a2),
                    )
                    if masses is None:
                        _logM = np.unique(iso["logM"])
                    else:
                        _logM = masses

                    # define interpolator
                    points = np.array([self[k]
                                       for k in "logA logM Z".split()]).T
                    values = np.array(
                        [self[k] for k in list(self.data.keys())]).T
                    _ifunc = interpolate.LinearNDInterpolator(points, values)

                    pts = np.array([(_logA, logMk, metal) for logMk in _logM])
                    r = _ifunc(pts)
                    return Table(r)
                else:
                    raise Exception("Age not covered by the isochrones")
            elif (True in cz1) & (True in cz2):
                # need to find closest Z
                pass
            return
        else:
            # find the closest match
            _Z = self.Z[((metal - self.Z)**2).argmin()]
            # _logA = np.log10(self.ages[((_age - self.ages) ** 2).argmin()])
            _logA = self.logages[((np.log10(_age) - self.logages)**2).argmin()]
            tab = self.data.selectWhere(
                "*", "(round(Z, 6) == {0}) & (round(logA,6) == {1})".format(
                    _Z, _logA))
            # mass selection
            if masses is not None:
                # masses are expected in logM for interpolation
                # if masses.max() > 2.3:
                #    _m = np.log10(masses)
                # else:
                _m = masses
                data_logM = tab["logM"][:]
                # refuse extrapolation!
                # ind = np.where(_m <= max(data_logM))
                data = {}
                for kn in list(tab.keys()):
                    data[kn] = interp(_m,
                                      data_logM,
                                      tab[kn],
                                      left=np.nan,
                                      right=np.nan)
                return Table(data)
예제 #2
0
class padova2010(Isochrone):
    def __init__(self):
        super().__init__()
        self.name = "Padova 2010 (Marigo 2008 + Girardi 2010)"
        self.source = __ROOT__ + "/padova2010.iso.fits"
        self._load_table_(self.source)
        self.ages = 10**np.unique(self.data["logA"])
        self.Z = np.unique(self.data["Z"])

    def _load_table_(self, source):
        t = Table(self.source)
        data = {}
        for k in list(t.keys()):
            data[k] = t[k]
        # Alias columns
        data["logM"] = log10(np.asarray(data["M_ini"]))
        data["logg"] = np.asarray(data["logG"])
        data["logT"] = np.asarray(data["logTe"])
        data["logL"] = np.asarray(data["logL/Lo"])
        data["logA"] = np.asarray(data["log(age/yr)"])
        # clean columns
        data.pop("log(age/yr)")
        data.pop("M_ini")
        data.pop("logG")
        data.pop("logTe")
        data.pop("logL/Lo")

        self.data = Table(data, name="Isochrone from %s" % self.name)

    def _get_isochrone(self,
                       age,
                       metal=None,
                       FeH=None,
                       masses=None,
                       *args,
                       **kwargs):
        """ Retrieve isochrone from the original source
            internal use to adapt any library
        """
        # make sure unit is in years and then only give the value (no units)
        _age = int(units.Quantity(age, units.year).value)

        # if hasUnit(age):
        #    _age = int(age.to('yr').magnitude)
        # else:
        #    _age = int(age * inputUnit.to('yr').magnitude)

        assert (metal
                is not None) | (FeH is not None), "Need a chemical par. value."

        if (metal is not None) & (FeH is not None):
            print("Warning: both Z & [Fe/H] provided, ignoring [Fe/H].")

        if metal is None:
            metal = self.FeHtometal(FeH)

        assert metal in self.Z, "Metal %f not find in %s" % (metal, self.Z)

        data = {}
        t = self.data.selectWhere("*", "(Z == _z)", condvars={"_z": metal})
        if _age in self.ages:
            # no interpolation, isochrone already in the file
            t = t.selectWhere("*",
                              "(logA == _age)",
                              condvars={"_age": log10(_age)})
            for kn in list(t.keys()):
                data[kn] = np.asarray(t[kn])
        else:
            # interpolate between isochrones
            d = (self.ages - float(_age))**2
            a1, a2 = self.ages[np.argsort(d)[:2]]
            # print "Warning: Interpolation between %d and %d Myr" % (a1, a2)
            r = np.log10(_age / a1) / np.log10(a2 / a1)

            t1 = t.selectWhere("*",
                               "logA == _age",
                               condvars={"_age": log10(a1)})
            t2 = t.selectWhere("*",
                               "logA == _age",
                               condvars={"_age": log10(a2)})

            stop = min(t1.nrows, t2.nrows)

            for kn in list(t1.keys()):
                y2 = t2[kn][:stop]
                y1 = t1[kn][:stop]
                data[kn] = y2 * r + y1 * (1.0 - r)
                del y1, y2

        # mass selection
        if masses is not None:
            # masses are expected in logM for interpolation
            if masses.max() > 2.3:
                _m = np.log10(masses)
            else:
                _m = masses
            data_logM = data["logM"][:]
            for kn in data:
                data[kn] = interp(_m, data_logM, data[kn])

        del t
        table = Table(data, name="Isochrone from %s" % self.name)
        table.header["metal"] = metal
        table.header["time"] = _age
        return table