Source code for mstm_studio.rii_materials


import sys
import numpy as np
from scipy import interpolate
from mstm_studio.mstm_spectrum import Material

try:
    from pathlib import Path
    import zipfile
    import yaml
except:
    print('WARNING: reading from refractiveindex.info is disabled')
    print('required python modules: zipfile, yaml')


[docs]class RiiMaterial(Material): def __init__(self, archive_filename=''): ''' Setup material from RefractiveIndexInfo database dump available online at url: <https://refractiveindex.info/download/database/> archive_filename: string path to the downloaded zip file of db dump Example of usage: >>> riimat = RiiMaterial('rii-database-2024-08-14.zip') >>> riimat.select('main', 'Ag', 'Babar') ''' self.rii_db_items = dict() if archive_filename == '': # use system-dependedt default path if sys.platform == 'win32': appdata_path = Path.home() / 'AppData' / 'Roaming' / 'mstm_studio' else: appdata_path = Path.home() / '.mstm_studio' # find in appdata_path filenames = list(appdata_path.glob('rii-database-*.zip')) if len(filenames) > 0: archive_filename = filenames[-1] else: print('WARNING: RII database zip file not found ') print('in app data folder') print(f' {appdata_path}') print('search in home..') filenames = list(Path.home().glob('rii-database-*.zip')) if len(filenames) > 0: archive_filename = filenames[-1] else: raise Exception('RII database zip file not found.\n'+ 'Please download it from url: \n' + '<https://refractiveindex.info/download/database/>') print(f'Using RII database zip file: {archive_filename}') self.archive_filename = archive_filename
[docs] def scan(self): ''' Read information about all materials in database and store it in internal dict `rii_db_items` ''' self.rii_db_items = dict() # 0 1 2 3 4 # 'database', 'data-nk', 'organic', 'CHBr3 - bromoform', 'Ghosal.yml' with zipfile.ZipFile(self.archive_filename) as z: for filename in z.namelist(): if '/' in filename: words = filename.split('/') else: words = filename.split('\\') if len(words) < 5: continue if words[1] == 'data-nk' and len(words[4]) != 0: if words[2] == 'other': key = f'{words[2]}/{words[3]}' if key not in self.rii_db_items: self.rii_db_items[key] = dict() if words[4] not in self.rii_db_items[key]: self.rii_db_items[key][words[4]] = [] if words[5][-4:] == '.yml': self.rii_db_items[key][words[4]].append(words[5][:-4]) else: if words[2] not in self.rii_db_items: self.rii_db_items[words[2]] = dict() if words[3] not in self.rii_db_items[words[2]]: self.rii_db_items[words[2]][words[3]] = [] if words[4][-4:] == '.yml': self.rii_db_items[words[2]][words[3]].append(words[4][:-4])
[docs] def filter_valid(self): ''' Remove materials from the internal dict `rii_db_items` which does not contain data in limit of 300 and 800 nm ''' if self.rii_db_items is None: print('No items. Please `_scan()` first') return filtered_items = dict() for shelf in self.rii_db_items: for book in self.rii_db_items[shelf]: # print(f'testing {shelf}/{book}') for name in self.rii_db_items[shelf][book]: flag = True try: self.select(shelf, book, name) except Exception as e: flag = False if flag: try: self.get_n(300) self.get_k(300) self.get_n(800) self.get_k(800) except Exception as e: flag = False if flag: # passed if shelf not in filtered_items: filtered_items[shelf] = dict() if book not in filtered_items[shelf]: filtered_items[shelf][book] = [] filtered_items[shelf][book].append(name) self.rii_db_items = filtered_items
[docs] def print_db_items(self): ''' Print to std outout the list (tree) of available materials ''' if self.rii_db_items is None: print('No items. Please `_scan()` first') return print('`shelf`') print('\t`book`') print('\t\t`pages`') for shelf in self.rii_db_items: print(f'{shelf}') for book in self.rii_db_items[shelf]: print(f'\t{book}') print(f'\t\t{" ".join(self.rii_db_items[shelf][book])}')
[docs] def select(self, shelf, book, name): ''' Apply specific material from database. shelf: str the set of materials (main, organic, glasses, etc) book: str material name name: str (page in RII notation) variant of the dielectric function for material ''' with zipfile.ZipFile(self.archive_filename) as z: with z.open(f'database/data-nk/{shelf}/{book}/{name}.yml', 'r') as f: data = yaml.safe_load(f) i = 0 type_value = data.get('DATA', [])[i].get('type', '') if 'tabulated' not in type_value: i = 1 type_value = data.get('DATA', [])[i].get('type', '') if 'tabulated' not in type_value: i = 1 type_value = data.get('DATA', [])[i].get('type', '') data_value = data.get('DATA', [])[i].get('data', '') lines = data_value.split('\n') arrays = [np.array([float(x) for x in s.split()]) for s in lines] self.wls = np.array([1000*arr[0] for arr in arrays if arr.size > 0]) n = np.array([arr[1] for arr in arrays if arr.size > 1]) k = np.array([arr[2] for arr in arrays if arr.size > 2]) if len(k) == 0: k = np.zeros(len(self.wls)) self._get_n_interp = interpolate.interp1d(self.wls, n, kind='cubic') self._get_k_interp = interpolate.interp1d(self.wls, k, kind='cubic') self.__name__ = f'{book}/{name[:5]}'
[docs] def count_materials(self): ''' Return the number of distinct materials (not including variants of dielectric functions) ''' i = 0 for shelf in self.rii_db_items: i += len(self.rii_db_items[shelf]) # ~ for book in self.rii_db_items[shelf]: # ~ i += 1 return i
if __name__ == '__main__': riimat = RiiMaterial() riimat.scan() print(f'Before filtration {riimat.count_materials()}') riimat.filter_valid() print(f'After filtration {riimat.count_materials()}') riimat.print_db_items() riimat.select('main', 'Ag', 'Babar') print(riimat) riimat.plot()