Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Normalize eigenmode source to unit power #728

Merged

Conversation

HomerReid
Copy link
Contributor

Another stab at #470.

@HomerReid
Copy link
Contributor Author

I will add a test to verify functionality.

python/source.py Outdated
@@ -107,6 +109,10 @@ def __init__(self,
self.eig_resolution = eig_resolution
self.eig_tolerance = eig_tolerance

@eig_tolerance.setter
def eig_tolerance(self, val):
self._eig_tolerance = check_positive('EigenModeSource.eig_tolerance', val)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method seems to be duplicate of line 158.

@HomerReid
Copy link
Contributor Author

Updated hard-coded comparison values for some python tests to accommodate revised normalization of eigenmode sources.

Augmented python/tests/mode_coeffs.py to add unit test for unit-power normalization of eigenmode sources. For an eigenmode source in an unperturbed waveguide section with a flux monitor placed downstream from the source, the test computes the observed power flux through the monitor and compares with the predictions of the eig_power() method in the EigenmodeSource class. Results look like this:

expectedvsobservedfluxforeigsource

I am not sure what is up with what appears to be a slight systematic offset between the curves. Maybe I misunderstand MEEP's conventions for the definition of frequency ranges. For the time being, the agreement at the center frequency is good and I have written the unit test to look at that.

##################################################
if nf>1:
power_observed=mp.get_fluxes(mode_flux)
freqs=[mode_flux.freq_min + n*mode_flux.dfreq for n in range(len(power_observed))]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of computing freqs manually, you can use the built-in routine get_flux_freqs:

freqs=mp.get_flux_freqs(mode_flux)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to this, and it now seems clear that the observed DFT data need to be plotted with a leftward shift of 0.001 (i.e. one-half the spacing between X tics) to fall correctly on top of the predicted data. In particular, the maximum entry in the 51-element flux() array computed for the DFT cell is not the entry in cell #26, i.e. the exact middle of the array, but rather for cell #27, corresponding to a frequency slightly beyond the center frequency. I don't know what that is about.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is because get_flux_freqs is based on Numpy's linspace and is using endpoint=False:

def get_flux_freqs(f):
    return np.linspace(f.freq_min, f.freq_min + f.dfreq * f.Nfreq, num=f.Nfreq, endpoint=False).tolist()

Thus for an odd number of frequency bins, the center frequency will not be fcen and will not be the middle element of the freqs array (e.g., the 26th element of the 51-element array). Rather, the center frequency will be the element adjacent to the middle element (e.g., the 27th element of the 51-element array). For reference, this is demonstrated below.

>>> import numpy as np
>>> fcen = 0.20; df = 0.5*fcen; nfreq = 51;
>>> fmax = fcen+0.5*df; fmin = fcen-0.5*df;
>>> dfreq = (fmax-fmin)/(nfreq-1);
>>> freqs = np.linspace(fmin, fmin+dfreq*nfreq, num=nfreq, endpoint=False);
>>> print("26th element: {}".format(freqs[25]))
26th element: 0.2
>>> print("27th element: {}".format(freqs[26]))
27th element: 0.202

The size of the frequency spacing (i.e. dfreq from above) is defined in fields::add_dft.

@oskooi
Copy link
Collaborator

oskooi commented Feb 26, 2019

From the Travis CI logs: test_eigensource_normalization of python/tests/mode_coeffs.py is failing.

FAIL: test_eigensource_normalization (__main__.TestModeCoeffs)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "../../../python/tests/mode_coeffs.py", line 131, in test_eigensource_normalization
    self.assertAlmostEqual(max(p_exp),max(p_obs),places=1)
AssertionError: 100.0 != 100.91659498273228 within 1 places

This is the output of Travis' python/test-suite.log. If it is not visible, it is because the last "triangle" in the left column is facing rightwards (which means it is collapsed); you need to click on it so that it points downwards in order to uncollapse and view the file.

@HomerReid
Copy link
Contributor Author

I think this is a bug in the unittest.TestCase.assertAlmostEqual, since the two numbers here are clearly in agreement to one decimal place. Actually with the updated eigenmode source amplitude this bug was causing the oblique_source test to fail too, for a similar reason. I fixed that one last night but didn't realize it was affecting mode_coeffs also.

power_observed=mp.get_fluxes(mode_flux)
freqs=mp.get_flux_freqs(mode_flux)
power_expected=[source.eig_power(f) for f in freqs]
import ipdb; ipdb.set_trace()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Travis is failing because of this line which should be removed (since it is presumably from debugging?).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad.

@stevengj stevengj merged commit 4a4f4f1 into NanoComp:master Feb 28, 2019
@oskooi oskooi mentioned this pull request Jun 21, 2019
bencbartlett pushed a commit to bencbartlett/meep that referenced this pull request Sep 9, 2021
* add --without-scheme option to configure to bypass building the scheme interface

* revised normalization of eigenmode sources to yield unit power flux (in the CW case); added discussion to FAQ section of documentation

* updates

* update FAQ entry regarding normalization of eigenmode sources

* updates

* updates

* added eig_power() method to EigenmodeSource class in python

* updates

* updates

* updates

* updates

* updates

* updates

* augmented mode_coeffs.py unit test to check normalization of eigenmode sources

* updates

* updates

* move docs from FAQ to manual, change fourier_transform to take f and not omega

* delete blank line

* tweak
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants