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

broadband source feature #534

Merged
merged 2 commits into from
Oct 14, 2022
Merged

Conversation

dbochkov-flexcompute
Copy link
Contributor

frontend part of broadband sources

Copy link
Collaborator

@momchil-flex momchil-flex left a comment

Choose a reason for hiding this comment

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

This looks good overall, but I'd like for @tylerflex to have a look if it makes sense too.

Comment on lines 485 to 488
def map_frequencies(self, freq_grid) -> np.ndarray:
"""Map frequency values into (-1,1) interval."""
fmin, fmax = self.source_time.frequency_range(4)
return (freq_grid - 0.5 * (fmin + fmax)) / (0.5 * (fmax - fmin))
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's just move this to the backend; put it in source.py as a standalone function for now, after this is merged I will do the change of implementing BackendSource types and will include it there.

tidy3d/components/source.py Show resolved Hide resolved
@tylerflex tylerflex self-requested a review October 5, 2022 06:20
class BroadbandSource(Source, ABC):
"""A source with frequency dependent field distributions."""

num_freqs: pydantic.NonNegativeInt = pydantic.Field(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this rather be pydantic.PositiveInt? What happens if the num_freqs = 0?

def frequency_grid(self) -> np.ndarray:
"""A Chebyshev grid used to approximate frequency dependence."""
fmin, fmax = self.source_time.frequency_range(4)
return 0.5 * (fmin + fmax) + 0.5 * (fmax - fmin) * np.cos(
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we could make this more readable by splitting it over a few lines and assigning some intermediate variables, for example:

f_add = 0.5 * (fmin + fmax)
f_diff = 0.5 * (fmax - fmin)
f_range = (2 * np.flip(np.arange(self.num_freqs)) + 1) / self.num_freqs
return f_add + f_diff * np.cos(0.5 * np.pi * f_range)

or something like this (double check..)


def map_frequencies(self, freq_grid) -> np.ndarray:
"""Map frequency values into (-1,1) interval."""
fmin, fmax = self.source_time.frequency_range(4)
Copy link
Collaborator

Choose a reason for hiding this comment

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

can we add the keyword argument explicitly? Ie

fmin, fmax = self.source_time.frequency_range(num_fwidth=4)

I had to look up what frequency_range accepted because I forgot, doing it this way will make it a bit more readable. (note that 4 is the default value, so alternatively we could just remove the argument here)

Copy link
Collaborator

@tylerflex tylerflex left a comment

Choose a reason for hiding this comment

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

Looks good overall. Please add some front end tests as well.
In tests/test_components/test_source.py, we should add a test where each of the broadband sources are initialized with some num_freqs > 1 and then call these new methods map_frequencies and frequency_grid and make sure they work as expected. If you can think of other things to test (not involving any backend), feel free to add them as well. Thanks!

@tylerflex tylerflex self-requested a review October 10, 2022 14:52
Copy link
Collaborator

@tylerflex tylerflex left a comment

Choose a reason for hiding this comment

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

Thanks for adding the test and refactoring that method, looks great!

@dbochkov-flexcompute dbochkov-flexcompute force-pushed the daniil/broadband-source branch 3 times, most recently from 4584a7e to aec5698 Compare October 10, 2022 17:51
@momchil-flex
Copy link
Collaborator

momchil-flex commented Oct 10, 2022

I think we should take some care to prevent a naive user from specifying way too high num_freqs, which could make it slow to compute all modes. Some suggestions:

  • Add an explanation to the description of the num_freqs field that Chebyshev decomposition is used which can approximate weakly-varying functions very well with a small number of points.
  • Limit num_freqs to e.g. 100.
  • Add a warning if the user sets e.g. num_freqs > 20, saying that num_freqs > 20 is not needed unless very sharp dependence of the mode profiles on frequency is expected.

What do you think?

@dbochkov-flexcompute
Copy link
Contributor Author

I think we should take some care to prevent a naive user from specifying way too high num_freqs, which could make it slow to compute all modes. Some suggestions:

  • Add an explanation to the description of the num_freqs field that Chebyshev decomposition is used which can approximate weakly-varying functions very well with a small number of points.
  • Limit num_freqs to e.g. 100.
  • Add a warning if the user sets e.g. num_freqs > 20, saying that num_freqs > 20 is not needed unless very sharp dependence of the mode profiles on frequency is expected.

What do you think?

I think that's a great suggestion, will add all of that

@momchil-flex
Copy link
Collaborator

Great, for point 2 you can directly add 'le' to the field initialization https://pydantic-docs.helpmanual.io/usage/schema/#field-customization

For 3 you'd need a small custom validator, have a look at other components if you haven't seen those in action yet.

@dbochkov-flexcompute dbochkov-flexcompute force-pushed the daniil/broadband-source branch 2 times, most recently from ab4dbef to 87ce649 Compare October 12, 2022 23:48
@@ -151,3 +151,81 @@ def get_pol_dir(axis, pol_angle=0, angle_theta=0, angle_phi=0):
assert np.allclose(
get_pol_dir(axis=2, angle_theta=np.pi / 4), (-1 / np.sqrt(2), 0, +1 / np.sqrt(2))
)


def test_BroadbandSource():
Copy link
Collaborator

Choose a reason for hiding this comment

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

Sorry, very nitpicky, but the style we follow in python is snake_case for functions and CamelCase for class names only, so this would be test_broadband_source

Copy link
Contributor Author

Choose a reason for hiding this comment

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

sounds good, I guess I was just following test_FieldSource() and test_UniformCurrentSource()

if val >= 20:
logging.warning(
f"A large number ({val}) of frequency points is used in a broadband source. "
"It is expected that less than 20 points is typically sufficient."
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also nitpicky, but I suggest slightly different wording, something like "A large number ({val}) of frequency points is used in a broadband source. This can slow down simulation time and is only needed if the mode fields are expected to have a very sharp frequency dependence. 'num_freqs' < 20 is sufficient in most cases."

@dbochkov-flexcompute dbochkov-flexcompute merged commit dabec37 into develop Oct 14, 2022
@tylerflex tylerflex deleted the daniil/broadband-source branch May 16, 2023 14:21
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