Astrophysical Isochrone Shifting and Interpolation

This Python script is designed for astrophysical analysis, specifically for adjusting isochrones based on distance and extinction, loading stellar population models with varying characteristics (such as population type, helium content, and alpha enrichment) from pickle files, and interpolating these models by magnitude or age. It uses libraries such as numpy for numerical operations, scipy for interpolation, and tqdm for progress bars during data processing.

import numpy as np
import pickle as pkl
import pathlib
import re
 
from tqdm import tqdm
 
from scipy.interpolate import interp1d
 
def shift_isochrone(color, magnitude, distance : float, extinction : float):
    mu = 5*np.log10(distance) - 5# + extinction
    aptMag = mu + magnitude
    aptCol = 3.2*extinction + color
    return aptMag, aptCol
 
def load_ISO_CMDs(root):
    CMDs = list(map(lambda x: str(x), pathlib.Path(root).rglob("CMD.pkl")))
    extract = list(map(lambda x: re.findall(r"Pop(A|E)\+(\d\.\d+)\/alpha-(\d\.\d+)\/", x)[0], CMDs))
    pops = set(map(lambda x: x[0], extract))
    Ys = set(map(lambda x: x[1], extract))
    alphas = set(map(lambda x: x[2], extract))
 
    lookup = dict()
    for pop in tqdm(pops, leave=False):
        lookup[pop] = dict()
        for Y in tqdm(Ys, leave=False):
            lookup[pop][float(Y)] = dict()
            for alpha in tqdm(alphas, leave=False):
                if checkTup := (pop, Y, alpha) in extract:
                    extractID = extract.index((pop, Y, alpha))
                    with open(CMDs[extractID], 'rb') as f:
                        CMD = pkl.load(f)
                    lookup[pop][float(Y)][float(alpha)] = CMD
    return lookup
 
def interCMDatMag(color, mag, targetMag):
    f = interp1d(mag, color)
    return f(targetMag)
 
def interp_isochrone_age(iso, targetAge):
    logTargetAgeYr= np.log10(targetAge*1e9)
    ageKeys = list(iso.keys())
    distance = [(x-logTargetAgeYr, x) for x in ageKeys]
    below = sorted(filter(lambda x: x[0] <=0, distance), key=lambda x: abs(x[0]))
    above = sorted(filter(lambda x: x[0] > 0, distance), key=lambda x: x[0])
    isoBelow = iso[below[0][1]]
    isoAbove = iso[above[0][1]]
    age1 = isoBelow['log10_isochrone_age_yr'].iloc[0]
    age2 = isoAbove['log10_isochrone_age_yr'].iloc[0]
 
    def linearinterpolate(x, other, age1, age2):
        newIso = ((other[x.name] - x)/(age2-age1)) * (logTargetAgeYr - age1) + x
        return newIso
 
    interpolated = isoBelow.apply(lambda x: linearinterpolate(x, isoAbove, age1, age2))
    return interpolated