Exemple #1
0
 def mass_excess(self, ions):
     """
     TODO:
       generally supplement by data from
          http://www.nndc.bnl.gov/masses/mass.mas12
     """
     if not is_iterable(ions):
         shape = ()
         ions = ions,
     else:
         shape = np.shape(ions)
     if not hasattr(self, '_mass_excess_data'):
         self._mass_excess_data = dict()
     me = []
     spec_ions_me = {
         isotope.ion('nt1') : 8.07131714,
         isotope.ion('h1' ) : 7.28897059,
         isotope.ion('he4') : 2.42491561,
         isotope.ion('be8') : 4.941671,
         }
     for i in ions:
         x = self._mass_excess_data.get(i, None)
         if x is None:
             try:
                 x = self.__getitem__(i).mass_excess()
             except KeyError:
                 x = spec_ions_me[isotope.ion(i)]
             self._mass_excess_data[i] = x
         me.append(x)
     if shape == ():
         return me[0]
     return np.array(me)
Exemple #2
0
    def add_stable(self, ix):
        """
        Flag an ion as stable, extending decays from edge.

        Assume all isotopes are either isomers or isotopes.
        Extra gap fillers will be assumed to be isomers in gs (if isomeric)
        """
        Z = ix.Z
        A = ix.A
        E = ix.E
        a = np.array([jx.A for jx in self.decdata.keys() if jx.Z == Z and jx.E == E])
        if len(a) > 0:
            amin = min(a)
            amax = max(a)
            if self.isomers:
                E = 0
            else:
                E = None
            for a in range(A+1, amin):
                newion = ion(Z = Z, A = a, E = E)
                self.decdata[newion] = self.get_decay(newion)
            for a in range(amax+1, A):
                newion = ion(Z = Z, A = a, E = E)
                self.decdata[newion] = self.get_decay(newion)
        # finally add/overwrite "stable"
        self.decdata[ix] = [(np.float64(1),)]
Exemple #3
0
 def __init__(self, i_in, i_out, rate):
     i_in = list(iterable(i_in))
     i_out = list(iterable(i_out))
     for j,i in enumerate(i_in):
         if isinstance(i, str):
             i_in[j] = ion(i)
     for j,i in enumerate(i_out):
         if isinstance(i, str):
             i_out[j] = ion(i)
     self.i_in = i_in
     self.i_out = i_out
     self.rate = rate
Exemple #4
0
    def get_decay(self, ix):
        """
        Return decay table entry.

        If the decay is not in stored data, extrapolate from last
        available decay at same element (Z value).

        Use gs decays only for extrapolation and assume unspecified
        excited states do single 'g' decay.

        TODO: should we store new entries?
        """
        try:
            return self.decdata[ix]
        except:
            if ix.is_isomer():
                if ix.E > 0:
                    return [(1., ix.isomer(E = ix.E - 1))]
            Z = ix.Z
            a = np.array([ix.A for ix in self.decdata.keys() if ix.Z == Z and ix.E == 0])
            assert len(a) > 0, "Problem finding isotopes for decay."
            assert not (min(a) < ix.A < max(a)), 'decay chain has gaps, no unique extrapolation possible'
            A = min(max(a), max(min(a), ix.A))
            refion = ion(Z = Z,
                         A = A,
                         isomer = ix.is_isomer())
            try:
                refdec = self.decdata[refion]
            except KeyError:
                raise Exception('Decay Extrapolation: Could not determine reference nucleus')
            dec = copy(refdec)
            dA = ix.A - refion.A
            for i, branch in enumerate(refdec):
                br = branch[0]
                products = list(branch[1:])
                # stable
                if len(products) == 0:
                    assert len(refdec) == 0, 'can only be stable or not'
                    continue
                #Q: use last or most heavy nucleus?
                #A: let's check last one is most heavy
                ap = ufunc_A(products)
                maxa = np.where(ap == np.max(ap))[0]
                assert len(maxa) == 1, 'cannot determine decay nucleus'
                # or I could just use the most heavy nucleus
                idec = maxa[0]
                refdecion = products[idec]
                newdecion = ion(Z = refdecion.Z,
                                A = refdecion.A + dA,
                                isomer = ix.is_isomer())
                products[idec] = newdecion
                dec[i] = tuple([br] + products)
            return dec
Exemple #5
0
 def __init__(self, f, mode = 'winvne2', nt9 = None):
     assert mode == 'winvne2'
     assert nt9 is not None
     l = f.readline()
     if len(l.strip()) == 0:
         raise EmptyRecord()
     nuc, A, Z, N, S, ME, label = l.split()
     self.ion = isotope.ion(nuc)
     self.A = int(round(float(A)))
     self.Z = int(Z)
     self.N = int(N)
     self.S = float(S)
     self.ME = float(ME)
     self.E = 0.
     self.label = label
     assert self.N + self.Z == self.A
     assert self.ion.N == self.N
     assert self.ion.Z == self.Z
     assert self.ion.E == 0
     data = []
     for i in range(nt9):
         j = i % 8
         if j == 0:
             l = f.readline()
         data.append(float(l[12*j:12*(j+1)]))
     self.coeff = data
     self.Q = round(
         self.Z * 7.28898454697355
         + self.N * 8.071317791830353
         - self.ME, 3)
     self.formula = self.winvne2_type
Exemple #6
0
 def find_rate(self, ion, reac = None, return_other = False, silent = False):
     if reac is None:
         i = ion.find('(')
         if i < 0:
             i = len(ion) - 2
         reac = ion[i:]
         ion = ion[:i]
     if not isinstance(ion, isotope.Ion):
         ion = isotope.ion(ion)
     if isinstance(reac, int):
         return self[ion], rate
     reac = ReactIon(reac)
     prod = ion + reac
     forward = True
     if ion.Z > prod.Z or (ion.Z == prod.Z and ion.A > prod.A):
         ion, prod = prod, ion
         reac = -reac
         forward = False
     rec = self[ion]
     ind = self.rate_map[str(reac)]
     s = '{}{}{}: {}'.format(ion, reac, prod, rec[ind].creac)
     if rec[ind].cref != '':
         s +=' ({})'.format(rec[ind].cref)
     s += ' {} {} {}'.format(ind, *rec[ind].ic)
     if forward:
         s += ' forward'
     else:
         s += ' reverse'
     if not silent:
         print(' [BDAT] ' + s)
     ret_val = rec, ind, forward
     if return_other:
         ret_val += (self[prod],)
     return ret_val
