Source code for chemistrylab.benches.characterization_bench

import numpy as np
import copy
import sys
from chemistrylab import material, vessel
import numba
from typing import NamedTuple, Tuple, Callable, Optional, List

[docs] @numba.jit(nopython=True) def calc_absorb3(item, C, x, w_min, w_max, absorb): # iterate through the spectral parameters in self.params and the wavelength space for j in range(item.shape[0]): nm = abs((1e7/item[j,1]-w_min)/(w_min-w_max)) #get a bounding area for x values above 1e-12 radius = 6*item[j, 2]*x.shape[0] left = max(0,int(nm*x.shape[0]-radius-1)) right = min(x.shape[0],int(nm*x.shape[0]+radius+2)) for k in range(left,right): #convert inverse cm to nm decay_rate = np.exp( -0.5 * ( (x[k] - nm) / item[j, 2] ) ** 2.0 ) if decay_rate < 1e-30: decay_rate = 0 absorb[k] += C * item[j, 0] * decay_rate
[docs] class CharacterizationBench: """ A set of methods made available to inspect an inputted vessel. Args: observation_list (Tuple[str]): Ordered list of observations to make (see Method Map) targets (Tuple[str]): A list of target materials n_vessels (int): The (maximum) number of vessels included in an observation Method Map: +------------+----------------+ | Key | Method | +============+================+ | 'spectra' | get_spectra | +------------+----------------+ | 'layers' | get_layers | +------------+----------------+ | 'targets' | encode_target | +------------+----------------+ | 'PVT' | encode_PVT | +------------+----------------+ """ def __init__(self, observation_list,targets,n_vessels): # specify the analysis techniques available in this bench self.params = {'spectra': {'range_ir': (2000, 20000)}} self.targets=targets self.n_vessels=n_vessels self.sizes=dict( spectra=200, layers=100, targets=len(targets), PVT = 3 ) #List of all functions, this can probably be a class variable instead of an instance variable self.characterization_tech = dict( spectra=self.get_spectra, layers=self.get_layers, targets=self.encode_target, PVT=self.encode_PVT ) #create a list of functions which will be used to build your observations self.observation_list=observation_list self.functions = [self.characterization_tech[a] for a in observation_list] #Determine the shape of the observations n_pixels=sum(self.sizes[a] for a in observation_list) self.observation_shape=(n_vessels*n_pixels,) self.state_s = (n_vessels,n_pixels)
[docs] def get_observation(self, vessels: vessel.Vessel, target: str): """ Returns a concatenation of observations of the vessels provided, using the list of observations provided in __init__ Args: vessels (Tuple[Vessel]): A list of vessels you want an observtation of. target (str): The current target material """ state=np.zeros(self.state_s,dtype=np.float32) for i,v in enumerate(vessels): if i>= self.n_vessels:break state[i] = np.concatenate([f(v) for f in self.functions]) return np.clip(state.flatten(),0,1)
def __call__(self, vessels, target): return self.get_observation(vessels, target)
[docs] def get_spectra(self, vessel: vessel.Vessel, materials: Optional[Tuple[material.Material]] = None, overlap: bool = True): """ Class method to generate total spectral data using a gaussian decay. Args: vessel (Vessel): The vessel inputted for spectroscopic analysis. materials (Optional[Tuple[material.Material]]): List of materials to get the spectra from overlap (bool): Indicates if the spectral plots show overlapping signatures. Defaults to False. Returns: np.array: A 1D array containing the absorption data of the present materials. """ mat_dict=vessel.material_dict # acquire the array of material concentrations if not materials: materials = [mat for key,mat in mat_dict.items()] else: materials = [mat_dict[mat] for mat in materials if mat in mat_dict] #prepare data to store absorption w_min,w_max=self.params['spectra']['range_ir'] x = np.linspace(0, 1, 200, endpoint=True, dtype=np.float32) absorb = np.zeros(x.shape[0], dtype=np.float32) #Get concentrations and spectras C = np.array([mat.mol for mat in materials])/vessel.filled_volume() if not overlap: params = tuple(mat.get_spectra_no_overlap() for mat in materials) else: params = tuple(mat.get_spectra_overlap() for mat in materials) #Build observation for i,param in enumerate(params): calc_absorb3(param, C[i], x, w_min, w_max, absorb) return np.clip(absorb, 0.0, 1.0)
[docs] def get_layers(self, vessel: vessel.Vessel): """ Returns: np.array: a 1D array of vessel layer information""" return vessel.get_layers()
[docs] def encode_PVT(self,vessel: vessel.Vessel): """ Returns: np.array: a size 3 array containing [temperature,volume,pressure]""" # set up the temperature #Tmin, Tmax = vessel.get_Tmin(), vessel.get_Tmax() temp = vessel.temperature normalized_temp = (temp - 0) / (1000 - 0) # set up the volume: this measure is kind of bad #consider using (vessel.get_current_volume()[-1] / vessel.get_volume()) instead #Vmin, Vmax = vessel.get_min_volume(), vessel.get_max_volume() volume = vessel.filled_volume() normalized_volume = (volume - 0) / (vessel.volume - 0) # set up the pressure #Pmax = vessel.get_pmax() #total_pressure = vessel.get_pressure() normalized_pressure = 0#total_pressure / Pmax #add them all into a 1D array out = np.array([normalized_temp,normalized_volume,normalized_pressure],dtype=np.float32) return np.clip(out,0,1)
[docs] def encode_target(self, vessel: vessel.Vessel): """ Returns: np.array: a 1D one-hot encoding of the target material (note must be set before doing this) """ targ_index = self.targets.index( one_hot=np.zeros(len(self.targets)) one_hot[targ_index]=1 return one_hot