예제 #1
0
def move_thermal_boundary(r, T, Tcen, n_points):

    #Calculate movement of boundary by matching the gradients
    #s_new = move_bound2(Tcen,lb)

    #######################
    #Match temperature

    #    if T[-1]-adiabat(r[-1],Tcen) < 0:
    #        s_new = r[-1]
    #        r_new = np.ones(n_points)*r[-1]
    #        T_new = np.ones(n_points)*adiabat(r[-1],Tcen)
    #    else:
    #        def f(guess,T,Tcen):
    #            return T-adiabat(guess,Tcen)
    #
    #        s_new = bisect(f,0,3480e3,args=(T[0],Tcen),maxiter=200)
    #######################

    #Match gradient
    #####################
    dT_dr = np.gradient(T, r[1] - r[0], edge_order=2)
    dT_dr_func = interp1d(r, dT_dr, kind='linear')

    s_new = move_bound2(Tcen, dT_dr[0])
    if 1 == 1:
        #####################

        T_rel = T - adiabat(r, Tcen)

        if s_new < r[0]:  #Add grid points below layer

            #Append solution
            r, T_rel = expand_domain(r, s_new, T_rel)

        else:  #Find point that is also sub-adiabatic

            grad_diff = np.gradient(T, r[1] - r[0],
                                    edge_order=2) - adiabat_grad(r, Tcen)

            grad_diff_func = interp1d(r, grad_diff, kind='linear')

            #If super-adiabatic everywhere
            if len(grad_diff[grad_diff > 0]) == 0:
                s_new = r[-1]

            #If super-adiabatic at the base of the lauer but still sub-adiabatic at the top, reduce to just sub-adiabatic region
            elif grad_diff[0] < 0 and grad_diff[-1] > 0:

                s_new = bisect(grad_diff_func, r[0], r[-1], maxiter=200)

        #Interpolate onto regular grid
        r_new = np.linspace(s_new, r[-1], n_points)
        T_rel = interp1d(r, T_rel, kind='linear')(r_new)

        T_new = T_rel + adiabat(r_new, Tcen)

    return r_new, T_new
예제 #2
0
def layer_growth(r, c, T, Tcen, dTa_dt, dc_int, dc_dr, dc_sl):

    if prm.compositional_stratification:

        s_new_c = r[0] + (dc_int - dc_sl) / dc_dr

    else:
        s_new_c = r[-1]

    if prm.thermal_stratification:

        ######## Match Gradients  #######

        T_rel = T - adiabat(r, Tcen)

        s_new_T = move_bound2(Tcen, r, T)

    else:
        T_rel = T - adiabat(r, Tcen)
        s_new_T = r[-1]

    s_new = np.min([s_new_c, s_new_T])

    if s_new < r[0]:  #Interface moves down

        #Append solution
        r, T_rel = append_thermal_solution(r, s_new, T_rel)
        T = T_rel + adiabat(r, Tcen)

        r, c = append_compositional_solution(r, s_new, c, dc_dr)

        #Interpolate solution onto regular grid
        r_new = np.linspace(s_new, prm_c.r_cmb, prm.n_points)
        T_new = interp1d(r, T, kind='linear')(r_new)
        c_new = interp1d(r, c, kind='linear')(r_new)

    else:  #Interface moves down

        #Interpolate solution onto regular grid
        r_new = np.linspace(s_new, prm_c.r_cmb, prm.n_points)
        T_new = interp1d(r, T, kind='linear')(r_new)
        c_new = interp1d(r, c, kind='linear')(r_new)

    return r_new, T_new, c_new
예제 #3
0
def secular_cool(r, rho, Ta, M):
    #Values are normalised to the cooling rate.
    Tcen = Ta[0]
    Is = 4 * np.pi * integrate(r, rho * Ta * r**2)
    Qs = -prm.cp * Is / Tcen

    Ts = adiabat(r[-1], Tcen)
    Es = prm.cp * (M - Is / Ts) / Tcen

    return Qs, Es
예제 #4
0
def evolve_thermal_layer(r, T, Tcen, dT_dr_cmb, dt):

    ub = dT_dr_cmb  #upper boundary condition (fixed gradient)
    lb = adiabat(r[0], Tcen)  #lower boundary condition (fixed gradient)

    ub_type = 1  #upper boundary condition type (0=Fixed value  1=Fixed gradient)
    lb_type = 0  #upper boundary condition type (0=Fixed value  1=Fixed gradient)

    #Diffuse the solution and cool adiabat
    T_new = diffusion(T, r, dt, prm_c.kappa, lb_type, ub_type, lb, ub)

    return T_new
예제 #5
0
def ic_growth(r, Tcen, Tm):

    if adiabat(r[0], Tcen) > Tm[0]:
        ri = 0
    elif adiabat(r[-1], Tcen) > Tm[-1]:

        dT = adiabat(r, Tcen) - Tm

        x1 = np.arange(dT.size)[dT > 0][0] - 1
        x2 = np.arange(dT.size)[dT > 0][0]

        dx = dT[x1] / (dT[x1] - dT[x2])

        ri = r[x1] + dx * (r[x2] - r[x1])

#        f_Tm =  interpolate.interp1d(r,Tm)
#        def f(r,Tcen,f_Tm):
#            return adiabat(r,Tcen)-f_Tm(r)
#
#        ri = bisect(f,r[0],r[-1],args=(Tcen,f_Tm))
    else:
        assert adiabat(r[-1], Tcen) >= Tm[-1], 'The whole core has frozen!'

    return ri
예제 #6
0
def expand_layer(ds, sl_model, Tcen):

    T = sl_model.T
    r = sl_model.r
    s_new = r[0] + ds

    Ta = adiabat(s_new, Tcen)

    r_insert = np.linspace(s_new, r[0], 10)
    T_insert = np.linspace(T[0], Ta, 10)

    n = np.ceil(1 + len(r) * ds / (r[-1] - r[0]))

    T = np.insert(T, 0, T_insert)
    r = np.insert(r, 0, r_insert)

    r_new = np.linspace(r[0], r[-1], n)
    T_new = np.interp(r_new, r, T)

    sl_model.r = r_new
    sl_model.T = T_new

    return sl_model
예제 #7
0
def initialise_layer(s, Tcen):

    r = np.linspace(s, prm.r_upper, prm.n_points)
    T = adiabat(r, Tcen)

    return r, T
예제 #8
0
def mantle_evolution(model, core_model=False):

    #Read in variables from model and parameters file
    time = model.time

    Tm = model.Tm  #average mantle temperature

    r_upper = model.r_upper  #upper radius
    r_lower = model.r_lower  #lower radius

    nu_upper = model.nu_upper  #viscosity in upper mantle
    nu_lower = model.nu_lower  #viscosity in lower mantle

    k_upper = model.k_upper  #thermal conductivity in upper mantle
    k_lower = model.k_lower  #thermal conductivity in lower mantle

    Tsurf = model.Tsurf  #Surface temperature
    Qr0 = model.Qr0  #Initial radiogenic heating
    Trad = model.Trad  #radiogenic heating decay
    mass = model.mass  #mantle mass
    alpha = model.alpha  #volumetric expansion
    g = model.g  #gravity
    kappa = model.kappa  #thermal diffusivity
    cp = model.cp  #specific heat capacity
    Rac = model.Rac  #critical Rayleigh Number

    if core_model:
        from thermal_history.core.profiles import adiabat
        Tcen = core_model.Tcen
        Tcmb = adiabat(r_lower, Tcen)
    else:
        Tcmb = model.Tcmb_func(model)

    #Calculate boundary layers
    Ta_upper = Tm * 0.7
    Ta_lower = Tm * 1.3

    D = r_upper - r_lower  #Mantle Thickness

    delta_upper = D * ((kappa * nu_upper * Rac) /
                       ((D**3) * alpha * g * (Ta_upper - Tsurf)))**(1 / 3)

    delta_lower = D * ((kappa * nu_lower * Rac) / ((D**3) * alpha * g *
                                                   (Tcmb - Ta_lower)))**(1 / 3)

    #Conductive heat flow through boundaries

    Qsurface = 4 * np.pi * r_upper**2 * k_upper * (
        (Ta_upper - Tsurf) / delta_upper)

    Qcmb = 4 * np.pi * r_lower**2 * k_lower * ((
        (Tcmb - Ta_lower)) / delta_lower)

    #heat produced via radiogenic production
    Qr = Qr0 * np.exp(-time / Trad)

    #Calculating energy from mantle secular cooling
    Qs = Qsurface - Qcmb - Qr

    #Mantle cooling rate
    dTm_dt = -Qs / (mass * cp)

    #Save values to model class
    model.delta_upper = delta_upper
    model.delta_lower = delta_lower

    model.Qr = Qr
    model.Qs = Qs
    model.Qcmb = Qcmb
    model.Qsurface = Qsurface

    model.dT_dt = dTm_dt
    model.Tcmb = Tcmb

    return model
예제 #9
0
 def f(guess, T, Tcen):
     return T - adiabat(guess, Tcen)
예제 #10
0
def sl_evolution(model,
                 dt=1e6,
                 core_model=False,
                 mantle_model=False,
                 debugging=False):

    from thermal_history.core.profiles import conductivity, density, adiabat, adiabat_grad
    from thermal_history.core.numerical import integrate
    from thermal_history.stable_layer.functions import evolve_thermal_layer, append_layer, diffusion, initialise_layer

    from scipy.optimize import bisect
    from scipy.interpolate import interp1d
    from scipy.special import erfcinv

    #Read in values from model
    time = model.time
    it = model.it
    ys = model.ys
    model.dt = dt * ys
    t_tot = model.dt

    r_cmb = model.r_upper
    k_cmb = conductivity(r_cmb)

    diffusivity_c = model.D_c[0]
    diffusivity_T = model.kappa
    alpha_T = model.alpha_T
    alpha_c = model.alpha_c[0]
    n_points = model.n_points
    tolerance = model.depth_tolerance

    if mantle_model:
        Qcmb = mantle_model.Qcmb
    else:
        Qcmb = model.Qcmb_func(time)

    if core_model:
        Tcen, dTa_dt = core_model.Tcen, core_model.dT_dt
    else:
        Tcen, dTa_dt = model.Ta_func(model)

    #Initialse values on iteration 0:
    if it == 0:

        model.r = np.ones(n_points) * r_cmb
        model.T = adiabat(model.r, Tcen)

    #for testing purposes
    #Qcmb = 0.99 * -adiabat_grad(r_cmb,Tcen)*k_cmb*4*np.pi*r_cmb**2

    #Calculate one of 2 cases, thermal/chemical:

    if model.thermal_stratification:

        time_gone = 0

        test = 0

        while time_gone < t_tot:
            test = test + 1

            T = model.T
            r = model.r

            s = r[0]

            #TESTING
            #            if time < 3.5e9*ys:
            #                Qcmb = 1.00001-(k_cmb*4*np.pi*r_cmb**2)*adiabat_grad(r_cmb,Tcen)
            #            else:
            #                Qcmb = 0.999*-(k_cmb*4*np.pi*r_cmb**2)*adiabat_grad(r_cmb,Tcen)

            #Calculate CMB temp gradient
            dT_dr_cmb = -Qcmb / (k_cmb * 4 * np.pi * r_cmb**2)

            adiabaticity = float(dT_dr_cmb / adiabat_grad(r_cmb, Tcen))

            if adiabaticity >= 1 and s > tolerance:

                r_new = np.ones(n_points) * r_cmb
                T_new = adiabat(r_new, Tcen)

                s_new = r_new[0]
                ds_dt = (s_new - s) / t_tot

                time_gone = t_tot

            else:

                if s > tolerance:
                    r, T = initialise_layer(tolerance, Tcen)
                    s = r[0]

                #Variable dt
                dt = (1 / diffusivity_T) * ((r_cmb - s) /
                                            (2 * erfcinv(1e-10)))**2

                if time_gone + dt > t_tot:
                    dt = t_tot - time_gone
                elif dt < 1000 * ys:
                    dt = 1000 * ys

                lb = adiabat_grad(r[0], Tcen)
                ub = dT_dr_cmb

                #Diffuse the solution and cool adiabat

                #                if model.it == 881:
                #                    print(test)

                T_new = diffusion(T,
                                  r,
                                  dt,
                                  diffusivity_T,
                                  1,
                                  1,
                                  lb,
                                  ub,
                                  coord='sph')
                Tcen = Tcen + dTa_dt * dt

                assert T_new[0] < adiabat(0, Tcen), "Entire core is stratified"

                if T_new[0] < adiabat(r_cmb, Tcen):

                    r_new = np.ones(n_points) * r_cmb
                    T_new = adiabat(r_new, Tcen)

                    s_new = r_new[0]
                    ds_dt = (s_new - s) / dt

                else:

                    #Calculate movement of boundary
                    def f(guess, T, Tcen):
                        return T - adiabat(guess, Tcen)

                    try:
                        s_new = bisect(f,
                                       0,
                                       3480e3,
                                       args=(T_new[0], Tcen),
                                       maxiter=200)
                    except:
                        pdb.set_trace()

                    ds_dt = (s_new - s) / dt
                    if dt == 0:
                        pdb.set_trace()

                    T_rel = T_new - adiabat(r, Tcen)
                    #Append solution
                    r, T_rel = append_layer(r, s_new, T_rel)
                    T = T_rel + adiabat(r, Tcen)

                    #Interpolate solution
                    r_new = np.linspace(s_new, r_cmb, n_points)
                    T_new = interp1d(r, T, kind='linear')(r_new)

                    time_gone += dt

                    model.r = r_new
                    model.T = T_new

        #pdb.set_trace()

#
#
#            #Check if layer is thin and superadiabatic (destroy layer):
#            if r_s >= tolerance and adiabaticity >= adiabaticity_limit:
#
#
#                r_new = np.ones(n_points)*r_cmb
#                T_new = np.ones(n_points)*adiabat(r_cmb,Tcen)
#                Qs = 0
#                ds_dt = 0
#
#
#            #layer is thin and sub-adiabatic (initialise values):
#            elif r_s > tolerance and adiabaticity < adiabaticity_limit:
#
#                r_new = np.linspace(tolerance,r_cmb,n_points)
#                T_new = adiabat(r_new,Tcen)
#                Qs = 0
#                ds_dt = 0
#
#            #layer is thick and can be evolved
#            else:
#
#                #Decide on time step
#                dt = 100*model.ys*(model.s_layer.layer_thickness/30)
#
#
#                r = model.s_layer.r
#                T = model.s_layer.T
#
#                T_new = evolve_thermal_layer(r, T, Tcen, dT_dr_cmb, dt)
#
#                dT_dt = (T_new-T)/dt
#                rho = density(r,o_rho)
#
#                Qs = 4*np.pi*integrate(r,dT_dt*rho*cp*r**2)
#
#                Tcen = Tcen + dTa_dt*dt
#
#                r_new, T_new = move_thermal_boundary(r,T_new,Tcen,n_points)
#
#                ds_dt = (r_new[0]-r[0])/dt
#
#                if r_new[0] > tolerance:
#                    model.adiabaticity_limit = adiabaticity
#
#
#            #Save those unique to thermal stratification
#            model.s_layer.Qs = Qs
#            model.s_layer.T = T_new

    if model.compositional_stratification:

        if it == 0:
            r = np.linspace(tolerance, r_cmb, n_points)
            c = np.ones(r.size) * conc_l
        else:
            r = model.r
            c = model.c

        #Barodiffusion
#            dmu_dc = prm_sl.dmu_dc
#            dg_dr = 10/3480e3
#            g = 10
#            a = diffusivity_c*alpha_c/dmu_dc  #Gubbins/Davies table 1
#
#            #baro_cst = -( 2*g*a/r +a*dg_dr
#ub = alpha_c*g/dmu_dc
        baro_cst = 0

        ###################
        #Chemical Diffusion
        dT_dr = Qcmb / -(k_cmb * 4 * np.pi * r_s**2)

        super_adiabatic_grad = dT_dr - adiabat_grad(r_s, Tcen)
        #super_adiabatic_grad = -1/1000

        bc_lower = 1  #lower boundary condition type
        bc_upper = 0  #upper boundary condition type

        ub = model.ub_func(model)  #upper boundary condition
        lb = -(alpha_T /
               alpha_c) * super_adiabatic_grad  #lower boundary condition

        if lb < 0:
            print('Can\'t have this boundary condition!!')
            pdb.set_trace()

        c_new = diffusion(c,
                          r,
                          dt,
                          diffusivity_c,
                          bc_lower,
                          bc_upper,
                          lb,
                          ub,
                          cst=baro_cst,
                          coord='sph')

        dc_dt_sl = (c_new[0] - c[0]) / dt

        #Calculate movement of boundary
        ds_dt = (dc_dt - dc_dt_sl) / lb

        ds = ds_dt * dt
        s_new = r_s + ds

        if ds < 0:
            #Append solution
            r_append = np.linspace(s_new, r[0], 10)[:-1]
            c_append = np.ones(9) * conc_l

            r_appended = np.append(r_append, r)
            c_appended = np.append(c_append, c_new)

            r_new = np.linspace(s_new, r[-1], n_points)
            c_new = np.interp(r_new, r_appended, c_appended)

        else:

            r_new = np.linspace(s_new, r[-1], n_points)
            c_new = np.interp(r_new, r, c_new)

        #Save those unique to compositional stratification
        model.c = c_new

    if debugging:
        return dict([[key, value] for key, value in locals().items()
                     if type(value) in (int, float, str,
                                        np.ndarray) and not key.startswith('_')
                     ])

    else:

        #        pdb.set_trace()
        #Save to model
        model.Tcen = Tcen
        model.dTa_dt = dTa_dt
        model.Qcmb = Qcmb
        model.r_lower = s_new
        model.ds_dt = ds_dt
        model.r = r_new
        model.T = T_new

        model.adiabaticity = adiabaticity

        return model