Exemple #7
0
    def __init__(self,
                 *args,
                 check = False,
                 silent = False):

        (nz, nzx, nn, na, iso,
         q,
         sa, ist, gs,
         ic, c,
         cm, cref, creac) = args

        self.ion = isotope.ion(Z=nz, A=na)
        self.q     = q
        self.sa    = sa
        self.ist   = ist
        self.gs    = gs
        self.cm    = cm

        self.rates = [BDatRate(ic[i], c[i], creac[i], cref[i]) for i in range(len(ic))]

        if not check:
            return

        assert nz == nzx
        assert nn == na - nz
        assert self.ion == iso
    def stackplot(self, ions=None):
        """
        Produces a plot of contributions of each isotope towards the total ejected fraction
	also plots the rate of ejection over time for each isotope.

        Input desired isotopes as a string or isotope.ion vector
        """
        topes = ions
        if topes is None:
            topes = input('Enter desired isotopes: ')

        if isinstance(topes, str):
            topes = topes.split()
        topes = np.array([isotope.ion(x) for x in topes])

        fig = plt.figure(1)
        ax = fig.add_subplot(1, 1, 1)
        taxis = np.linspace(self.tmin, self.tmax, self.numsteps)
        y = []

        # this will collect the required isotopes to be stacked, will also create the legend as stackplot can't do it.

        for x in range(len(topes)):
            topeindex = np.where(topes[x] == self.isoinfo)[0][0]
            y.append(self.mastersum[topeindex])
            ax.plot([], [], label=self.isoinfo[topeindex].LaTeX())
        ax.plot(taxis, self.total, '--', label='Grand Total')

        # this resets the colour cycle to default so the stackplot colours match with the legend, generalises the code and allowsthe user to select any number of isotopes
        plt.gca().set_prop_cycle(None)

        ax.stackplot(taxis, y)
        ax.set_ylabel('Ejecta Mass Fraction')
        ax.set_xlabel('Time(years)')
        ax.set_title('Contribution by isotopes to ejecta.')
        ax.legend(loc='upper left')
        fig.tight_layout()
        plt.show()
        fig.savefig(
            os.path.expanduser('~/python/project/outputfiles/stackplot.pdf'),
            bbox_inches='tight')

        fig = plt.figure(2)
        plt.gca().set_prop_cycle(None)
        bx = fig.add_subplot(1, 1, 1)
        for x in range(len(topes)):
            topeindex = np.where(topes[x] == self.isoinfo)[0][0]
            m = lambda t: np.exp(self.interpolationfunction(np.log(t)))
            y = lambda t: -self.IMF(m(t)) * self.c * self.deriv(np.log(
                t)) * self.isofracinterp[topeindex](t) / t * m(t)
            bx.plot(taxis, y(taxis), label=self.isoinfo[topeindex].LaTeX())
        bx.set_ylabel('Ejecta Rate (massfraction per year)')
        bx.set_xlabel('Time(years)')
        bx.set_title('Rate of mass ejection over time.')
        bx.legend(loc='upper right')
        fig.tight_layout()
        plt.show()
        fig.savefig(
            os.path.expanduser('~/python/project/outputfiles/ejectarate.pdf'),
            bbox_inches='tight')
Exemple #9
0
 def find_rate(self, ion, reac = None, return_other = False, silent = False):
     if reac is None:
         i = ion.find('(')
         if i < 0:
             i = len(ion) - 2
         reac = ion[i:]
         ion = ion[:i]
     if not isinstance(ion, isotope.Ion):
         ion = isotope.ion(ion)
     if isinstance(reac, int):
         return self[ion], rate
     reac = ReactIon(reac)
     prod = ion + reac
     forward = True
     if ion.Z > prod.Z or (ion.Z == prod.Z and ion.A > prod.A):
         ion, prod = prod, ion
         reac = -reac
         forward = False
     rec = self[ion]
     ind = self.rate_map[str(reac)]
     s = '{}{}{}: {}'.format(ion, reac, prod, rec[ind].creac)
     if rec[ind].cref != '':
         s +=' ({})'.format(rec[ind].cref)
     s += ' {} {} {}'.format(ind, *rec[ind].ic)
     if forward:
         s += ' forward'
     else:
         s += ' reverse'
     if not silent:
         print(' [BDAT] ' + s)
     ret_val = rec, ind, forward
     if return_other:
         ret_val += (self[prod],)
     return ret_val
    def __init__(self, data=default_data, silent=False):
        """
        TODO - implement data
        """
        self.setup_logger(silent=silent)
        path = os.getenv('KEPLER_DATA')
        if not path:
            path = os.path.join(os.path.expanduser('~'), 'kepler',
                                'local_data')
            self.logger.warning('using default path ' + path)
        filename = os.path.join(path, 'masses_audi_2003.dat')

        self.comment = ()
        self.iso = np.array([], dtype=np.object)
        self.mass = np.array([], dtype=np.float64)

        xre = re.compile('[-+a-zA-Z0-9.]+')
        with open(filename, 'r') as f:
            self.logger_file_info(f)
            for line in f:
                if not line.startswith((';', '#')):
                    xdata = xre.findall(line)
                    xnum = len(xdata)
                    if xnum == 0:
                        continue
                    if xnum == 2:
                        xion, xabu = tuple(xdata)
                    else:
                        print(line)
                        raise IOError('bad format')
                    self._append(isotope.ion(xion), np.double(xabu))
                else:
                    self.comment += (line[2:], )
        message = "{:3d} masses loaded in".format(len(self.iso))
        self.close_logger(timing=message)
Exemple #11
0
    def __init__(self,
                 *args,
                 check = False,
                 silent = False):

        (nz, nzx, nn, na, iso,
         q,
         sa, ist, gs,
         ic, c,
         cm, cref, creac) = args

        self.ion = isotope.ion(Z=nz, A=na)
        self.q     = q
        self.sa    = sa
        self.ist   = ist
        self.gs    = gs
        self.cm    = cm

        self.rates = [BDatRate(ic[i], c[i], creac[i], cref[i]) for i in range(len(ic))]

        if not check:
            return

        assert nz == nzx
        assert nn == na - nz
        assert self.ion == iso
 def __init__(self, f, mode='winvne2', nt9=None):
     assert mode == 'winvne2'
     assert nt9 is not None
     l = f.readline()
     if len(l.strip()) == 0:
         raise EmptyRecord()
     nuc, A, Z, N, S, ME, label = l.split()
     self.ion = isotope.ion(nuc)
     self.A = int(round(float(A)))
     self.Z = int(Z)
     self.N = int(N)
     self.S = float(S)
     self.ME = float(ME)
     self.E = 0.
     self.label = label
     assert self.N + self.Z == self.A
     assert self.ion.N == self.N
     assert self.ion.Z == self.Z
     assert self.ion.E == 0
     data = []
     for i in range(nt9):
         j = i % 8
         if j == 0:
             l = f.readline()
         data.append(float(l[12 * j:12 * (j + 1)]))
     self.coeff = data
     self.Q = round(
         self.Z * 7.28898454697355 + self.N * 8.071317791830353 - self.ME,
         3)
     self.formula = self.winvne2_type
    def isoyield(self, tmin, tmax, ions=None):
        """
        isoyield acts like massyield except it calculates the yield for
        any given isotope and time interval. 
        Input tmin, tmax, isotopes as a string or isotope.ion array

        """
        topes = ions
        if topes is None:
            topes = input('Enter desired isotopes: ')

        if isinstance(topes, str):
            topes = re.split('[ ,;]+', topes)
        topes = np.array([isotope.ion(x) for x in topes])

        for x in range(len(topes)):
            topeindex = np.where(topes[x] == self.isoinfo)[0][0]

            self.intsum = yieldout.yieldcode(tmin, tmax, self.correctedtime,
                                             self.isosol[topeindex],
                                             self.isofracinterp[topeindex],
                                             self.interpolationfunction,
                                             self.c, self.IMF)

            print('The yield for ', self.isoinfo[topeindex], ' is ',
                  self.intsum)
