Module layerlumos.utils

Expand source code
import csv
import json
import os
from pathlib import Path
import numpy as np
from scipy.interpolate import interp1d
from scipy.constants import c

Metals_sigma = {
    'Cu': 5.96e7,
    'Cr': 7.74e6,
    'Ag': 6.3e7,
    'Al': 3.77e7,
    'Ni' : 1.43e7,
    'W' : 1.79e7,
    'Ti' : 2.38e6,
    'Pd' : 9.52e6
}
Metals_nk_updated_specific_sigma = {}
mu0 = 4 * np.pi * 1e-7  # H/m
Z_0 = 377  # Ohms, impedance of free space
# Frequency range
nu = np.linspace(8e9, 18e9, 11)  # From 8 GHz to 18 GHz
omega = 2 * np.pi * nu  # Angular frequency
for metal, sigma in Metals_sigma.items():
    Z = np.sqrt(1j * omega * mu0 / sigma)  # Impedance of the material using specific sigma
    n_complex = Z_0 / Z  # Complex refractive index

    # Extract real and imaginary parts of the refractive index
    n_real = np.real(n_complex)
    k_imag = np.imag(n_complex)
    
    # Update the dictionary with the new values
    Metals_nk_updated_specific_sigma[metal] = {
        'freq_data': nu.tolist(),
        'n_data': n_real.tolist(),
        'k_data': k_imag.tolist()
    }
def load_material_RF(material_name, frequencies):
    """
    Load material RF data for a given material and frequencies.
    
    Parameters:
    - material_name: The name of the material to load.
    - frequencies: Array of frequencies for which data is requested.
    
    Returns:
    - A NumPy array with columns for frequency, n, and k.
    """
    # Check if the material is defined
    if material_name not in Metals_nk_updated_specific_sigma:
        # Material not found, return default values (n=1, k=0) for given frequencies
        n_default = np.ones_like(frequencies)
        k_default = np.zeros_like(frequencies)
        data = np.column_stack((frequencies, n_default, k_default))
    else:
        # Material found, extract the data
        material_data = Metals_nk_updated_specific_sigma[material_name]
        freq_data = np.array(material_data['freq_data'])
        n_data = np.array(material_data['n_data'])
        k_data = np.array(material_data['k_data'])
        
        # Interpolate n and k data for the input frequencies, if necessary
        n_interpolated = np.interp(frequencies, freq_data, n_data)
        k_interpolated = np.interp(frequencies, freq_data, k_data)
        
        # Combine the data
        data = np.column_stack((frequencies, n_interpolated, k_interpolated))
    
    return data



def load_material(material_name):
    """
    Load material data from its CSV file, converting wavelength to frequency.

    Parameters:
    - material_name: The name of the material to load.
    
    Returns:
    - A NumPy array with columns for frequency (converted from wavelength), n, and k.
    """
    # Determine the directory of the current script
    current_dir = Path(__file__).parent

    # Build the absolute path to materials.json
    materials_file = current_dir / "materials.json"

    # Load the material index JSON to find the CSV file path
    with open(materials_file, 'r') as file:
        material_index = json.load(file)
    
    # Get the file path for the requested material
    relative_file_path = material_index.get(material_name)
    if not relative_file_path:
        raise ValueError(f"Material {material_name} not found in the index.")
    
    # Construct the absolute path to the material CSV file
    csv_file_path = current_dir / relative_file_path

    # Initialize a list to hold the converted data
    data = []
    
    # Open and read the CSV file
    with open(csv_file_path, 'r') as csvfile:
        csvreader = csv.reader(csvfile)
        next(csvreader)  # Skip the header row
        for row in csvreader:
            try:
                # Attempt to convert wavelength, n, and k to floats
                wavelength_um, n, k = map(float, row)
                # Convert wavelength in um to frequency in Hz
                frequency = c / (wavelength_um * 1e-6)
                data.append((frequency, n, k))
            except ValueError:
                # If conversion fails, skip this row
                continue
    
    # Convert to a NumPy array for easier handling in calculations
    data = np.array(data)
    # Ensure the data is sorted by frequency in ascending order
    data = data[data[:, 0].argsort()]
    
    return data

def interpolate_material(material_data, frequencies):
    """
    Interpolate n and k values for the specified frequencies.

    Parameters:
    - material_data: The data for the material, as returned by load_material.
    - frequencies: A list or NumPy array of frequencies to interpolate n and k for.
    
    Returns:
    - Interpolated values of n and k as a NumPy array.
    """
    # Extract frequency, n, and k columns
    freqs, n_values, k_values = material_data.T
    
    # Remove duplicates (if any) while preserving order
    unique_freqs, indices = np.unique(freqs, return_index=True)
    unique_n_values = n_values[indices]
    unique_k_values = k_values[indices]
    
    # Ensure frequencies are sorted (usually they should be, but just in case)
    sorted_indices = np.argsort(unique_freqs)
    sorted_freqs = unique_freqs[sorted_indices]
    sorted_n_values = unique_n_values[sorted_indices]
    sorted_k_values = unique_k_values[sorted_indices]
    
    # Create interpolation functions for the sorted, unique data
    n_interp = interp1d(sorted_freqs, sorted_n_values, kind='cubic', fill_value="extrapolate")
    k_interp = interp1d(sorted_freqs, sorted_k_values, kind='cubic', fill_value="extrapolate")
    
    # Interpolate n and k for the given frequencies
    n_interp_values = n_interp(frequencies)
    k_interp_values = k_interp(frequencies)
    
    return np.vstack((n_interp_values, k_interp_values)).T

