[Python] overflow encountered in matmul, what can I do?

Discussão em 'Python' iniciado por Stack, Fevereiro 25, 2025.

  1. Stack

    Stack Membro Participativo

    I am currently using an open source Python package called snompy (https://github.com/TomVincentUK/snompy). While implementing the package, a function that defines the transfer matrix returns an overflow error in the line that uses numpy's matrix product (matmul). The part of the code that raises the problem is as follows:

    def transfer_matrix_qs(self, q=0.0):
    """Return the transfer matrix for the sample in the quasistatic
    limit.

    Parameters
    ----------
    q : float, default 0.0
    In-plane electromagnetic wave momentum.
    Must be broadcastable with all `eps_stack[i, ...]` and
    `t_stack[i, ...]`. Either `q` or `theta_in` must be None.

    Returns
    -------
    M_qs : complex
    The quasistatic transfer matrix of the sample.

    Notes
    -----
    This implementation of the transfer matrix method is based on the
    description given in reference [1]_.

    References
    ----------
    .. [1] T. Zhan, X. Shi, Y. Dai, X. Liu, and J. Zi, “Transfer matrix
    method for optics in graphene layers,” J. Phys. Condens. Matter,
    vol. 25, no. 21, p. 215301, May 2013,
    doi: 10.1088/0953-8984/25/21/215301.

    """
    trans_factor = self.eps_stack[:-1] / self.eps_stack[1:]
    trans_matrices = (
    1 + np.array([[1, -1], [-1, 1]]) * trans_factor[..., np.newaxis, np.newaxis]
    ) / 2

    # Convert stack to single transfer matrix (accounting for propagation if needed)
    M_qs = trans_matrices[0]
    if self.multilayer:
    # Optical path length of internal layers
    prop_factor = np.array([q * t for t in self.t_stack])

    # Avoid overflow by clipping (there's probably a more elegant way)
    prop_factor = np.clip(prop_factor, -_MAX_EXP_ARG, _MAX_EXP_ARG)
    prop_matrices = np.exp(
    np.array([1, -1]) * prop_factor[..., np.newaxis, np.newaxis]
    ) * np.eye(2)

    for T, P in zip(trans_matrices[1:], prop_matrices):
    M_qs = M_qs @ P @ T
    else:
    M_qs = M_qs * np.ones_like(q)[..., np.newaxis, np.newaxis]

    return M_qs


    The error then propagates to functions that depend on the transfer_matrix_qs results. The error window on my side is displayed as follows:


    C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:228: RuntimeWarning: overflow encountered in matmul M_qs = M_qs @ P @ T C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:228: RuntimeWarning: invalid value encountered in matmul M_qs = M_qs @ P @ T C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:252: RuntimeWarning: overflow encountered in divide return M[..., 1, 0] / M[..., 0, 0] C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:252: RuntimeWarning: invalid value encountered in divide return M[..., 1, 0] / M[..., 0, 0] C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:723: RuntimeWarning: invalid value encountered in multiply phi = np.sum(w_lag * beta_q, axis=0) / (2 * z_Q) C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:723: RuntimeWarning: invalid value encountered in divide phi = np.sum(w_lag * beta_q, axis=0) / (2 * z_Q) C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:724: RuntimeWarning: invalid value encountered in multiply E = np.sum(w_lag * x_lag * beta_q, axis=0) / (4 * z_Q**2) C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:724: RuntimeWarning: invalid value encountered in divide E = np.sum(w_lag * x_lag * beta_q, axis=0) / (4 * z_Q**2) C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:796: RuntimeWarning: invalid value encountered in divide d_image = np.abs(phi / E) - z_Q C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\sample.py:797: RuntimeWarning: invalid value encountered in divide beta_image = phi**2 / E C:\Spyder\envs\spyder-runtime\Lib\site-packages\snompy\fdm.py:261: RuntimeWarning: invalid value encountered in divide alpha_eff = 1 + (beta_0 * f_0) / (2 * (1 - beta_1 * f_1))
    ​

    I have prepared a test code you can copy and run yourself to reproduce the error:

    import numpy as np
    import snompy

    # Set some experimental parameters
    A_tip = 90e-9 # AFM tip tapping amplitude
    r_tip = 10e-9 # AFM tip radius of curvature
    L_tip = 300e-9 # Semi-major axis length of ellipsoid tip model
    n = 2 # Harmonic for demodulation
    theta_in = np.deg2rad(60) # Light angle of incidence
    c_r = 0.9 # Experimental weighting factor
    nu_vac = np.linspace(600,1000, 1000) * 1e2 # Vacuum wavenumber
    method = "multi" # The FDM method to use
    t_aln= 250e-9 #AlN layer thickness
    t_sample=np.array([t_aln])
    eps_air = 1.0 # Air permittivity
    eps_Si = 11.7 # Si permitivitty in the mid-infrared
    ### GaN Lorentzian model parameters
    einf_gan = 5.35 #epsilon infinity GaN
    to_gan = 530 #TO phonon frequency in cm-1
    lo_gan = 735 #LO phonon frequency in cm-1
    gamma_gan = 3.5 #relaxation factor
    ### AlN Lorentzian model parameters
    einf_aln=4.6
    to_aln=649.5
    lo_aln=880.3
    gamma_aln= 9

    #Dielectric permittivity from a single Lorentzian oscillator:
    eps_gan = einf_gan*(1+ (lo_gan**2 -to_gan**2)/(to_gan**2 - (nu_vac*1e-2)**2 - (nu_vac*1e-2)*1j*gamma_gan))
    eps_aln= einf_aln*(1+ (lo_aln**2 -to_aln**2)/(to_aln**2 - (nu_vac*1e-2)**2 - (nu_vac*1e-2)*1j*gamma_aln))

    #Model of AlN on GaN
    sample_aln = snompy.Sample(
    eps_stack=(eps_air,eps_aln, eps_gan),
    t_stack = t_sample,
    nu_vac=nu_vac,)

    # Model of Si
    sample_si = snompy.bulk_sample(eps_sub=eps_Si, eps_env=eps_air, nu_vac=nu_vac)

    # Measurement
    alpha_eff_aln = snompy.fdm.eff_pol_n(
    sample=sample_aln, A_tip=A_tip, n=n, r_tip=r_tip, L_tip=L_tip, method=method
    )
    r_coef_aln = sample_aln.refl_coef(theta_in=theta_in)
    sigma_aln = (1 + c_r * r_coef_aln) ** 2 * alpha_eff_aln

    # Silicon reference
    alpha_eff_si = snompy.fdm.eff_pol_n(
    sample=sample_si, A_tip=A_tip, n=n, r_tip=r_tip, L_tip=L_tip, method=method
    )
    r_coef_si = sample_si.refl_coef(theta_in=theta_in)
    sigma_si = (1 + c_r * r_coef_si) ** 2 * alpha_eff_si

    # Normalised complex scattering
    eta_n = sigma_aln / sigma_si


    I'm interested in eta_n's amplitude and phase, but it has a bunch of nans caused by the overflow. Reducing the AlN layer thickness (t_aln) helps in reducing the amount of elements in the array that overflow, but I want the code to work for the actual thickness.

    Before asking directly to the author of the code, I was wondering if there's anything on my end that I can do to avoid the function to overflow. The function uses complex numbers, so very naïvely I tried to change the type from complex128 to complex256 but apparently that type is not supported on my machine. Any further suggestions are highly appreciated.

    Continue reading...

Compartilhe esta Página