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

Add adaptive scientific notation for frequency range #2196

Merged

Conversation

rahul-flex
Copy link
Contributor

As discussed with @tomflexcompute we want to include as many significant digits as possible, provided the two numbers (frequency range: fmin_med and fmax_med) remain identical up to that point.
Once a differing digit is encountered, the output rounds off subsequent digits.
Also, the function returns the min and max values with same exponent.

Below are few test examples:
inputs are fmin_med and fmax_med

`Input: 1234567.56, 1234577.34
Output: 1.23457e6, 1.23458e6

Input: 1234567.56, 211234577.34
Output: 1e6, 211e6

Input: 1234567, 1934577
Output: 1e6, 2e6

Input: 1234567, 1284577
Output: 1.2e6, 1.3e6

Input: 123, 128
Output: 1.2e2, 1.3e2

Input: 0.00123, 0.00128
Output: 1.2e-3, 1.3e-3

Input: 0, 10
Output: 0e+00, 1e+01

Input: 123456789012345, 123456789012346
Output: 1.23456789012345e14, 1.23456789012346e14`

@tomflexcompute
Copy link
Contributor

@rahul-flex actually I think we should at least display a certain number of digitals like 5 for example. Since in most materials, the f_min and f_max differ in the first significant digital already. Could you test it on the test model and see how the output warning looks like?

@rahul-flex
Copy link
Contributor Author

@tomflexcompute The warning message for the test setup you provided looks like this:

18:15:58 EST WARNING: The medium associated with structures[0] has a frequency  
range: (1e12, 250e12) (Hz) that does not fully cover the           
frequencies contained in monitors[0]. This can cause inaccuracies  
in the recorded results. 

@rahul-flex rahul-flex marked this pull request as ready for review January 22, 2025 23:36
@tomflexcompute
Copy link
Contributor

Yeah I think we do need more significant digitals otherwise the numbers are too crude.

Fyi this pr is to address #1086

@@ -2805,6 +2805,34 @@ def warn(istruct, side):

return val

def _scientific_notation(fmin_med: float, fmax_med: float) -> Tuple[str, str]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I guess this shouldn't be a Simulation level method. Maybe Tidy3dBaseModel? Let's also change the variable names to not specifically refer to frequency, more like min_val, max_val? And then regarding @tomflexcompute's point, add an extra argument like min_digits=4? Looking at the code it seems that this number would refer not to the total number of significant digits, but to the digits after the decimal, e.g. 1.1234e12 to 250.1234e12 right? I think that's fine.

Copy link
Collaborator

Choose a reason for hiding this comment

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

agree with Tidy3dBaseModel (here). also decorate this with a staticmethod and change the below calls to self._scientific_notation instead of cls._scientific_notation, otherwise this will error when called on a class instance.

Copy link
Collaborator

@yaugenst-flex yaugenst-flex left a comment

Choose a reason for hiding this comment

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

Thanks @rahul-flex this looks pretty good overall. Don't forget to add a unit test and a changelog entry though, this is a nicely testable function.

@@ -2805,6 +2805,34 @@ def warn(istruct, side):

return val

def _scientific_notation(fmin_med: float, fmax_med: float) -> Tuple[str, str]:
Copy link
Collaborator

Choose a reason for hiding this comment

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

agree with Tidy3dBaseModel (here). also decorate this with a staticmethod and change the below calls to self._scientific_notation instead of cls._scientific_notation, otherwise this will error when called on a class instance.

Comment on lines 2828 to 2829
while round(normalized_fmin, precision) == round(normalized_fmax, precision):
precision += 1
Copy link
Collaborator

Choose a reason for hiding this comment

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

Edge case: this will cause an infinite loop if normalized_fmin == normalized_fmax. Not very likely to happen, but should be handled

Copy link

@rahul-flex
Copy link
Contributor Author

Thanks, @momchil-flex, @tomflexcompute, and @yaugenst-flex for the review comments. I have updated the function and added test cases.
@momchil-flex Yes, the min_digits refers to the digits after the decimal in scientific notation.

Copy link
Contributor

@tomflexcompute tomflexcompute left a comment

Choose a reason for hiding this comment

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

Thanks @rahul-flex I think it should work very well.

Copy link
Collaborator

@yaugenst-flex yaugenst-flex left a comment

Choose a reason for hiding this comment

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

Thanks @rahul-flex almost good to go :)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Thanks @rahul-flex the test is great, only request I have is could you turn this into a parameterized test instead? That makes them run as separate tests so it will be easier to debug in case something fails. Also note that you generally don't need to add assertion messages in pytest because they are a bit redundant as you will get a summary of the failed tests and their parameters.

Here is how to convert to a parameterized test:

@pytest.mark.parametrize(
    "min_val, max_val, min_digits, expected",
    [
        (1234567, 1234577, 4, ("1.23457e6", "1.23458e6")),
        (1234567, 1234577, 6, ("1.234567e6", "1.234577e6")),
        (1.23e-3, 1.28e-3, 4, ("1.2300e-3", "1.2800e-3")),
        (123456789012345, 123456789012346, 4, ("1.23456789012345e14", "1.23456789012346e14")),
        (123656789012345, 123756789012346, 4, ("1.2366e14", "1.2376e14")),
        (123, 123, 4, ("1.2300e2", "1.2300e2")),
    ],
    ids=[
        "default_min_digits",
        "increased_min_digits",
        "small_numbers",
        "large_numbers_precise",
        "large_numbers_rounded",
        "identical_numbers"
    ]
)
def test_scientific_notation(min_val, max_val, min_digits, expected):
    """Test the _scientific_notation method with various inputs."""
    result = Tidy3dBaseModel._scientific_notation(min_val, max_val, min_digits=min_digits)
    assert result == expected

@@ -2833,6 +2833,10 @@ def _warn_monitor_mediums_frequency_range(cls, val, values):

# make sure medium frequency range includes all monitor frequencies
fmin_med, fmax_med = medium.frequency_range
sci_fmin_med, sci_fmax_med = Tidy3dBaseModel._scientific_notation(
Copy link
Collaborator

Choose a reason for hiding this comment

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

Simulation is a subclass of Tidy3dBaseModel, so just call self._scientific_notation() here

Copy link
Collaborator

@yaugenst-flex yaugenst-flex left a comment

Choose a reason for hiding this comment

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

Nice, looks great @rahul-flex!

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.

Looks good after small changelog comment, and eventually squashing all commits.

CHANGELOG.md Outdated
@@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [2.8.0rc1] - 2024-12-17

### Added
- Scientific notation for frequency range warnings.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This changelog item should be in Unreleased not in 2.8.0rc1. Also generally we tend to put new things at the bottom of the list (Added/Fixed/Changed), not at the top.

@rahul-flex rahul-flex force-pushed the rahul-flex/sci-notation branch from 132a8fc to 034ba05 Compare January 24, 2025 16:38
@yaugenst-flex yaugenst-flex merged commit 4b1ac96 into flexcompute:pre/2.8 Jan 24, 2025
13 checks passed
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