Functions

def interpolate_material(material_data, frequencies)

Interpolate n and k values for the specified frequencies.

Parameters: - material_data: The data for the material, as returned by load_material. - frequencies: A list or NumPy array of frequencies to interpolate n and k for.

Returns: - Interpolated values of n and k as a NumPy array.

Expand source code
def interpolate_material(material_data, frequencies):
    """
    Interpolate n and k values for the specified frequencies.

    Parameters:
    - material_data: The data for the material, as returned by load_material.
    - frequencies: A list or NumPy array of frequencies to interpolate n and k for.
    
    Returns:
    - Interpolated values of n and k as a NumPy array.
    """
    # Extract frequency, n, and k columns
    freqs, n_values, k_values = material_data.T
    
    # Remove duplicates (if any) while preserving order
    unique_freqs, indices = np.unique(freqs, return_index=True)
    unique_n_values = n_values[indices]
    unique_k_values = k_values[indices]
    
    # Ensure frequencies are sorted (usually they should be, but just in case)
    sorted_indices = np.argsort(unique_freqs)
    sorted_freqs = unique_freqs[sorted_indices]
    sorted_n_values = unique_n_values[sorted_indices]
    sorted_k_values = unique_k_values[sorted_indices]
    
    # Create interpolation functions for the sorted, unique data
    n_interp = interp1d(sorted_freqs, sorted_n_values, kind='cubic', fill_value="extrapolate")
    k_interp = interp1d(sorted_freqs, sorted_k_values, kind='cubic', fill_value="extrapolate")
    
    # Interpolate n and k for the given frequencies
    n_interp_values = n_interp(frequencies)
    k_interp_values = k_interp(frequencies)
    
    return np.vstack((n_interp_values, k_interp_values)).T
def load_material(material_name)

Load material data from its CSV file, converting wavelength to frequency.

Parameters: - material_name: The name of the material to load.

Returns: - A NumPy array with columns for frequency (converted from wavelength), n, and k.

Expand source code
def load_material(material_name):
    """
    Load material data from its CSV file, converting wavelength to frequency.

    Parameters:
    - material_name: The name of the material to load.
    
    Returns:
    - A NumPy array with columns for frequency (converted from wavelength), n, and k.
    """
    # Determine the directory of the current script
    current_dir = Path(__file__).parent

    # Build the absolute path to materials.json
    materials_file = current_dir / "materials.json"

    # Load the material index JSON to find the CSV file path
    with open(materials_file, 'r') as file:
        material_index = json.load(file)
    
    # Get the file path for the requested material
    relative_file_path = material_index.get(material_name)
    if not relative_file_path:
        raise ValueError(f"Material {material_name} not found in the index.")
    
    # Construct the absolute path to the material CSV file
    csv_file_path = current_dir / relative_file_path

    # Initialize a list to hold the converted data
    data = []
    
    # Open and read the CSV file
    with open(csv_file_path, 'r') as csvfile:
        csvreader = csv.reader(csvfile)
        next(csvreader)  # Skip the header row
        for row in csvreader:
            try:
                # Attempt to convert wavelength, n, and k to floats
                wavelength_um, n, k = map(float, row)
                # Convert wavelength in um to frequency in Hz
                frequency = c / (wavelength_um * 1e-6)
                data.append((frequency, n, k))
            except ValueError:
                # If conversion fails, skip this row
                continue
    
    # Convert to a NumPy array for easier handling in calculations
    data = np.array(data)
    # Ensure the data is sorted by frequency in ascending order
    data = data[data[:, 0].argsort()]
    
    return data
def load_material_RF(material_name, frequencies)

Load material RF data for a given material and frequencies.

Parameters: - material_name: The name of the material to load. - frequencies: Array of frequencies for which data is requested.

Returns: - A NumPy array with columns for frequency, n, and k.

Expand source code
def load_material_RF(material_name, frequencies):
    """
    Load material RF data for a given material and frequencies.
    
    Parameters:
    - material_name: The name of the material to load.
    - frequencies: Array of frequencies for which data is requested.
    
    Returns:
    - A NumPy array with columns for frequency, n, and k.
    """
    # Check if the material is defined
    if material_name not in Metals_nk_updated_specific_sigma:
        # Material not found, return default values (n=1, k=0) for given frequencies
        n_default = np.ones_like(frequencies)
        k_default = np.zeros_like(frequencies)
        data = np.column_stack((frequencies, n_default, k_default))
    else:
        # Material found, extract the data
        material_data = Metals_nk_updated_specific_sigma[material_name]
        freq_data = np.array(material_data['freq_data'])
        n_data = np.array(material_data['n_data'])
        k_data = np.array(material_data['k_data'])
        
        # Interpolate n and k data for the input frequencies, if necessary
        n_interpolated = np.interp(frequencies, freq_data, n_data)
        k_interpolated = np.interp(frequencies, freq_data, k_data)
        
        # Combine the data
        data = np.column_stack((frequencies, n_interpolated, k_interpolated))
    
    return data