Domain: Physics — Physics (general)

Problem:
In a one-dimensional domain with length of $[0, 0.1\mathrm{m}]$, considering the pure heat conduction. The left boundary has Robin type boundary condition with the convective heat transfer coefficient is $100.0 \mathrm{W/m^2}$, and the environment temperature is $1000\mathrm{K}$. The right boundary has constant temperature of $400\mathrm{K}$. Consider the steady state, what is the mean absolute deviation (in $\mathrm{K}$) of the temperature profile to the linear profile in the domain? Round to 2 decimal places. Assume the thermal conductivity is linear profile of the temperature and the position with $0.1 + \frac{0.2T}{300} + 0.1x \mathrm{W/(m\cdot K)}$.

Answer: $31.08$

Solution code:
import math

def main():
    L = 0.1              
    h = 100.0            
    T_inf = 1000.0       
    TL_val = 400.0       

    a = 0.1
    b = 0.2 / 300.0     
    c = 0.1

    def residual_T0(T0: float) -> float:
        C = -h * (T_inf - T0)
        d = b * C
        y0 = a + b*T0 + c*0.0
        yL = a + b*TL_val + c*L
        u0 = c*y0 + d
        uL = c*yL + d
        return (uL - d * math.log(abs(uL))) - (u0 - d * math.log(abs(u0))) - (c*c*L)

    def bracket_root(f, t_min, t_max, step=10.0):
        t_prev = t_min
        f_prev = f(t_prev)
        t = t_prev + step
        while t <= t_max:
            f_curr = f(t)
            if f_prev == 0:
                return t_prev, t_prev
            if f_prev * f_curr <= 0:
                return t_prev, t
            t_prev, f_prev = t, f_curr
            t += step
        raise RuntimeError("Failed to bracket the root for T0.")

    def bisection(f, a_, b_, tol=1e-12, maxit=300):
        fa, fb = f(a_), f(b_)
        if fa * fb > 0:
            raise RuntimeError("Root not bracketed for bisection.")
        a, b = a_, b_
        for _ in range(maxit):
            m = 0.5*(a+b)
            fm = f(m)
            if abs(fm) < tol or 0.5*(b-a) < tol:
                return m
            if fa * fm <= 0:
                b, fb = m, fm
            else:
                a, fa = m, fm
        return 0.5*(a+b)

    a_br, b_br = bracket_root(residual_T0, 400.0, 1200.0, step=10.0)
    T0 = bisection(residual_T0, a_br, b_br, tol=1e-14, maxit=400)

    def k_func(T, x): 
        return a + b*T + c*x

    def integrate_profile(T0, N=20000):
        dx = L / N
        C = -h * (T_inf - T0)
        x = 0.0
        T = T0
        xs = [x]
        Ts = [T]
        for _ in range(N):
            k1 = C / k_func(T, x)
            Tm1 = T + 0.5*dx*k1
            xm  = x + 0.5*dx
            k2 = C / k_func(Tm1, xm)
            Tm2 = T + 0.5*dx*k2
            k3 = C / k_func(Tm2, xm)
            Tend = T + dx*k3
            xe = x + dx
            k4 = C / k_func(Tend, xe)
            T += (dx/6.0)*(k1 + 2*k2 + 2*k3 + k4)
            x = xe
            xs.append(x)
            Ts.append(T)
        return xs, Ts

    xs, Ts = integrate_profile(T0, N=20000)

    def compute_mad(xs, Ts, T0, TL):
        total = 0.0
        for i in range(len(xs)-1):
            x_i, x_j = xs[i], xs[i+1]
            Ti, Tj = Ts[i], Ts[i+1]
            Tli = T0 + (TL - T0) * (x_i / L)
            Tlj = T0 + (TL - T0) * (x_j / L)
            ei = abs(Ti - Tli)
            ej = abs(Tj - Tlj)
            total += 0.5 * (ei + ej) * (x_j - x_i)
        return total / L

    MAD = compute_mad(xs, Ts, T0, TL_val)

    print(f"Mean absolute deviation (MAD) = {MAD:.2f} K")

if __name__ == "__main__":
    main()