コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

ファイル:SPP silver-air interface 370nm.gif

ページのコンテンツが他言語でサポートされていません。

SPP_silver-air_interface_370nm.gif (480 × 320 ピクセル、ファイルサイズ: 475キロバイト、MIME タイプ: image/gif、ループします、30 フレーム、2.1秒)

概要

解説
English: E-field of a surface plasmon polariton, at the silver-air interface. The animation shows how the E-field varies over an optical cycle. Free-space wavelength is 370nm, so the permittivity of silver is -2.62 + 0.626i. The picture is 0.3 * 370 nanometers across horizontally.
日付
原典 投稿者自身による著作物
作者 Sbyrnes321

ライセンス

この作品の著作権者である私は、この作品を以下のライセンスで提供します。
Creative Commons CC-Zero このファイルはクリエイティブ・コモンズ CC0 1.0 全世界 パブリック・ドメイン提供のもとで利用可能にされています。
ある作品に本コモンズ証を関連づけた者は、その作品について世界全地域において著作権法上認められる、その者が持つすべての権利(その作品に関する権利や隣接する権利を含む。)を、法令上認められる最大限の範囲で放棄して、パブリック・ドメインに提供しています。

この作品は、たとえ営利目的であっても、許可を得ずに複製、改変・翻案、配布、上演・演奏することが出来ます。

Source code

 
この GIF ラスター画像Matplotlibで作成されました。
"""
(C) Steven Byrnes, 2013. This code is released under the MIT license
http://opensource.org/licenses/MIT

This code runs in Python 2.7 or 3.3. It requires imagemagick to be installed;
that's how it assembles images into animated GIFs.

Creates an animation of the electric field vectors of a
surface-plasmon-polariton wave. The metal-dielectric interface is at z=0,
with metal at z<0 and dielectric (such as air) at z>0.
"""
 
# Use Python 3 style division and print
# a/b is real division, a//b is integer division
from __future__ import division, print_function

import numpy as np
from cmath import exp, pi

import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches

import subprocess, os
directory_now = os.path.dirname(os.path.realpath(__file__))

# --- PART 1 OF 2: PHYSICS --- #

def Efield(x_times_kvac, z_times_kvac, t_times_omega, eps_m, eps_d, print_wave_properties=False):
    """"
    Inputs:
      * x_times_kvac and z_times_kvac are the coordinates (x,z) multiplied
          by the vacuum angular wavenumber kvac = omega / c.
      * t_times_nu is the time t multiplied by frequency nu.
      * eps_m and eps_d are the complex permittivities of the metal and dielectric.
    
    Output: The electric field vector (E_x,E_z). It is scaled so that
      E_z(0, 0, tw, e1, e2) = cos(tw) on the dielectric side of the interface.
    """
    # Calculate components of the angular wavevector in the dielectric and
    # metal, as a multiple of kvac = omega / c:
    eps_m = complex(eps_m) #cast to complex, so square roots won't raise errors.
    kx_over_kvac = (eps_m * eps_d / (eps_m + eps_d))**(1/2)
    kzd_over_kvac = (eps_d - kx_over_kvac**2)**(1/2)
    kzm_over_kvac = (eps_m - kx_over_kvac**2)**(1/2)
    
    # Pick the correct square-roots, so that e^(i*k*z) decays away from interface
    if kzd_over_kvac.imag < 0:
        kzd_over_kvac *= -1
    if kzm_over_kvac.imag > 0:
        kzm_over_kvac *= -1
    
    #double-check the boundary condition
    almost_equal = lambda a,b,tolerance : (abs(a-b) / (abs(a) + abs(b))) < tolerance
    if not almost_equal(kzd_over_kvac * eps_m, kzm_over_kvac * eps_d, 1e-10):
        raise ValueError('Something is wrong! Boundary condition fails!')
    
    if print_wave_properties:
        print('kx / kvac = ', kx_over_kvac)
        print('kzd / kvac = ', kzd_over_kvac)
        print('kzm / kvac = ', kzm_over_kvac)
        print('Wavelength / (Vacuum wavelength) = ', 1/(kx_over_kvac.real))
        if kx_over_kvac.imag != 0:
            print('(Decay length) / (Vacuum wavelength) = ', 1/(kx_over_kvac.imag))
        else:
            print('Wave does not decay, it propagates forever.')
        print('(Decay length into dielectric) / (Vacuum wavelength) = ', 1/(kzd_over_kvac.imag))
        print('(Decay length into metal) / (Vacuum wavelength) = ', -1/(kzm_over_kvac.imag))
   
    if z_times_kvac > 0:
        # dielectric
        Ez = exp(1j * kx_over_kvac * x_times_kvac + 1j * kzd_over_kvac * z_times_kvac - 1j * t_times_omega)
        Ex = -Ez * kzd_over_kvac / kx_over_kvac
    else:
        # metal
        Ez = (kzd_over_kvac / kzm_over_kvac) * exp(
                 1j * kx_over_kvac * x_times_kvac + 1j * kzm_over_kvac * z_times_kvac - 1j * t_times_omega)
        Ex = -Ez * kzm_over_kvac / kx_over_kvac
    return (Ex.real, Ez.real)

# --- PART 2 OF 2: DRAWING --- #

def draw_box(x1, x2, y1, y2, color):
    """
    Code to draw a rectangular box in matplotlib ... used to color the metal area.
    See http://matplotlib.org/users/path_tutorial.html
    """
    vertices = [ (x1, y1), (x1, y2), (x2, y2), (x2, y1), (x1, y1)]
    codes = [Path.MOVETO,Path.LINETO,Path.LINETO,Path.LINETO,Path.CLOSEPOLY]
    path = Path(vertices, codes)
    #lw=0 means no outline; zorder=-1 means it shouldn't block the arrows.
    return patches.PathPatch(path, facecolor=color, lw=0, zorder=-1)