Exemple #14
0
def iyplot(tmin, tmax, numsteps, mastersum, isoinfo, total, ions):
 
    """
    Isotopeyieldplot plots the yield of the entered isotopes on a logscale alongwith the grand total of all isotopes ejected.
    """

    topes = ions
    if topes is None:
        topes = input('Enter desired isotopes: ')
    
    if isinstance (topes, str):
        topes = re.split('[ ,;]+', topes)
    topes  =  np.array([isotope.ion(x) for x in topes])
    fig = plt.figure(1)
    ax = fig.add_subplot(1,1,1)
    taxis = np.linspace(tmin, tmax, numsteps)
        
    for x in range(len(topes)):
        topeindex = np.where(topes[x] == isoinfo)[0][0]
        ax.plot(taxis, mastersum[topeindex], label = isoinfo[topeindex].LaTeX())
            

    ax.plot(taxis, total, '--', label = 'Grand Total')
    ax.set_ylabel('Ejecta Mass Fraction')

    ax.set_xlabel('Time(years)')
    ax.set_yscale('log')
        
    ax.set_title('Mass ejection over time for star dependent energy')
    ax.legend(loc = 'best')
    fig.tight_layout()
    plt.show()
    fig.savefig(os.path.expanduser('~/python/project/outputfiles/noexplisoyieldplot.pdf'), bbox_inches = 'tight')
Exemple #15
0
 def decaydata(self):
     decays = list()
     for d in self.data:
         r = d.get_ad()
         if r is not None:
             decays += [r]
         r = d.get_bd()
         if r is not None:
             decays += [r]
     decays += [DecayRate([isotope.ion('be8')],
                          [isotope.ion('he4'), isotope.ion('he4')],
                          np.log(2)/6.7e-8),
                DecayRate([isotope.ion('nt1')],
                          [isotope.ion('pn1')],
                          np.log(2)/881.5),
                ]
     return decays
Exemple #16
0
 def decaydata(self):
     decays = list()
     for d in self.data:
         r = d.get_ad()
         if r is not None:
             decays += [r]
         r = d.get_bd()
         if r is not None:
             decays += [r]
     decays += [DecayRate([isotope.ion('be8')],
                          [isotope.ion('he4'), isotope.ion('he4')],
                          np.log(2)/6.7e-8),
                DecayRate([isotope.ion('nt1')],
                          [isotope.ion('pn1')],
                          np.log(2)/881.5),
                ]
     return decays
Exemple #17
0
 def __getitem__(self, ion):
     if not hasattr(self, '_ion_hash'):
         self._ion_hash = {d.ion : i for i,d in enumerate(self.data)}
     if not isinstance(ion, isotope.Ion):
         ion = isotope.ion(ion)
     try:
         return self.data[self._ion_hash[ion]]
     except:
         raise KeyError('{} not in data base'.format(ion))
Exemple #18
0
 def __getitem__(self, ion):
     if not hasattr(self, '_ion_hash'):
         self._ion_hash = {d.ion : i for i,d in enumerate(self.data)}
     if not isinstance(ion, isotope.Ion):
         ion = isotope.ion(ion)
     try:
         return self.data[self._ion_hash[ion]]
     except:
         raise KeyError('{} not in data base'.format(ion))
Exemple #19
0
    def get_ad(self):
        ic = self[7].ic
        if ic[0] == 0:
            return None
        assert ic[0] == 19
        i_in = (self.ion + 'he4', )
        i_out = (self.ion, isotope.ion('he4'))
        rate = self[7].c[0]

        return DecayRate(i_in, i_out, rate)
Exemple #20
0
    def get_ad(self):
        ic = self[7].ic
        if ic[0] == 0:
            return None
        assert ic[0] == 19
        i_in = (self.ion + 'he4', )
        i_out = (self.ion, isotope.ion('he4'))
        rate = self[7].c[0]

        return DecayRate(i_in, i_out, rate)
Exemple #21
0
    def __getitem__(self, ion):
        """
        Return mass of ion in amu (or approximate)

        TODO: accept list
        """
        try:
            i, = np.argwhere(self.iso == ion)
            return self.mass[i[0]]
        except:
            pass
        return np.double(isotope.ion(ion).A)
Exemple #22
0
    def __init__(self,
                 filename = '~/Plots/solar/Asplund2009-isotopes_protosun.dat',
                 comment = None,
                 silent = False):
        """
        Load abundace set from Aspund "dat" file.

        TODO - add option to show comment
        """
        self.setup_logger(silent = silent)
        comment = stuple(comment)

        xre = re.compile('[-+a-zA-Z0-9.]+')
        iso = np.array([],dtype=np.object)
        abu = np.array([],dtype=np.float64)

        filename = os.path.expanduser(filename)

        with open(filename,'r') as f:
            self.logger_file_info(f)
            comment += ('',
                        'Generated from file "{:s}".'.format(filename),
                        'Original file comments follow:',
                        '')
            for line in f:
                if not line.startswith((';','#')):
                    xdata = xre.findall(line)
                    xnum = len(xdata)
                    if xnum == 0:
                        continue
                    if xnum == 5:
                        xiso = isotope.ion(A = int(xdata[2]),
                                   Z = int(xdata[1]))
                        xabu = np.double(xdata[4])
                    else:
                        print(line)
                        raise IOError('bad format')
                    iso = np.append(iso, xiso)
                    abu = np.append(abu, xabu)
                else:
                    comment += (line[2:].rstrip(),)
        m = Mass()

        # well, this could require tests...
        abu = np.array([a*m(i) for i,a in zip(iso,abu)])
        abu = abu/abu.sum()

        super().__init__(
            iso = iso,
            abu = abu,
            comment = comment)
        message = "{:3d} isotopes loaded in".format(iso.size)
        self.close_logger(timing = message)
Exemple #23
0
 def daughters(self, ix):
     """
     return dictionary of daughter nuclei (including self) and their weights
     """
     ix = ion(ix)
     ii = np.where(ix == self.ions)[0][0]
     col = self.map[ii,:]
     ii = np.where(col > 0)[0]
     p = {}
     for i in ii:
         p[self.decions[i]] = col[i]
     return p
Exemple #24
0
    def __getitem__(self, ion):
        """
        Return mass of ion in amu (or approximate)

        TODO: accept list
        """
        try:
            i, = np.argwhere(self.iso == ion)
            return self.mass[i[0]]
        except:
            pass
        return np.double(isotope.ion(ion).A)
Exemple #25
0
    def __init__(self,
                 filename = '~/Plots/solar/Asplund2009-isotopes_protosun.dat',
                 comment = None,
                 silent = False):
        """
        Load abundace set from Aspund "dat" file.

        TODO - add option to show comment
        """
        self.setup_logger(silent = silent)
        comment = stuple(comment)

        xre = re.compile('[-+a-zA-Z0-9.]+')
        iso = np.array([],dtype=np.object)
        abu = np.array([],dtype=np.float64)

        filename = os.path.expanduser(filename)

        with open(filename,'r') as f:
            self.logger_file_info(f)
            comment += ('',
                        'Generated from file "{:s}".'.format(filename),
                        'Original file comments follow:',
                        '')
            for line in f:
                if not line.startswith((';','#')):
                    xdata = xre.findall(line)
                    xnum = len(xdata)
                    if xnum == 0:
                        continue
                    if xnum == 5:
                        xiso = isotope.ion(A = int(xdata[2]),
                                   Z = int(xdata[1]))
                        xabu = np.double(xdata[4])
                    else:
                        print(line)
                        raise IOError('bad format')
                    iso = np.append(iso, xiso)
                    abu = np.append(abu, xabu)
                else:
                    comment += (line[2:].rstrip(),)
        m = Mass()

        # well, this could require tests...
        abu = np.array([a*m(i) for i,a in zip(iso,abu)])
        abu = abu/abu.sum()

        super().__init__(
            iso = iso,
            abu = abu,
            comment = comment)
        message = "{:3d} isotopes loaded in".format(iso.size)
        self.close_logger(timing = message)
