<commit_before>"""
Functions for calculating exposure ages.

We generally follow the notation of <NAME> (2010), Cosmogenic Nuclides:
Principles, Concepts and Application in the Earth Surface Sciences, Cambridge
University Press, Cambridge. pp. 187.
"""
from __future__ import division, print_function, unicode_literals

import numpy as np
import scipy.optimize as opt

from cosmogenic import production, sim

def exposure_age(C, P, nuclide, z0=0.0, erosion_rate=None, z=None):
    """
    Parameters:
    ----------
    C:  concentration of cosmogenic nuclide (CN) (atoms / g)
    P:  function
        local production rate at depth in g/cm**2
        units: (atoms / g / yr)
    nuclide: a cosmogenic nuclide object
    z0: modern depth (g / cm**2)
    erosion_rate (optional): assumed constant rate of erosion (g / cm**2 / yr),
                             default is no erosion
    z (optional): Function z(t) that returns depth in cm
    erosion_rate: (optional) Rate of steady erosion to assume (ignored if z is
                  supplied.
    """

    
    # construct z(t) function if one was not supplied
    if z is None:
        if erosion_rate is None:
            z = lambda t: z0
        else:
            def z(t):
                return z0 + erosion_rate * t
    
    def residual(t):
        C_model, _ = sim.nexpose(P, nuclide, z, t)
        return np.abs(C - C_model)
    
    # go out to 7 half lives... this is really pushing it
    # the sample would be saturated at this age
    upper_age_bound = 7 * np.log(2) / nuclide.LAMBDA
    bounds = (0.0, upper_age_bound)

    res = opt.minimize_scalar(residual, bounds=bounds, method='bounded')
    if res.success:
        t = res.x
        return sim.nexpose(P, nuclide, z, t)
    else:
        raise Error("Something went wrong in the inversion")
<commit_msg>return age and concentration<commit_after>"""
Functions for calculating exposure ages.

We generally follow the notation of <NAME> (2010), Cosmogenic Nuclides:
Principles, Concepts and Application in the Earth Surface Sciences, Cambridge
University Press, Cambridge. pp. 187.
"""
from __future__ import division, print_function, unicode_literals

import numpy as np
import scipy.optimize as opt

from cosmogenic import production, sim

def exposure_age(C, P, nuclide, z0=0.0, erosion_rate=None, z=None):
    """
    Parameters:
    ----------
    C:  concentration of cosmogenic nuclide (CN) (atoms / g)
    P:  function
        local production rate at depth in g/cm**2
        units: (atoms / g / yr)
    nuclide: a cosmogenic nuclide object
    z0: modern depth (g / cm**2)
    erosion_rate (optional): assumed constant rate of erosion (g / cm**2 / yr),
                             default is no erosion. Ignored if z is supplied.
    z (optional): Function z(t) that returns depth in cm
    """

    
    # construct z(t) function if one was not supplied
    if z is None:
        if erosion_rate is None:
            z = lambda t: z0
        else:
            def z(t):
                return z0 + erosion_rate * t
    
    def residual(t):
        C_model, _ = sim.nexpose(P, nuclide, z, t)
        return np.abs(C - C_model)
    
    # go out to 7 half lives... this is really pushing it
    # the sample would be saturated at this age
    upper_age_bound = 7 * np.log(2) / nuclide.LAMBDA
    bounds = (0.0, upper_age_bound)

    res = opt.minimize_scalar(residual, bracket=bounds) 
    t = res.x
    return t, sim.nexpose(P, nuclide, z, t)

{'fraction_non_alphanumeric': 0.09237410071942447, 'fraction_numerical': 0.012086330935251799, 'mean_word_length': 2.4178957718780727, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '877608', 'n_tokens_mistral': 1143, 'n_tokens_neox': 1057, 'n_words': 403}