Source code for interpolation

# -*- coding: utf-8 -*-
"""
The interpolation module allows simple interpolation of data.

It is highly recommended to interpolate data over extent for analysis and optimization.

For experimental data with many data points (e.g. DSC or rheology experiments), a linear 
interpolation is usually more than enough.

For experimental data with scarce data points (e.g. FTIR experiments) 
a cubic spline interpolation might be more appropriate.
"""

import numpy as np
from scipy import interpolate




[docs] def limit_of_interpolation(conversions_lists): """ Find the minimum and maximum values in a list of conversion lists. Parameters ---------- conversions_lists : list List of conversion lists. Returns ------- tuple Minimum and maximum values found in the conversion lists. """ flat_conversions = np.concatenate(conversions_lists) return np.min(flat_conversions), np.max(flat_conversions)
[docs] def check_increase_and_remove_if_not(conversions, times, temperatures, rates): """ Check if conversions are increasing and remove any non-increasing segments. Parameters ---------- conversions : list List of conversion arrays. times : list List of time arrays. temperatures : list List of temperature arrays. rates : list, optional List of rate arrays. Default is None. Returns ------- tuple New lists of conversions, times, temperatures, and rates with non-increasing segments removed. """ new_conversions = [] new_times = [] new_temperatures = [] new_rates = [] if rates else None for i in range(len(conversions)): conv = np.array(conversions[i]) time = np.array(times[i]) temp = np.array(temperatures[i]) increasing_indices = np.where(conv[:-1] < conv[1:])[0] increasing_indices = np.append(increasing_indices, len(conv) - 1) new_conversions.append(conv[increasing_indices]) new_times.append(time[increasing_indices]) new_temperatures.append(temp[increasing_indices]) if rates: rate = np.array(rates[i]) new_rates.append(rate[increasing_indices]) if rates: return new_conversions, new_times, new_temperatures, new_rates else: return new_conversions, new_times, new_temperatures
[docs] def linear_interpolation(conversions_lists, times_lists, temperatures_lists, rates_lists, number_of_points): """ Perform linear interpolation on conversion, time, temperature, and rate data. Parameters ---------- conversions_lists : list List of conversion arrays. times_lists : list List of time arrays. temperatures_lists : list List of temperature arrays. rates_lists : list List of rate arrays. number_of_points : int Number of points for interpolation. Returns ------- tuple Interpolated conversion, time, temperature, and rate arrays. """ flat_conversions = np.concatenate(conversions_lists) minimum, maximum = np.min(flat_conversions), np.max(flat_conversions) global_conversion = np.linspace(minimum, maximum, number_of_points) conv, time, temp, rates = check_increase_and_remove_if_not(conversions_lists, times_lists, temperatures_lists, rates_lists) new_conversions = np.empty((len(conversions_lists), number_of_points)) new_times = np.empty((len(conversions_lists), number_of_points)) new_temperatures = np.empty((len(conversions_lists), number_of_points)) new_rates = np.empty((len(conversions_lists), number_of_points)) if rates_lists else None for i in range(len(conversions_lists)): f = interpolate.interp1d(conv[i], time[i]) g = interpolate.interp1d(conv[i], temp[i]) h = interpolate.interp1d(conv[i], rates[i]) new_times[i] = f(global_conversion) new_temperatures[i] = g(global_conversion) new_rates[i] = h(global_conversion) new_conversions[i] = global_conversion return new_conversions, new_times, new_temperatures, new_rates
[docs] def linear_interpolation_multiple_limits(conversions_lists, times_lists, temperatures_lists, rates_lists, number_of_points): """ Perform linear interpolation on conversion, time, temperature, and rate data with multiple limits. Parameters ---------- conversions_lists : list List of conversion arrays. times_lists : list List of time arrays. temperatures_lists : list List of temperature arrays. rates_lists : list List of rate arrays. number_of_points : int Number of points for interpolation. Returns ------- tuple Interpolated conversion, time, temperature, and rate arrays. """ new_conversions = np.empty((len(conversions_lists), number_of_points)) new_times = np.empty((len(conversions_lists), number_of_points)) new_temperatures = np.empty((len(conversions_lists), number_of_points)) new_rates = np.empty((len(conversions_lists), number_of_points)) for i, conv_list in enumerate(conversions_lists): minimum = conv_list[0] maximum = conv_list[-1] global_conversion = np.linspace(minimum, maximum, number_of_points) f = interpolate.interp1d(conv_list, times_lists[i]) g = interpolate.interp1d(conv_list, temperatures_lists[i]) h = interpolate.interp1d(conv_list, rates_lists[i]) new_times[i] = f(global_conversion) new_temperatures[i] = g(global_conversion) new_rates[i] = h(global_conversion) new_conversions[i] = global_conversion return new_conversions, new_times, new_temperatures, new_rates
[docs] def cubic_spline_interpolation(conversions_lists, times_lists, temperatures_lists, rates_lists, number_of_points): """ Perform cubic spline interpolation on conversion, time, temperature, and rate data. Parameters ---------- conversions_lists : list List of conversion arrays. times_lists : list List of time arrays. temperatures_lists : list List of temperature arrays. rates_lists : list List of rate arrays. number_of_points : int Number of points for interpolation. Returns ------- tuple Interpolated conversion, time, temperature, and rate arrays. """ flat_conversions = np.concatenate(conversions_lists) minimum, maximum = np.min(flat_conversions), np.max(flat_conversions) global_conversion = np.linspace(minimum, maximum, number_of_points) conv, time, temp, rates = check_increase_and_remove_if_not(conversions_lists, times_lists, temperatures_lists, rates_lists) new_conversions = np.empty((len(conversions_lists), number_of_points)) new_times = np.empty((len(conversions_lists), number_of_points)) new_temperatures = np.empty((len(conversions_lists), number_of_points)) new_rates = np.empty((len(conversions_lists), number_of_points)) if rates_lists else None for i in range(len(conversions_lists)): f = interpolate.CubicSpline(conv[i], time[i]) g = interpolate.CubicSpline(conv[i], temp[i]) h = interpolate.CubicSpline(conv[i], rates[i]) new_times[i] = f(global_conversion) new_temperatures[i] = g(global_conversion) new_rates[i] = h(global_conversion) new_conversions[i] = global_conversion return new_conversions, new_times, new_temperatures, new_rates
[docs] def cubic_spline_interpolation_multiple_limits(conversions_lists, times_lists, temperatures_lists, rates_lists, number_of_points): """ Perform cubic spline interpolation on conversion, time, and temperature data with multiple limits. Parameters ---------- conversions_lists : list List of conversion arrays. times_lists : list List of time arrays. temperatures_lists : list List of temperature arrays. number_of_points : int Number of points for interpolation. Returns ------- tuple Interpolated conversion, time, and temperature arrays. """ # Preallocate arrays for interpolated values new_conversions = np.empty((len(conversions_lists), number_of_points)) new_times = np.empty((len(conversions_lists), number_of_points)) new_temperatures = np.empty((len(conversions_lists), number_of_points)) new_rates = np.empty((len(conversions_lists), number_of_points)) for i, conv_list in enumerate(conversions_lists): minimum = conv_list[0] maximum = conv_list[-1] global_conversion = np.linspace(minimum, maximum, number_of_points) # Perform cubic spline interpolation f = interpolate.CubicSpline(conversions_lists[i], times_lists[i]) g = interpolate.CubicSpline(conversions_lists[i], temperatures_lists[i]) h = interpolate.CubicSpline(conv_list, rates_lists[i]) # Evaluate interpolations at global conversion points new_conv = global_conversion new_time = f(global_conversion) new_temp = g(global_conversion) new_rate = h(global_conversion) # Append to results new_conversions.append(new_conv) new_times.append(new_time) new_temperatures.append(new_temp) new_rates.append(new_rate) return np.array(new_conversions), np.array(new_times), np.array(new_temperatures)
if __name__ == "__main__": #%% Example 1 - Experiment with a lot of experimental data points import matplotlib.pyplot as plt import kinetic_models as km number_of_points = 500 time_list = np.linspace(0, 25, number_of_points) # 30 minutes times = [time_list, time_list, time_list, time_list] temperatures = [np.linspace(293, 443, number_of_points), # 5°C/min np.linspace(293, 593, number_of_points), # 10°C/min np.linspace(293, 743, number_of_points), # 15°C/min np.linspace(293, 893, number_of_points)] # 20°C/min A1 = 1e10 E1 = 70000 A2 = 1e13 E2 = 85000 m = 0.45 n = 1 conversions = [] rates = [] for i in range(len(times)): extent, rate, _, _, _ = km.compute_extent_and_rate(times[i], temperatures[i], rate_law=km.rate_for_kamal, rate_law_args=(A1,E1,A2,E2,m,n)) conversions.append(extent) rates.append(rate) linear_conversions, linear_times, linear_temperatures, linear_rates = linear_interpolation(conversions,times,temperatures,rates,1000) cubic_conversions, cubic_times, cubic_temperatures, cubic_rates = cubic_spline_interpolation(conversions,times,temperatures,rates,5) #%% Plot linear interpolation # Rate over time fig, ax = plt.subplots() ax.set_xlabel("Time (s)") ax.set_ylabel("Rate") ax.set_title("Linear interpolation vs Original data") for i in range(len(rates)): line_original, =ax.plot(times[i],rates[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(linear_times[i],linear_rates[i],label="Linear interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend() # Rate over extent fig, ax = plt.subplots() ax.set_xlabel("Extent") ax.set_ylabel("Rate") ax.set_title("Linear interpolation vs Original data") for i in range(len(rates)): line_original, = ax.plot(conversions[i],rates[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(linear_conversions[i],linear_rates[i],label="Linear interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend() # Extent over time fig, ax = plt.subplots() ax.set_xlabel("Time (s)") ax.set_ylabel("Extent") ax.set_title("Interpolation vs Original data") for i in range(len(rates)): line_original, = ax.plot(times[i],conversions[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(linear_times[i],linear_conversions[i],label="Linear interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend() #%% Plot cubic interpolation # Rate over time fig, ax = plt.subplots() ax.set_xlabel("Time (s)") ax.set_ylabel("Rate") ax.set_title("Cubic interpolation vs Original data") for i in range(len(rates)): line_original, =ax.plot(times[i],rates[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(cubic_times[i],cubic_rates[i],label="Cubic interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend() # Rate over extent fig, ax = plt.subplots() ax.set_xlabel("Extent") ax.set_ylabel("Rate") ax.set_title("Cubic interpolation vs Original data") for i in range(len(rates)): line_original, = ax.plot(conversions[i],rates[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(cubic_conversions[i],cubic_rates[i],label="Cubic interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend() # Extent over time fig, ax = plt.subplots() ax.set_xlabel("Time (s)") ax.set_ylabel("Extent") ax.set_title("Cubic interpolation vs Original data") for i in range(len(rates)): line_original, = ax.plot(times[i],conversions[i],label="Original data for " + str((i+1)*5) + "°/min",alpha=0.5) curve_color = line_original.get_color() ax.plot(cubic_times[i],cubic_conversions[i],label="Cubic interpolation for " + str((i+1)*5) + "°/min", color=curve_color, linestyle="dashed") ax.legend()