Exemple #26
0
 def __init__(self, *args, **kwargs):
     # initialise with minnet?
     netnum = kwargs.pop('netnum', None)
     if netnum is None:
         if len(args) > 0 and isinstance(args[0], str):
             netnum = args.pop(0)
         else:
             netnum = 1
     self.netnum = netnum
     kwargs['duplicates'] = False
     super().__init__(*args, **kwargs)
     self.compositions = []
     self.minnet = np.array([isotope.ion(i) for i in _minnet])
     self.add(self.minnet)
     # find gaps
     gaps = []
     j = self.minnet[0]
     for i in range(1, len(self.minnet)):
         j, i = self.minnet[i], j
         if i.Z == j.Z and j.A > i.A + 1:
             gaps.append(isotope.ion(Z = j.Z, A = i.A + 1))
     self.gaps = np.array(gaps)
 def __init__(self, *args, **kwargs):
     # initialise with minnet?
     netnum = kwargs.pop('netnum', None)
     if netnum is None:
         if len(args) > 0 and isinstance(args[0], str):
             netnum = args.pop(0)
         else:
             netnum = 1
     self.netnum = netnum
     kwargs['duplicates'] = False
     super().__init__(*args, **kwargs)
     self.compositions = []
     self.minnet = np.array([isotope.ion(i) for i in _minnet])
     self.add(self.minnet)
     # find gaps
     gaps = []
     j = self.minnet[0]
     for i in range(1, len(self.minnet)):
         j, i = self.minnet[i], j
         if i.Z == j.Z and j.A > i.A + 1:
             gaps.append(isotope.ion(Z=j.Z, A=i.A + 1))
     self.gaps = np.array(gaps)
Exemple #28
0
 def mass_excess(self, ions):
     """
     TODO:
       generally supplement by data from
          http://www.nndc.bnl.gov/masses/mass.mas12
     """
     if not is_iterable(ions):
         shape = ()
         ions = ions,
     else:
         shape = np.shape(ions)
     if not hasattr(self, '_mass_excess_data'):
         self._mass_excess_data = dict()
     me = []
     spec_ions_me = {
         isotope.ion('nt1') : 8.07131714,
         isotope.ion('h1' ) : 7.28897059,
         isotope.ion('he4') : 2.42491561,
         isotope.ion('be8') : 4.941671,
         }
     for i in ions:
         x = self._mass_excess_data.get(i, None)
         if x is None:
             try:
                 x = self.__getitem__(i).mass_excess()
             except KeyError:
                 try:
                     x = spec_ions_me[isotope.ion(i)]
                 except KeyError:
                     x = 0
                     #print(f' [ERROR] NOT FOUND: {i} (returning {x})')
                     print(' [ERROR] NOT FOUND: {} (returning {})'.format(i,x))
             self._mass_excess_data[i] = x
         me.append(x)
     if shape == ():
         return me[0]
     return np.array(me)
 def load_nuclear_data(
     self,
     filename='/home/alex/kepler/fission/winvne_v2.0.dat',
     mode='winvne2',
 ):
     """
     load nuclear data for ReacLib
     """
     self.setup_logger(silent=False)
     assert mode == 'winvne2'
     nucdata = []
     with open(filename) as f:
         self.logger.info(f'loading {filename} ...')
         # read header: grid and nuclei info
         l = f.readline()
         assert len(l.strip()) == 0, '{}'.format(len(l)) + ' >' + l + '<'
         l = f.readline()
         assert l.rstrip(
         ) == '010015020030040050060070080090100150200250300350400450500600700800900100'
         t9grid = [
             int(l[3 * i:3 * (i + 1)]) / 10
             for i in range(len(l.rstrip()) // 3)
         ]
         nt9 = len(t9grid)
         nuclei = []
         while True:
             l = f.readline()
             n = isotope.ion(l)
             # equal nuclei is used as sentinel for end of list
             if len(nuclei) > 1 and nuclei[-1] == n:
                 break
             nuclei.append(n)
         nnuclei = len(nuclei)
         self.logger.info('{} temperature points for {} nuclei.'.format(
             nt9, nnuclei))
         while True:
             try:
                 nuc = ReacLibNuc(f, mode=mode, nt9=nt9)
                 if nuc is not None:
                     nucdata.append(nuc)
             except Exception as e:
                 if isinstance(e, EmptyRecord):
                     break
                 else:
                     raise
         assert len(nucdata) == len(nuclei)
     self.nucdata = nucdata
     self.close_logger(r'loaded {} nuclei in '.format(len(nucdata)))
Exemple #30
0
    def output2ionarr(ions, molfrac_out = None):
        """
        extract ions from input data

        # TODO add IonMap
        """
        if isinstance(ions, AbuData):
            molfrac_out = ions.molfrac
            ions = ions.ions
        elif isinstance(ions, AbuSet):
            assert molfrac_out in (None, False)
            molfrac_out = False
            ions = ions.iso
        if isinstance(ions, IonList):
            ions = np.array(ions)
        ions = np.atleast_1d(ions)
        if isinstance(ions[0], str):
            ions = np.array([ion(ix) for ix in ions])
        return ions, molfrac_out
Exemple #31
0
 def load_nuclear_data(self,
                       filename = '/home/alex/kepler/fission/winvne_v2.0.dat',
                       mode = 'winvne2',
                       ):
     """
     load nuclear data for ReacLib
     """
     self.setup_logger(silent = False)
     assert mode == 'winvne2'
     nucdata = []
     with open(filename) as f:
         self.logger.info(f'loading {filename} ...')
         # read header: grid and nuclei info
         l = f.readline()
         assert len(l.strip()) == 0, '{}'.format(len(l)) + ' >' + l + '<'
         l = f.readline()
         assert l.rstrip() == '010015020030040050060070080090100150200250300350400450500600700800900100'
         t9grid = [int(l[3*i:3*(i+1)])/10 for i in range(len(l.rstrip())//3)]
         nt9 = len(t9grid)
         nuclei = []
         while True:
             l = f.readline()
             n = isotope.ion(l)
             # equal nuclei is used as sentinel for end of list
             if len(nuclei) > 1 and nuclei[-1] == n:
                 break
             nuclei.append(n)
         nnuclei = len(nuclei)
         self.logger.info('{} temperature points for {} nuclei.'.format(nt9, nnuclei))
         while True:
             try:
                 nuc = ReacLibNuc(f, mode = mode, nt9 = nt9)
                 if nuc is not None:
                     nucdata.append(nuc)
             except Exception as e:
                 if isinstance(e, EmptyRecord):
                     break
                 else:
                     raise
         assert len(nucdata) == len(nuclei)
     self.nucdata = nucdata
     self.close_logger(r'loaded {} nuclei in '.format(len(nucdata)))
Exemple #32
0
    def _abu_massfrac_raw(self, scale):
        """
        Raw scaled solar abundances
        """

        scaled = self.sun * scale + self.bbn * (1 - scale)

        # beyond-solar scaling
        if scale > 1.:
            jj, = np.argwhere(scaled.iso == isotope.ion('He4'))
            # make sure we have same set of istopes
            bbn = (self.sun * 0) + self.bbn
            for j in np.argwhere(scaled.abu < self.sun.abu).flat:
                scaled.abu[jj] += scaled.abu[j]
                scaled.abu[j] = self.sun.abu[j] * np.exp(
                    (scale - 1)*(1 - self.bbn.abu[j]/self.sun.abu[j]))
                scaled.abu[jj] -= scaled.abu[j]
        scaled.normalize()

        return scaled.abu
Exemple #33
0
    def _abu_massfrac_raw(self, scale):
        """
        Raw scaled solar abundances
        """

        scaled = self.sun * scale + self.bbn * (1 - scale)

        # beyond-solar scaling
        if scale > 1.:
            jj, = np.argwhere(scaled.iso == isotope.ion('He4'))
            # make sure we have same set of istopes
            bbn = (self.sun * 0) + self.bbn
            for j in np.argwhere(scaled.abu < self.sun.abu).flat:
                scaled.abu[jj] += scaled.abu[j]
                scaled.abu[j] = self.sun.abu[j] * np.exp(
                    (scale - 1)*(1 - self.bbn.abu[j]/self.sun.abu[j]))
                scaled.abu[jj] -= scaled.abu[j]
        scaled.normalize()

        return scaled.abu
def bbncoc(filename, write=False):
    """
    convert BBN abunaces from
    http://www2.iap.fr/users/pitrou/primat.htm
    to data file
    """

    with open(filename) as f:
        lines = f.readlines()
    ions = []
    abu = []
    for i, l in enumerate(lines):
        if l.count('1 n') > 0:
            break
    while True:
        if lines[i].count('Z=') > 0:
            break
        offset = 0
        if lines[i].startswith(';'):
            offset += 2
        xions = [
            ''.join(lines[i][k:k + 10].split())
            for k in range(offset, 70 + offset, 10)
        ]
        i += 1
        xabu = list(lines[i][offset:].split())
        ions += [x for x in xions if len(x) > 0]
        abu += xabu
        i += 2
    abu = [float(a) for a in abu]
    ions = isotope.ion(ions)
    abu = AbuSet(ions, abu)
    from ionmap import decay
    abu = decay(abu, stable=True)
    if write:
        with open(filename, 'at') as f:
            for a in abu:
                #f.write(f'{a[0].name():5s} {a[1]:12.5e}\n')
                f.write('{:5s} {:12.5e}\n'.format(a[0].name(), a[1]))
    return abu
Exemple #35
0
    def __init__(self,
                 data = default_data,
                 silent = False):
        """
        TODO - implement data
        """
        self.setup_logger(silent = silent)
        path = os.getenv('KEPLER_DATA')
        if not path:
            path=os.path.join(os.path.expanduser('~'),'kepler','local_data')
            self.logger.warning('using default path ' + path)
        filename = os.path.join(path,'masses_audi_2003.dat')

        self.comment = ()
        self.iso  = np.array([],dtype=np.object)
        self.mass = np.array([],dtype=np.float64)

        xre = re.compile('[-+a-zA-Z0-9.]+')
        with open(filename,'r') as f:
            self.logger_file_info(f)
            for line in f:
                if not line.startswith((';','#')):
                    xdata = xre.findall(line)
                    xnum = len(xdata)
                    if xnum == 0:
                        continue
                    if xnum == 2:
                        xion,xabu = tuple(xdata)
                    else:
                        print(line)
                        raise IOError('bad format')
                    self._append(isotope.ion(xion), np.double(xabu))
                else:
                    self.comment += (line[2:],)
        message = "{:3d} masses loaded in".format(len(self.iso))
        self.close_logger(timing = message)
def data(dbfilename=os.path.expanduser(
    '~/python/project/znuc2012.S4.star.el.y.stardb.gz')):
    """
    This is the main data collecting module which gets every single isotope/remnant mass from the database which is later used to interpolate from to obtain desired values
    """
    db = stardb.load(dbfilename)  # loads database
    nmass = db.nvalues[0]  # finds the number of values
    masses = db.values[0][:nmass]  #creates a vector of the initial masses
    isodb = stardb.load(
        os.path.expanduser(
            '~/python/project/znuc2012.S4.star.deciso.y.stardb.gz'))

    massnumber = []
    for x in range(len(isodb.ions)):
        mn = isodb.ions[x].A
        massnumber.append(mn)
    massnumber = np.array(massnumber)
    np.save(os.path.expanduser('~/python/project/filestoload/Massnumber'),
            massnumber)
    #######################
    # write all energy and mixing values

    energyvalues = np.unique(db.fielddata['energy'])
    mixingvalues = np.unique(db.fielddata['mixing'])
    masterremnant = []  # result will be a multidimensional array
    elementdata = []
    isodata = []
    r = len(db.ions)  # for loop iteration
    w = len(isodb.ions)
    for energy in energyvalues:
        remmixingarray = []  # reinitialise the next dimension
        elmixingarray = []
        isomixingarray = []
        for mixing in mixingvalues:

            ii = np.logical_and(np.isclose(db.fielddata['energy'], energy),
                                np.isclose(db.fielddata['mixing'], mixing))

            mass = db.fielddata[ii]['remnant']
            remmixingarray.append(
                mass
            )  # this is an array of remnant masses for one energy and every mixing value

            elfill = []  # reinitialise the next dimension again
            isofill = []

            for m in range(w):

                a = isodb.ions[m]  #for obtaining the element string
                kk = np.where(
                    isodb.ions == isotope.ion(a)
                )  # finding the indices in db.ions for a particular element
                jj = np.where(ii)
                isotopes = isodb.data[jj, kk][
                    0]  # array of abundances for that particular element
                isofill.append(
                    isotopes
                )  # this is an array of element data for every mass for one energy and one mixing value

            isomixingarray.append(isofill)

        masterremnant.append(
            remmixingarray
        )  # these master arrays have every bit of data under its own energy. so called like elementdata[energy][mixing][elementnumber] gives the element data for every star for a single element.

        isodata.append(isomixingarray)

    np.save(os.path.expanduser('~/python/project/filestoload/IsoData'),
            isodata)
    np.save(os.path.expanduser('~/python/project/filestoload/RemnantMasses'),
            masterremnant)
    np.save(os.path.expanduser('~/python/project/filestoload/Ioninfo'),
            isodb.ions)
    time = []

    for mass in masses:  # for loop will cycle through the masses and grab the lifetime of each star
        s = str(
            mass)  # converts the mass number to a string for file acquiring
        if s.endswith('.0'):  # formatting issue, to match the filenames
            s = s[:-2]
        filename = os.path.expanduser(
            '~/python/project/dumps/z{}#presn').format(s)
        # grabs filename corrosponding to this mass
        d = kepdump.load(filename)  # loads the kepdump data for this star
        time.append(d.time)
    yr = 365.2425 * 86400
    time = np.array(time) / yr
    dataarray = [masses, time]

    return dataarray
Exemple #37
0
 def ext_ions(self):
     addions = ('nt1', 'h1', 'he4', 'be8')
     ions = set(self.ions) | set(isotope.ion(i) for i in addions)
     return IonList(sorted(list(ions)))
Exemple #38
0
    def __init__(self,
                 ions = None,
                 molfrac_in = None,
                 molfrac_out = None,
                 decay = True,
                 isobars = False,
                 elements = False,
                 isotones = False,
                 isotopes = True,
                 solprod = False,
                 stable = False,
                 solions = False,
                 sort = True,
                 ionlist = None,
                 addions = None,
                 keepions = None,
                 stabions = None,
                 orgions = None,
                 solabu = None,
                 keepall = True,
                 decayfile = '~/kepler/local_data/decay.dat',
                 isomers = None,
                 silent = False,
                 debug = False,
                 ):
        """
        Initialize decay map.

        ions - list of input ions.
               Currently np.array of isotope.Ion.
               Probably should allow (or requre?) composition instead?
               Allow any string, array of strings, ...
               Same for all ion lists.

        decay - whether to do decay
                if disabled and no other option is used,
                the matrix will just do sorting, if specified

        molfrac_in - whether input is mass or abundance.
        molfrac_out - whether output is mass or abundance.
        TODO - add molfrac, used for both

        isobars - return result mapped to isobars   [only stable or undecayed isotopes]
        elements - return result mapped to elements [only stable or undecayed isotopes]
        isotones - return result mapped to isotones [only stable or undecayed isotopes]
        isotopes - return result mapped to isotopes - if processing isomers

        ADD - isotopes - return result mapped to isotopes; isomers otherwise
        ADD - decay - do decay or not

        solabu - solar abundance set to use: filename, token, or isotope.SolAbu
        solprod - return result in terms of solar production factor [only stable isotopes]
        solions - return exactly ions in solar abundace set [plus addions, stabions, keepions]

        ionlist - output *exactly* these isotops

        stable - output only stable isotopes, discard chains
        addions - output these extra ions, but not add to EL/A sums
        keepions - ions to keep as stable but not add ion EL/A sums

        stabions - ions to fully treat as stable - may conflict with solprod

        orgions - ions for which to return the initial value w/o decays

        sort - sort output ions (Z > A > E), mostly relevant when
               customized ions are provided.

        keepall - if set to false, do not keep all ions even if stable set is used.

        decayfile - decay file to use. [should add allowing to pass object]

        isomers - process as isomers if input is isotopes

        silent - whether to be verbose or not
        """
        self.setup_logger(silent)

#        ions = np.array([ion('pb220')])
#        ions = np.array([ion('n13'), ion('o14'), ion('pb209')])
#        ions = np.array([ion('n13'), ion('o14')])

        ions, molfrac_in, molfrac_out = self.input2ionarr(
            ions, molfrac_in, molfrac_out)

        if isomers is None:
            isomers = np.any(ufunc_is_isomer(ions))

        if not isomers and np.any(ufunc_is_isomer(ions)):
            new_ions = assert_isotope(ions)
            assert len(np.unique(ufunc_idx(new_ions))) == len(ions), 'Failed to project ions uniquely'
            ions = new_ions

        if isomers and not np.all(ufunc_is_isomer(ions)):
            ions = assert_isomer(ions)

        # all need to be the same.  TODO - more sophisticated
        assert np.all(ufunc_is_isomer(ions) == ions[0].is_isomer())

        if molfrac_in is None:
            molfrac_in = False
        if molfrac_out is None:
            molfrac_out = molfrac_in

        assert isinstance(ions, np.ndarray), "ions need to be np.array type"
        assert ions.ndim == 1, "ions need to be 1D array"
        assert isinstance(ions[0], Ion), "ions must be of type Ion"

        # find out whether we need list of stable ions
        need_stable = stable

        # TODO - check ionlist should exclude isobars, isotopes, ...
        need_isotopes = isotopes
        need_isobars  = isobars
        need_isotones = isotones
        need_elements = elements

        # add things from ionlist
        if ionlist:
            need_isotopes |= np.any(ufunc_is_isotope(ionlist))
            need_isobars  |= np.any(ufunc_is_isobar(ionlist))
            need_isotones |= np.any(ufunc_is_isotone(ionlist))
            need_elements |= np.any(ufunc_is_element(ionlist))
        if addions:
            need_isotopes |= np.any(ufunc_is_isotope(addions))
            need_isobars  |= np.any(ufunc_is_isobar(addions))
            need_isotones |= np.any(ufunc_is_isotone(addions))
            need_elements |= np.any(ufunc_is_element(addions))

        need_orgions = orgions or not decay

            ### [WORK HERE]

        # THIS IS WRONG - ONLY IF DECAY
        # if need_elements or need_isobars or need_isotones or (need_isotopes and isomers):
        #     need_stable = decay
        if need_elements or need_isobars or need_isotones:
            need_stable = decay

        self.ions = ions
        self.amax = np.max(ufunc_A(ions))
        self.zmax = np.max(ufunc_Z(ions))

        # check keepions
        if keepions is not None:
            if isinstance(keepions, IonSet):
                keepions = np.array(keepions)
            keepions = np.atleast_1d(keepions)
            assert isinstance(keepions, np.ndarray), "keepions need to be np.array type"
            assert keepions.ndim == 1, "keepions need to be 1D array"
            assert issubclass(type(keepions[0]),Ion), "keepions must be of type Ion"

            self.amax = max(self.amax, np.max(ufunc_A(keepions)))
            self.zmax = max(self.zmax, np.max(ufunc_Z(keepions)))

        # check stabions
        if stabions is not None:
            if isinstance(stabions, IonSet):
                stabions = np.array(stabions)
            stabions = np.atleast_1d(stabions)
            assert isinstance(stabions, np.ndarray), "stabions need to be np.array type"
            assert stabions.ndim == 1, "stabions need to be 1D array"
            assert issubclass(type(stabions[0]),Ion), "stabions must be of type Ion"

            self.amax = max(self.amax, np.max(ufunc_A(stabions)))
            self.zmax = max(self.zmax, np.max(ufunc_Z(stabions)))

        # check ionlist
        if ionlist is not None:
            if not isinstance(ionlist, np.ndarray):
                ionlist = np.array(ionlist)
            ionlist = np.atleast_1d(sn.squeeze(ionlist))
            assert ionlist.ndim == 1, "ionlist need to be 1D array"
            assert issubclass(type(ionlist[0]),Ion), "ionlist must be of type Ion"

            self.amax = max(self.amax, np.max(ufunc_A(ionlist)))
            self.zmax = max(self.zmax, np.max(ufunc_Z(ionlist)))

        # generate decay data
        self.decdata = DecayData(
            filename = decayfile,
            amax = self.amax,
            zmax = self.zmax,
            isomers = isomers,
            silent = silent,
            debug = debug,
            )
        # self.decdata = DecayData(decayfile, isomers = isomers, silent = silent)

        # now let's add keepions - not sure about this one - probably wrong
        if keepions is not None:
            # the strategy is to modify the decdata
            for ix in keepions:
                self.decdata.add_stable(ix)

        # ...and stabions
        if stabions is not None:
            # the strategy is modify the decdata
            for ix in stabions:
                self.decdata.add_stable(ix)

        # construct table from ions
        self.dectable = {}
        if decay:
            d0 = [self.iter_add_dectable(ix) for ix in self.ions]
        else:
            d0 = [self.identity_dectable(ix) for ix in self.ions]

        # let us just use indices into the array to speed things up
        self.d = np.ndarray(len(self.dectable), dtype = object)
        for dec in self.dectable.values():
            self.d[dec[0][1]] = dec

        self.decions = np.array([ix for ix in self.dectable.keys()], dtype = object)
        self.indices = np.array([dec[0][1] for dec in self.dectable.values()], dtype = np.int64)

        # construct decay matrix - this should be its separate method!!!
        nions = len(ions)
        ndec = len(self.dectable)
        self.decmatrix = np.zeros([nions,ndec], dtype=np.float64)

        # compute needed decay matrix
        #
        # currently this is fixed when isomers are mapped to isotopes,
        # but this loses the 'maxradio' info for isomers.
        #
        # Instead, in the future, a full square decay matrix needs to
        # be constractued that can invert the isomer submatrix for
        # isotopes, and similar for all cases, releasing the
        # requirement for stable or raw isotopes only.
        #
        # the extra isotopes should be added after a first full decay
        # attempt.
        #
        # not sure this will ever be useful other than for isotopes.
        #
        if need_isotopes and not stable and decay and isomers:
            self.revind = np.argsort(self.indices)
            for i,ix in enumerate(self.ions):
                self.iter_add_decmatrix_iso(i, np.float64(1), d0[i])
        else:
            for i,ix in enumerate(self.ions):
                self.iter_add_decmatrix(i, np.float64(1), d0[i])

        m = self.decions.argsort()
        self.decions = self.decions[m]
        self.decmatrix = self.decmatrix[:,self.indices[m]]

        self.molfrac = [molfrac_in, molfrac_out]

        self.molfrac_convert(self.decmatrix)

        # we need to check whether we need solar abundances.
        need_solabu = solions or solprod
        # since we can get the list of stable ions from the decay table,
        # we do not really need this for definition of stable isotopes.
        if need_solabu:
            if isinstance(solabu, str):
                solabu = SolAbu(solabu)
            elif solabu is None:
                solabu = SolAbu()
            assert isinstance(solabu, SolAbu), "Need solar abundace data."
            # let us assure solar abundance pattern is sorted
            assert not np.any(solabu.iso.argsort() - np.arange(len(solabu))), "Solar pattern not sorted."

            # now we construct the map to solar, smap, and the map
            # from solabu to decions, rmap
            k = 0
            smap = []
            rmap = []
            for i,iso in enumerate(solabu.iso):
                while self.decions[k] < iso:
                    k += 1
                    if k == len(self.decions):
                        break
                if k == len(self.decions):
                    break
                if self.decions[k] == iso:
                    smap.append(k)
                    rmap.append(i)

        # why this ... not need_solabu ???
        # why not have need_solabu inply need_stable?
        if need_stable and not need_solabu:
            # here we are overwring smap from above!!!
            # WHY???
            # DELETE ???
            smap = [i for i,ix in enumerate(self.decions) if len(self.dectable[ix]) == 1]


        # before we do any of the following, we still need to make
        # sure to only include stable isotopes.
        # proably best to keep old array and construct new one piece
        # by piece.

        if need_stable or need_solabu:
            stable_decions = self.decions[smap]
            stable_decmatrix = self.decmatrix[:,smap]

        # add missing solar ions
        # ??? UPDATE to include stab...
        if solions and len(solabu) > len(stable_decions):
            ndec = len(solabu)
            d = np.zeros([nions,ndec], dtype=np.float64)
            d[:,rmap] = stable_decmatrix[:,:]
            stable_decions = solabu.iso
            stable_decmatrix = d

        ### add missing ions from ion list
        # ....
        # can ion list be elements, isobars, isotones?
        # yes!
        #
        # 1) the stuff below needs to be termined which to compute
        # 2) store computed values separately - not right in decions
        # 3) then select the ecessary ones for final decions

        # maybe able to construct decay/isotop map?
        if need_isotopes and not stable and decay and isomers:
            # construct a decay matrix that does not double-count.
            # The key is here a function that finds entries with
            # identical projected values
            decidx = ufunc_isotope_idx(self.decions)
            idx = np.unique(
                decidx,
                )
            decmatrix = self.decmatrix.copy()
            # but how to discard double counts???
            # ??? mat coeff in range, -I, subtract entire column (mat mult)
            # submatrix = np.zeros([len(self.decions)]*2)
            for i in idx:
                ii = np.where(i == decidx)[0]
                if len(ii) > 1:
                    deciso = self.decions[ii]
                    # do we need to assume isomeric states are ordered, or that order matters?
                    ions = []
                    iions = []
                    for jj,ix in enumerate(deciso):
                        j = np.where(self.ions == ix)[0]
                        if len(j) == 1:
                            ions += [j[0]]
                            iions += [ii[jj]]
                        elif len(j) > 1:
                            raise Exception('something is wrong here')
                    print(self.decmatrix[np.ix_(ions,ii)].transpose())

                    # next: sort by chain?
                    # find things that depend on each other, in order
                    # then subtract in order

                    # maybe subtract where things depend on self?

                    # OK, for this to work we need to ensure all ions
                    # on 'out' channels are also on 'in' channel so
                    # the matrix can be 'inverted'.

                    assert len(ii) == len(ions), 'matrix cannot be inverted'

                    # currently, further up, we create a differnt
                    # matrix for this case that does not require this
                    # correction.  In practice, we want to have both
                    # options, the 'maxradio' for all sub-sets and
                    # supersets.



            raise NotImplementedError()

        # *** temporary fix:
        if need_stable:
            raw_ions = stable_decions
            raw_matrix = stable_decmatrix
        else:
            raw_ions = self.decions
            raw_matrix = self.decmatrix


        if need_elements:
            decionz = ufunc_Z(raw_ions)
            elements_decmatrix, z = project(raw_matrix, decionz, return_values = True, axis = -1)
            elements_decions = np.array([ion(Z = Z) for Z in z])
        if need_isobars:
            deciona = ufunc_A(raw_ions)
            isobars_decmatrix, a = project(raw_matrix, deciona, return_values = True, axis = -1)
            isobars_decions = np.array([ion(A = A) for A in a])
        if need_isotones:
            decionn = ufunc_N(raw_ions)
            isotones_decmatrix, n = project(raw_matrix, decionn, return_values = True, axis = -1)
            isotones_decions = np.array([ion(N = N) for N in n])

        # *** likely, this should not use raw_ions but self.decions
        if need_isotopes:
            deciiso = ufunc_isotope_idx(raw_ions)
            isotopes_decmatrix, i = project(raw_matrix, deciiso, return_values = True, axis = -1)
            isotopes_decions = np.array([ion(idx = I) for I in i])

        if need_orgions:
            orgions_decmatrix = np.identity(len(self.ions))
            orgions_decions = self.ions


        if solprod:
            # TODO
            raise NotImplementedError('solprod')


        # compile final decions set; make it an IonList
        if isobars:
            decmatrix = isobars_decmatrix
            decions = isobars_decions
        elif isotones:
            decmatrix = isotones_decmatrix
            decions = isotones_decions
        elif elements:
            decmatrix = elements_decmatrix
            decions = elements_decions
        elif isotopes:
            decmatrix = isotopes_decmatrix
            decions = isotopes_decions
        elif ionlist is not None:
            # TODO
            raise NotImplementedError('ionlist')
        else:
            decmatrix = self.decmatrix
            decions = self.decions

        # clean up
        self.decions = decions
        self.map = decmatrix
        del self.decmatrix

        self.close_logger(timing = 'matrix constructed in')
Exemple #39
0
    def __init__(self,
                 z = 1,
                 silent = False,
                 check = None,
                 molfrac = False,
                 numfrac = False,
                 massfrac = None,
                 metal = None,
                 href = False,
                 ):
        """
        Generate abundances set using z = Z/Z_sun, the scale relative
        to solar, if z is positive; absolute metallicity Z = -z if z
        is negative.

        molfrac = metallicity by mol fraction

        numfrac = metallicity by number fraction

        massfrac = metallicity by mass fraction [default]

        metal = normalize to given metal, e.g., 'Fe'

        href = use fraction relative to hydrogen, e.g., to compute [Fe/H]

        """
        super().__init__()

        self.setup_logger(silent = silent)

        if check is None:
            check = self._check_default
        if check:
            numiso = len(self.ions)
            # assert self.ions == IonList(SolAbu('Lo09').ions())
            assert self.masses.shape[0] == numiso

        if massfrac is True:
            assert molfrac == numfrac == False
        else:
            massfrac = not (molfrac or numfrac)
        assert np.count_nonzero([massfrac, molfrac, numfrac]) == 1

        if metal is not None:
            ion_ref = ion(metal)
            Z_slice = np.where(ufunc_Z(np.array(self.ions)) == ion_ref.Z)[0]
        else:
            Z_slice = None
        self.Z_slice = Z_slice

        self.numfrac = numfrac
        self.molfrac = molfrac
        self.href = href

        self.solar_abu  = self._abu(1.)
        self.solar_metal  = self._abu_metallicity(self.solar_abu, Z_slice = self.Z_slice)
        if href:
            self.h_sun = self._abu_metallicity(self.solar_abu, Z_slice = self.hydrogen_slice)

        # negative values are interpreted as absolute values of z
        # rather than scale factor
        if z < 0:
            z = -z / self.solar_metal

        x = self._find_x(z)

        abu = self._abu(x, molfrac = False, numfrac = False)

        self.abu = abu
        self.iso = np.array(self.ions)

        self.normalize()
        self.is_sorted = True
        self.sort()

        self.close_logger(timing='Abundance set generated in')
Exemple #40
0
 def ext_ions(self):
     addions = ('nt1', 'h1', 'he4', 'be8')
     ions = set(self.ions) | set(isotope.ion(i) for i in addions)
     return IonList(sorted(list(ions)))
Exemple #41
0
    def __init__(self,
                 z = 1,
                 silent = False,
                 check = None,
                 molfrac = False,
                 numfrac = False,
                 massfrac = None,
                 metal = None,
                 href = False,
                 ):
        """
        Generate abundances set using z = Z/Z_sun, the scale relative
        to solar, if z is positive; absolute metallicity Z = -z if z
        is negative.

        molfrac = metallicity my mol fraction

        numfrac = metallicity my number fraction

        massfrac = metallicity my mass fraction [default]

        metal = normalize to given metal, e.g., 'Fe'

        href = use fraction relative to hydrogen, e.g., to compute [Fe/H]

        """
        super().__init__()

        self.setup_logger(silent = silent)

        if check is None:
            check = self._check_default
        if check:
            numiso = len(self.ions)
            # assert self.ions == IonList(SolAbu('Lo09').ions())
            assert self.masses.shape[0] == numiso

        if massfrac is True:
            assert molfrac == numfrac == False
        else:
            massfrac = not (molfrac or numfrac)
        assert np.count_nonzero([massfrac, molfrac, numfrac]) == 1

        if metal is not None:
            ion_ref = ion(metal)
            Z_slice = np.where(ufunc_Z(np.array(self.ions)) == ion_ref.Z)[0]
        else:
            Z_slice = None
        self.Z_slice = Z_slice

        self.numfrac = numfrac
        self.molfrac = molfrac
        self.href = href

        self.solar_abu  = self._abu(1.)
        self.solar_metal  = self._abu_metallicity(self.solar_abu, Z_slice = self.Z_slice)
        if href:
            self.h_sun = self._abu_metallicity(self.solar_abu, Z_slice = self.hydrogen_slice)

        # negative values are interpreted as absolute values of z
        # rather than scale factor
        if z < 0:
            z = -z / self.solar_metal

        x = self._find_x(z)

        abu = self._abu(x, molfrac = False, numfrac = False)

        self.abu = abu
        self.iso = np.array(self.ions)

        self.normalize()
        self.is_sorted = True
        self.sort()

        self.close_logger(timing='Abundance set generated in')
Exemple #42
0
    def __init__(self,
                 filename = None,
                 amax = 999,
                 zmax = 999,
                 isomers = False,
                 silent = False,
                 debug = True,
                 nuclei = True,
                 ):
        """
        Load decay file.

        format
          c12 [BR] [decay | output]+

        examples

          c9 1 p b8m3
          b8m3 g
          b8m2 b- c8
          c8 EC b8m1
          b8m1 g
          b8 b+ be8
          be8 2a
          he4
          h1


        """

        self.setup_logger(silent)
        self.isomers = isomers

        self.decayfile = os.path.expandvars(os.path.expanduser(filename))


        decdata = {}
        with open(self.decayfile,'rt') as f:
            self.logger.info('Loading {} ({})'
                  .format(f.name,
                          byte2human(os.fstat(f.fileno()).st_size)))
            for s in f:
                if debug:
                    print('\nprocessing: ' + s.strip())
                if s.startswith(';'):
                    continue
                if len(s.strip()) == 0:
                    continue
                reac = s.split()

                ix = ion(reac[0], isomer = isomers)
                if debug:
                    print('ion = ', ix)
                if ix.A > amax and ix.Z > zmax:
                    continue
                if isomers:
                    ix = assert_isomer([ix])[0]
                else:
                    ix = assert_isotope([ix])[0]
                    if ix is None:
                        continue
                if debug:
                    print('ion = ', ix)

                assert ix != Ion.VOID, "Ion name not valid: " + str(ix)
                i = 1
                if len(reac) > i:
                    try:
                        br = np.float64(reac[i])
                        i += 1
                    except ValueError:
                        br = np.float64(1.)
                else:
                    br = np.float64(1.)
                # we shall accept "empty" as stable....
                decays = []
                ions = []
                for r in reac[i:]:
                    try:
                        d = DecIon(r)
                    except:
                        d = VOID
                    if d == VOID:
                        jx = ion(r, isomer = isomers)
                        ions += [jx]
                    else:
                        decays += [d]
                if len(reac) == 1:
                    decays += [DecIon('s')]
                for dec in decays:
                    for p,n in dec.particles().items():
                        if n < 0:
                            p = -p
                            n = -n
                        ions = [p] * n + ions
                for jj,jx in enumerate(ions):
                    if jx.is_nucleus():
                        if isomers:
                            jx = assert_isomer([jx])[0]
                        else:
                            jx = jx.isotope()
                        ions[jj] = jx
                Z,A,E = ix.ZAE()
                for i in ions:
                     Z -= i.Z
                     A -= i.A
                     E -= i.E
                if not (A == 0 and Z == 0):
                    assert Z <= A, 'something is wrong'
                    if isomers:
                        if not (ix.A == A and ix.Z == Z):
                            E = 0
                    else:
                        E = None
                    out = ion(Z=Z, A=A, E=E)
                    if not out == ix:
                        ions += [out]

                # filter for nucleons
                if nuclei:
                    decions = [i for i in ions if i.is_nucleus()]
                else:
                    decions = ions

                decinfo = [br] + decions

                # store info
                if ix not in decdata:
                    decdata[ix] = []
                decdata[ix].append(tuple(decinfo))

        # check BRs and ion lists
        decions = set()
        for ix, products in decdata.items():
            BR = np.sum([x[0] for x in products])
            assert BR == 1, "BR don't add up {!s:}: {}".format(ix, BR)
            for x in products:
                for i in x[1:]:
                    decions |= {i}
        missing = decions - set(decdata)
        if len(missing) != 0:
            s = "missing ions from decdata: {}".format(', '.join([str(i) for i in missing]))
            if debug:
                self.logger.critical(s)
            else:
                self.logger.debug(s)

        self.decdata = decdata
        self.close_logger(timing = 'data loaded in')