def age_equation(j, f, include_decay_error=False, lambda_k=None, arar_constants=None): if isinstance(j, tuple): j = ufloat(*j) elif isinstance(j, str): j = ufloat(j) if isinstance(f, tuple): f = ufloat(*f) elif isinstance(f, str): f = ufloat(f) if not lambda_k: if arar_constants is None: arar_constants = ArArConstants() lambda_k = arar_constants.lambda_k if arar_constants is None: arar_constants = ArArConstants() if not include_decay_error: lambda_k = nominal_value(lambda_k) try: # lambda is defined in years, so age is in years age = lambda_k**-1 * umath.log(1 + j * f) return arar_constants.scale_age(age, current='a') except (ValueError, TypeError): return ufloat(0, 0)
def age_equation(j, f, include_decay_error=False, lambda_k=None, scalar=None, arar_constants=None): if isinstance(j, tuple): j = ufloat(*j) elif isinstance(j, str): j = ufloat(j) if isinstance(f, tuple): f = ufloat(*f) elif isinstance(f, str): f = ufloat(f) if not lambda_k: if arar_constants is None: arar_constants = ArArConstants() lambda_k = arar_constants.lambda_k if not scalar: if arar_constants is None: arar_constants = ArArConstants() scalar = float(arar_constants.age_scalar) if not include_decay_error: lambda_k = nominal_value(lambda_k) try: return (lambda_k**-1 * umath.log(1 + j * f)) / scalar except (ValueError, TypeError): return ufloat(0, 0)
def interference_corrections(a39, a37, production_ratios, arar_constants=None, fixed_k3739=False): if production_ratios is None: production_ratios = {} if arar_constants is None: arar_constants = ArArConstants() pr = production_ratios if arar_constants.k3739_mode.lower() == 'normal' and not fixed_k3739: ca3937 = pr.get('Ca3937', 0) k3739 = pr.get('K3739', 0) k39 = (a39 - ca3937 * a37) / (1 - k3739 * ca3937) k37 = pr.get('K3739', 0) * k39 ca37 = a37 - k37 ca39 = pr.get('Ca3937', 0) * ca37 else: if not fixed_k3739: fixed_k3739 = arar_constants.fixed_k3739 ca37, ca39, k37, k39 = apply_fixed_k3739(a39, pr, fixed_k3739) k38 = pr.get('K3839', 0) * k39 if not arar_constants.allow_negative_ca_correction: ca37 = max(ufloat(0, 0), ca37) ca36 = pr.get('Ca3637', 0) * ca37 ca38 = pr.get('Ca3837', 0) * ca37 return k37, k38, k39, ca36, ca37, ca38, ca39
def calculate(self, age, sensitivity, k2o): c = ArArConstants() xs = np.linspace(self.start, self.end) ys = np.array([self._calculate(wi, age, sensitivity, k2o, c) for wi in xs]) # nxs = np.linspace(max(1e-2, 0), self.end) # n40 = np.linspace(max(1, ys[0]), ys[-1]) n40 = ys[:] if ys[0] == 0: n40 = n40[1:] # r4039 = 7.78 n39 = n40 / self.r4039 # nys = ys[:] # print nys # nys = np.hstack(([1], nys[1:])) # print nys p = (0.0021435788651550671, -0.48505328994128016) e40_scalar = 3 e39 = powerlaw(p, n39) e40 = powerlaw(p, n40) * e40_scalar es = (e39 ** 2 + e40 ** 2) ** 0.5 # es = age * 1e3 * es # es = 0.2 * nys ** (-0.5) return xs, ys, n40, es * 100
def calculate_atmospheric(a38, a36, k38, ca38, ca36, decay_time, production_ratios=None, arar_constants=None): """ McDougall and Harrison Roddick 1983 Foland 1993 iteratively calculate atm36 """ if production_ratios is None: production_ratios = {} if arar_constants is None: arar_constants = ArArConstants() pr = production_ratios m = pr.get('cl3638', 0) * arar_constants.lambda_Cl36.nominal_value * decay_time atm36 = ufloat(0, 1e-20) for _ in range(5): ar38atm = arar_constants.atm3836.nominal_value * atm36 cl38 = a38 - ar38atm - k38 - ca38 cl36 = cl38 * m atm36 = a36 - ca36 - cl36 return atm36, cl36
def calculate(self, age, sensitivity, k2o): c = ArArConstants() xs = np.linspace(self.start, self.end) def to_weight(d, depth, rho): ''' d== mm depth==mm rho==kg/m^3 ''' # convert dimension to meters d = d / 1000. depth = depth / 1000. if self.shape == 'circle': v = math.pi * (d / 2.) ** 2 * depth else: v = d ** 2 * depth m = rho * v # convert mass to mg 1e6 mg in 1 kg return m * 1e6 # convert dim to weight ws = [to_weight(di, self.depth, self.rho) for di in xs] ys = [self._calculate(wi, age, sensitivity, k2o, c) for wi in ws] return xs, ys, xs, ws
def calculate_f(isotopes, decay_time, interferences=None, arar_constants=None, fixed_k3739=False): """ isotope values corrected for blank, baseline, (background) ic_factor, (discrimination), ar37 and ar39 decay """ a40, a39, a38, a37, a36 = isotopes def calc_f(pr): k37, k38, k39, ca36, ca37, ca38, ca39 = interference_corrections(a39, a37, pr, arar_constants, fixed_k3739) atm36, cl36, cl38 = calculate_atmospheric(a38, a36, k38, ca38, ca36, decay_time, pr, arar_constants) # calculate radiogenic trapped_4036 = copy(arar_constants.atm4036) trapped_4036.tag = 'trapped_4036' atm40 = atm36 * trapped_4036 k4039 = pr.get('K4039', 0) k40 = k39 * k4039 rad40 = a40 - atm40 - k40 try: ff = rad40 / k39 except ZeroDivisionError: ff = ufloat(1.0, 0) nar = {'k40': k40, 'ca39': ca39, 'k38': k38, 'ca38': ca38, 'cl38': cl38, 'k37': k37, 'ca37': ca37, 'ca36': ca36, 'cl36': cl36} try: rp = rad40 / a40 * 100 except ZeroDivisionError: rp = ufloat(0, 0) comp = {'rad40': rad40, 'a40': a40, 'radiogenic_yield': rp, 'ca37': ca37, 'ca39': ca39, 'ca36': ca36, 'k39': k39, 'atm40': atm40} ifc = {'Ar40': a40 - k40, 'Ar39': k39, 'Ar38': a38, 'Ar37': a37, 'Ar36': atm36} return ff, nar, comp, ifc if interferences is None: interferences = {} if arar_constants is None: arar_constants = ArArConstants() # make local copy of interferences pr = {k: ufloat(nominal_value(v), std_dev=0, tag=v.tag) for k, v in interferences.items()} f_wo_irrad, _, _, _ = calc_f(pr) f, non_ar_isotopes, computed, interference_corrected = calc_f(interferences) return f, f_wo_irrad, non_ar_isotopes, computed, interference_corrected
def __init__(self, *args, **kw): super(ArArAge, self).__init__(*args, **kw) self.arar_constants = ArArConstants() self.isotopes = {} self.non_ar_isotopes = {} self.computed = {} self.corrected_intensities = {} self.interference_corrections = {} self.production_ratios = {} self.temporary_ic_factors = {} self.discrimination = ufloat(1, 0)
def calculate_error_t(F, ssF, j, ssJ): ''' McDougall and Harrison p92 eq. 3.43 ''' JJ = j * j FF = F * F constants = ArArConstants() ll = constants().lambdak.nominal_value**2 sst = (JJ * ssF + FF * ssJ) / (ll * (1 + F * j)**2) return sst**0.5
def calculate_atmospheric(a38, a36, k38, ca38, ca36, decay_time, production_ratios=None, arar_constants=None): """ McDougall and Harrison Roddick 1983 Foland 1993 calculate atm36, cl36, cl38 # starting with the following equations atm36 = a36 - ca36 - cl36 m = cl3638*lambda_cl36*decay_time cl36 = cl38 * m cl38 = a38 - k38 - ca38 - ar38atm ar38atm = atm3836 * atm36 # rearranging to solve for atm36 cl38 = a38 - k38 - c38 - atm3836 * atm36 cl36 = m * (a38 - k38 - ca38 - atm3836 * atm36) = m (a38 - k38 - ca38) - m * atm3836 * atm36 atm36 = a36 - ca36 - m (a38 - k38 - ca38) + m * atm3836 * atm36 atm36 - m * atm3836 * atm36 = a36 - ca36 - m (a38 - k38 - ca38) atm36 * (1 - m*atm3836) = a36 - ca36 - m (a38 - k38 - ca38) atm36 = (a36 - ca36 - m (a38 - k38 - c38))/(1 - m*atm3836) """ if production_ratios is None: production_ratios = {} if arar_constants is None: arar_constants = ArArConstants() pr = production_ratios m = pr.get('Cl3638', 0) * nominal_value( arar_constants.lambda_Cl36) * decay_time atm3836 = nominal_value(arar_constants.atm3836) atm36 = (a36 - ca36 - m * (a38 - k38 - ca38)) / (1 - m * atm3836) ar38atm = atm3836 * atm36 cl38 = a38 - ar38atm - k38 - ca38 cl36 = cl38 * m return atm36, cl36, cl38
def interference_corrections(a40, a39, a38, a37, a36, production_ratios, arar_constants=None): if production_ratios is None: production_ratios = {} if arar_constants is None: arar_constants = ArArConstants() pr = production_ratios k37 = ufloat(0, 1e-20) if arar_constants.k3739_mode.lower() == 'normal': # iteratively calculate 37, 39 for _ in range(5): ca37 = a37 - k37 ca39 = pr.get('ca3937', 0) * ca37 k39 = a39 - ca39 k37 = pr.get('k3739', 0) * k39 else: ''' x=ca37/k39 y=ca37/ca39 T=s39dec_cor T=ca39+k39 T=ca37/y+ca37/x ca37=(T*x*y)/(x+y) ''' x = arar_constants.fixed_k3739 y = 1 / pr.get('ca3937', 1) ca37 = (a39 * x * y) / (x + y) ca39 = pr.get('ca3937', 0) * ca37 k39 = a39 - ca39 k37 = x * k39 k38 = pr.get('k3839', 0) * k39 ca36 = pr.get('ca3637', 0) * ca37 ca38 = pr.get('ca3837', 0) * ca37 return k37, k38, k39, ca36, ca37, ca38, ca39
def age_equation(j, f, include_decay_error=False, arar_constants=None): if isinstance(j, (tuple, str)): j = ufloat(j) if isinstance(f, (tuple, str)): f = ufloat(f) if arar_constants is None: arar_constants = ArArConstants() scalar = float(arar_constants.age_scalar) lk = arar_constants.lambda_k if not include_decay_error: lk = lk.nominal_value try: return (lk**-1 * umath.log(1 + j * f)) / scalar except (ValueError, TypeError): return ufloat(0, 0)
def interference_corrections(a40, a39, a38, a37, a36, production_ratios, arar_constants=None, fixed_k3739=False): if production_ratios is None: production_ratios = {} if arar_constants is None: arar_constants = ArArConstants() pr = production_ratios k37 = ufloat(0, 1e-20) if arar_constants.k3739_mode.lower() == 'normal' and not fixed_k3739: # iteratively calculate 37, 39 for _ in range(5): ca37 = a37 - k37 ca39 = pr.get('Ca3937', 0) * ca37 k39 = a39 - ca39 k37 = pr.get('K3739', 0) * k39 else: if not fixed_k3739: fixed_k3739 = arar_constants.fixed_k3739 ca37, ca39, k37, k39 = apply_fixed_k3739(a39, pr, fixed_k3739) k38 = pr.get('K3839', 0) * k39 if not arar_constants.allow_negative_ca_correction: ca37 = max(ufloat(0, 0), ca37) ca36 = pr.get('Ca3637', 0) * ca37 ca38 = pr.get('Ca3837', 0) * ca37 return k37, k38, k39, ca36, ca37, ca38, ca39
def calculate_flux(f, age, arar_constants=None): """ #rad40: radiogenic 40Ar #k39: 39Ar from potassium f: F value rad40Ar/39Ar age: age of monitor in years solve age equation for J """ if isinstance(f, (list, tuple)): f = ufloat(*f) if isinstance(age, (list, tuple)): age = ufloat(*age) try: if arar_constants is None: arar_constants = ArArConstants() j = (umath.exp(age * arar_constants.lambda_k.nominal_value) - 1) / f return j.nominal_value, j.std_dev except ZeroDivisionError: return 1, 0
def calculate_flux(rad40, k39, age, arar_constants=None): ''' rad40: radiogenic 40Ar k39: 39Ar from potassium age: age of monitor in years solve age equation for J ''' if isinstance(rad40, (list, tuple)): rad40 = ufloat(*rad40) if isinstance(k39, (list, tuple)): k39 = ufloat(*k39) if isinstance(age, (list, tuple)): age = ufloat(*age) # age = (1 / constants.lambdak) * umath.log(1 + JR) try: r = rad40 / k39 if arar_constants is None: arar_constants = ArArConstants() j = (umath.exp(age * arar_constants.lambda_k) - 1) / r return j.nominal_value, j.std_dev except ZeroDivisionError: return 1, 0
def calculate_F(isotopes, decay_time, interferences=None, arar_constants=None): """ isotope values corrected for blank, baseline, (background) ic_factor, (discrimination), ar37 and ar39 decay """ a40, a39, a38, a37, a36 = isotopes #a37*=113 if interferences is None: interferences = {} if arar_constants is None: arar_constants = ArArConstants() #make local copy of interferences pr = dict(((k, v.__copy__()) for k, v in interferences.iteritems())) #for k,v in pr.iteritems(): # print k, v k37, k38, k39, ca36, ca37, ca38, ca39 = interference_corrections( a40, a39, a38, a37, a36, pr, arar_constants) atm36, cl36 = calculate_atmospheric(a38, a36, k38, ca38, ca36, decay_time, pr, arar_constants) # calculate rodiogenic # dont include error in 40/36 atm40 = atm36 * arar_constants.atm4036.nominal_value k40 = k39 * pr.get('k4039', 1) rad40 = a40 - atm40 - k40 try: f = rad40 / k39 except ZeroDivisionError: f = ufloat(1.0, 0) rf = deepcopy(f) # f = ufloat(f.nominal_value, f.std_dev, tag='F') non_ar_isotopes = dict(k38=k38, k37=k37, ca36=ca36, ca37=ca37, ca38=ca38, ca39=ca39, cl36=cl36) try: rp = rad40 / a40 * 100 except ZeroDivisionError: rp = ufloat(0, 0) computed = dict(rad40=rad40, rad40_percent=rp, k39=k39) #print 'Ar40', a40-k40, a40, k40 #print 'Ar39', a39-k39, a39, k39 interference_corrected = dict(Ar40=a40 - k40, Ar39=k39, Ar38=a38 - k38 - ca38, Ar37=a37 - ca37 - k37, Ar36=a36) ##clear errors in irrad for pp in pr.itervalues(): pp.std_dev = 0 f_wo_irrad = f return rf, f_wo_irrad, non_ar_isotopes, computed, interference_corrected
def calculate_F(isotopes, decay_time, interferences=None, arar_constants=None, fixed_k3739=False): """ isotope values corrected for blank, baseline, (background) ic_factor, (discrimination), ar37 and ar39 decay """ a40, a39, a38, a37, a36 = isotopes if interferences is None: interferences = {} if arar_constants is None: arar_constants = ArArConstants() # make local copy of interferences pr = {k: v.__copy__() for k, v in interferences.iteritems()} k37, k38, k39, ca36, ca37, ca38, ca39 = interference_corrections( a40, a39, a38, a37, a36, pr, arar_constants, fixed_k3739) atm36, cl36, cl38 = calculate_atmospheric(a38, a36, k38, ca38, ca36, decay_time, pr, arar_constants) # calculate radiogenic # dont include error in 40/36 atm40 = atm36 * nominal_value(arar_constants.atm4036) k4039 = pr.get('K4039', 0) k40 = k39 * k4039 rad40 = a40 - atm40 - k40 try: f = rad40 / k39 except ZeroDivisionError: f = ufloat(1.0, 0) rf = deepcopy(f) non_ar_isotopes = dict(k40=k40, ca39=ca39, k38=k38, ca38=ca38, cl38=cl38, k37=k37, ca37=ca37, ca36=ca36, cl36=cl36) try: rp = rad40 / a40 * 100 except ZeroDivisionError: rp = ufloat(0, 0) computed = dict(rad40=rad40, rad40_percent=rp, k39=k39, atm40=atm40) interference_corrected = dict(Ar40=a40 - k40, Ar39=k39, Ar38=a38, Ar37=a37, Ar36=atm36) # clear errors in irrad for pp in pr.itervalues(): pp.std_dev = 0 f_wo_irrad = f return rf, f_wo_irrad, non_ar_isotopes, computed, interference_corrected
# fractional error from ar39 err39 = fe39 * Re * feJR errJ = Je * feJR errLambdaK = feLambdaK # print 'exception', err40, err36, err39, errJ # print 'exception', err36 + err40 + err39 + errJ # print 'exception', err36 + err37 + err38 + err40 + err39 + errJ + errLambdaK - 1 assert abs(err36 + err37 + err38 + err40 + err39 + errJ + errLambdaK - 1) < 1e-10 return err40, err39, err38, err37, err36, errJ, errLambdaK if __name__ == '__main__': constants = ArArConstants() s40 = ufloat(5.50986, 5.50986 * 0.0004) s39 = ufloat(3.65491e-1, 3.65491e-1 * 0.0011) s38 = ufloat(4.4904e-3, 4.4904e-3 * 0.0117) s37 = ufloat(2.47163e-3, 2.47163e-3 * 0.038) # s38 = ufloat((4.4904e-3, 0)) # s37 = ufloat((2.47163e-3, 0)) s36 = ufloat(2.623e-5, 2.623e-5 * 0.5955) J = ufloat(1, 0) k4039 = 0 ca3637 = 2.8e-4 cl3638 = 0 cl38 = s38 ar39 = s39
def __init__(self, make_arar_constants=True, *args, **kw): super(IdeogramPlotable, self).__init__(*args, **kw) if make_arar_constants: self.arar_constants = ArArConstants()