def draw_frame(t_times_omega, eps_m, eps_d, aspect_ratio=1.5,
               frac_metal=0.5, fig_width_px=480, x_range_times_kvac=2,
               img_filename=None):
    """
    Draw one frame of the animation.
    
    Inputs:
      * t_times_omega is time multiplied by angular frequency,
          it goes 0 --> 2pi each cycle.
      * eps_m and eps_d are the dielectric constants of the metal and dielectric
      * aspect_ratio is width over height
      * frac_metal is how much of the image is taken up by the metal.
      * fig_width_px is figure width in pixels
      * x_range_times_kvac is the width of the image as a multiple of kvac.
      * "img_filename" is what to save the frame as (or None to not save it).
    """
    # Figure geometry...
    fig_height_px = fig_width_px // aspect_ratio
    dpi = 80 #This number doesn't affect the final animation...
    fig_width_inches = fig_width_px / dpi
    fig_height_inches = fig_height_px / dpi
    
    # Coordinate limits in figure. All are implicitly multiplied by kvac.
    z_range_times_kvac = x_range_times_kvac / aspect_ratio
    xmin = 0
    xmax = x_range_times_kvac
    zmin = -z_range_times_kvac * frac_metal
    zmax = z_range_times_kvac * (1-frac_metal)
    
    # How many arrows to draw?
    num_arrows_x = 15
    num_arrows_z = num_arrows_x // aspect_ratio
    
    # Pick arrow coordinates...
    arrow_x_list, spacing = np.linspace(xmin, xmax, num=num_arrows_x,
                                     endpoint=False, retstep=True)
    arrow_x_list += spacing / 2
    
    arrow_z_list, spacing = np.linspace(zmin, zmax, num=num_arrows_z,
                                     endpoint=False, retstep=True)
    arrow_z_list += spacing / 2

    X,Z = np.meshgrid(arrow_x_list, arrow_z_list)
    
    # Arrow length scale: Larger number = smaller arrows
    arrow_len_scale = 15
    
    # Calculate the length of each arrow
    Ex_func = np.vectorize(lambda x,z : Efield(x,z,t_times_omega,eps_m,eps_d)[0])
    Ex_array = Ex_func(X, Z)
    Ez_func = np.vectorize(lambda x,z : Efield(x,z,t_times_omega,eps_m,eps_d)[1])
    Ez_array = Ez_func(X, Z)
    
    # Open a new figure with correct aspect ratio and pixel count and white background
    fig = plt.figure(figsize = (fig_width_inches,fig_height_inches), dpi=dpi, facecolor='w')
    
    # Draw a new set of axes that fill the entire figure area
    ax=fig.add_axes((0,0,1,1),axisbg='w')
    ax.set_axis_off()
    
    # Color the metal part
    metal_color = '#dddddd' #light gray
    ax.add_patch(draw_box(xmin,xmax,zmin,0,metal_color))
    
    # Draw the arrows
    ax.quiver(X, Z, Ex_array , Ez_array , scale=arrow_len_scale, scale_units='width', pivot='middle')
    
    ax.set_xlim(xmin, xmax)
    ax.set_ylim(zmin, zmax)
    if img_filename is not None:
        fig.savefig(os.path.join(directory_now, img_filename), dpi=dpi)
 
def draw_anim(eps_m, eps_d, anim_filename='anim.gif', frames_in_anim=30,
              total_anim_time_in_sec=2, keep_frame_images=False, **kwargs):
    """
    Create an animated GIF. **kwargs are all the keyword arguments to
    draw_frame()
    
    keep_frame_images=True to save the individual frame image files that make
    up the animation; otherwise they are created and immediately deleted.
    """
    filename_list = ['temp' + str(n) + '.png' for n in range(frames_in_anim)]
    
    for n in range(frames_in_anim):
        draw_frame(2*pi*n/frames_in_anim, eps_m, eps_d,
                   img_filename=filename_list[n], **kwargs)
    
    seconds_per_frame = total_anim_time_in_sec / frames_in_anim
    frame_delay = str(seconds_per_frame * 100)
    command_list = ['convert', '-delay', frame_delay, '-loop', '0'] + filename_list + [anim_filename]
    # Use the "convert" command (part of ImageMagick) to build the animation
    subprocess.call(command_list, cwd=directory_now)
    if keep_frame_images is False:
        for filename in filename_list:
            os.remove(os.path.join(directory_now, filename))

###################################################################

if True:
    # Silver-air interface at 370nm, using data from Palik
    eps_m = -2.62 + 0.626j
    eps_d = 1
    # Print diagnostics
    Efield(0, 0, 0, eps_m, eps_d, print_wave_properties=True)
    # Create animation
    draw_anim(eps_m, eps_d, anim_filename='Silver_370nm_Palik.gif')

キャプション

このファイルの内容を1行で記述してください

このファイルに描写されている項目

題材

2 12 2013

ファイルの履歴

過去の版のファイルを表示するには、その版の日時をクリックしてください。

日付と時刻サムネイル寸法利用者コメント
現在の版2013年12月2日 (月) 22:062013年12月2日 (月) 22:06時点における版のサムネイル480 × 320 (475キロバイト)Sbyrnes321User created page with UploadWizard

以下のページがこのファイルを使用しています:

グローバルなファイル使用状況

以下に挙げる他のウィキがこの画像を使っています: