victorliu / S4

Stanford Stratified Structure Solver - Electromagnetic simulator for layered periodic structures
http://www.stanford.edu/group/fan/S4/
GNU General Public License v2.0
133 stars 151 forks source link

Unclear documentation for GetFieldsOnGrid method #94

Open JamesWhitehead5 opened 3 years ago

JamesWhitehead5 commented 3 years ago

Issue

When testing a simulation with a non-zero polar angle of the excitation planewave of a single "vacuum" layer, the returned field from calling the GetFieldsOnGrid is spatially uniform in magnitude and phase. (Tested on the current OSX lua binary and an old python api compiled from source)

However, sampling the field on a grid (that is normal to the z axis) using the GetFields method yields the expected results for a plane wave incident at an angle.

A possible explanation is that GetFieldsOnGrid returns the field parallel to the incident plane wave. If this were the case, then the documentation does not reflect this.

Replication of issue (Python2.7)

import S4
import matplotlib.pyplot as plt
import numpy as np

def setup_simulation(period, wavelength, layer_thickness):
    simulation = S4.New(Lattice=((period, 0.), (0., period)), NumBasis=100) #setup lattice
    simulation.SetMaterial(Name='vacuum', Epsilon=complex(1.)) # create material
    simulation.AddLayer(Name='buffer_top', Thickness=layer_thickness, Material='vacuum') #add layer

    simulation.SetExcitationPlanewave(
        IncidenceAngles=(30., 0.), # polar angle is non-normal
        sAmplitude=0.,
        pAmplitude=1.,
        Order = 0,
    )
    simulation.SetFrequency(1./wavelength)
    return simulation

def get_fields_on_grid_default_method(simulation, n_samples):
    """Uses the GetFieldsOnGrid method to get the grid"""
    electric_field, _ = simulation.GetFieldsOnGrid(z=0., NumSamples=(n_samples, n_samples), Format='Array')
    electric_field = np.array(electric_field)
    electric_field_x_component = electric_field[:, :, 0]
    return electric_field_x_component

def get_fields_on_grid_sample_method(simulation, n_samples, period):
    """Uses the GetFields method to get the grid"""
    x = np.linspace(-period/2, period/2, n_samples)
    X, Y = np.meshgrid(x, x)

    def getExField(x, y, z):
        """
        x, y, z are floats where the field should be measured
        Returns the x componenet of the electric field at point (x, y, z)
        """
        electric_field, _ = simulation.GetFields(x, y, z)
        electric_field_x_component, _, _ = electric_field
        return electric_field_x_component

    # allows us to pass a numpy.array as argument so we don't have to loop over each element
    get_electric_field_x_component = np.vectorize(getExField) 

    electric_field_x_component = get_electric_field_x_component(X, Y, z=0)
    return electric_field_x_component

def plot_mag_phase(scalar_field, title):
    fig, (ax1, ax2) = plt.subplots(1, 2)
    fig.suptitle(title)

    plot1 = ax1.imshow(np.abs(scalar_field))
    ax1.set_title("Mag")
    fig.colorbar(plot1, ax=ax1)

    plot2 = ax2.imshow(np.angle(scalar_field))
    ax2.set_title("Phase")
    fig.colorbar(plot2, ax=ax2)

    plt.show()

if __name__ == '__main__':
    n_samples = 50
    period = 1.
    simulation = setup_simulation(period, wavelength=1., layer_thickness=1.)

    fields_on_grid_default_method = get_fields_on_grid_default_method(simulation, n_samples)
    fields_on_grid_sample_method = get_fields_on_grid_sample_method(simulation, n_samples, period)

    plot_mag_phase(fields_on_grid_default_method,"fields_on_grid_default_method")
    plot_mag_phase(fields_on_grid_sample_method,"fields_on_grid_sample_method")

Solution

If this behavior is intended, then adding documentation to the API entry GetFieldsOnGrid would fix this issue.

kwrobert commented 3 years ago

Hi there!

Unfortunately, I think this is actually a bug in the GetFieldsOnGrid method. Long ago, during my masters degree, I recall running into the same issue you're seeing here (a symptom of which is, the z-components of the field come out wrong for anything not normally incident). I fixed it while I was using this code. Nowadays, I think this fork of S4 is the most actively maintained fork by brilliant scientists who share their work openly.

I recommend using that fork. It's been modernized and cleaned up a lot.

Hope that helps!