Wednesday, October 2, 2024

Implemented Caching for BoltzmannDistribution Class for O(1) performance

Author: James M. Rogers, SE Ohio, 02 Oct 2024, 0227


We collapse the waveform of the entire set of all Boltzmann Distributions to a single point, and use that point to extract properties out of any temp in the entire set.  At O(1).  And you can encode entire computations, like Area under the curve, or FWHM.

Now everything in the library is O(1) after a percent is looked up the first time. And it caches everything at the reference temp of 5000 K and uses scale invariance to scale the energy to the requested temp.  If you ask for that same % again  

If you need more cached points for a large integration you are doing then adjust the cache size to fit the points you need, they are saved at the end of the run and loaded next run. 


import numpy as np

from scipy import constants

from scipy.optimize import fsolve

from collections import OrderedDict

import json

import os


# Speed of light in m/s

c = 299792458  


class BoltzmannDistribution:

    def __init__(self):

        self.representative_point = 4.7849648084645400e-20  # 50% point at 5000K

        self.reference_temperature = 5000

        self.cache_size = 10000

        self.cache = OrderedDict()

        self.cache_filename = "boltzmann_cache.json"

        self.load_cache()


    def scale_to_temperature(self, T):

        return T / self.reference_temperature


    def point_energy(self, T):

        return self.representative_point * self.scale_to_temperature(T)


    def peak_energy(self, T):

        return self.point_energy(T) / 0.2457097414250071665


    def area_under_curve(self, T):

        return self.point_energy(T) * T * 10e-22/50.20444590190353665093425661


    def peak_frequency(self, T):

        return self.point_energy(T) * 10e32 / .1627836661598892


    def fwhm(self, T):

        # Full Width at Half Maximum

        return self.point_energy(T)/.162935865000977884


    def wavelength_from_frequency(self, frequency):

        return c / frequency


    def frequency_from_wavelength(self, wavelength):

        return c / wavelength


    def energy_at_percentage(self, T, percentage):

        k = constants.Boltzmann

        def equation(E):

            return np.exp(-E / (k * T)) - percentage

        return fsolve(equation, k*T)[0]


    def calculate_energy_ratio(self, percentage):

        # Calculate energy at the reference temperature (5000K)

        return self.energy_at_percentage(self.reference_temperature, percentage)


    def get_energy_ratio(self, percentage, temperature):

        # Check if percentage is in cache

        if percentage in self.cache:

            reference_ratio = self.cache[percentage]

            # Move to end to mark as recently used

            self.cache.move_to_end(percentage)  

        else:

            reference_ratio = self.calculate_energy_ratio(percentage)

            self.cache[percentage] = reference_ratio

            if len(self.cache) > self.cache_size:

                # Remove least recently used item

                self.cache.popitem(last=False)  

        # Scale to requested temperature and return

        return reference_ratio * self.scale_to_temperature(temperature)


    def load_cache(self):

        if os.path.exists(self.cache_filename):

            with open(self.cache_filename, 'r') as f:

                loaded_cache = json.load(f)

                self.cache = OrderedDict((float(k), v) for k, v in loaded_cache.items())


    def save_cache(self):

        with open(self.cache_filename, 'w') as f:

            json.dump({str(k): v for k, v in self.cache.items()}, f)


    def __del__(self):

        self.save_cache()


No comments:

Post a Comment