-
Notifications
You must be signed in to change notification settings - Fork 0
Add tests for gradient check of affine transformations #1
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Getting there! I noticed some weird formatting in these files, did you install the pre-commit hook and did you run the autoformatter (ruff) on your code before committing? There is some weird indentation, I'm actually surprised it runs at all.
Regarding comments and docstrings: This is already pretty good! Note though that the lowest level of indentation should be aligned with the quotes, i.e. instead of
"""
docstring
"""
it should rather look like
"""
docstring
"""
Also for tests, it is generally enough if there is only a short docstring that explains what the test does, a full docstring like in the official docs with all parameters and types is generally not necessary (not bad either though).
@@ -21,6 +21,7 @@ | |||
from tidy3d.components.autograd.utils import is_tidy_box | |||
from tidy3d.components.data.data_array import DataArray | |||
from tidy3d.plugins.polyslab import ComplexPolySlab | |||
import tidy3d.components.geometry.polyslab as polyslab |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for this import, polyslab is available as td.PolySlab
@pytest.fixture | ||
def create_polyslab()-> polyslab.PolySlab: | ||
""" | ||
Creates a PolySlab instance for testing affine transformations. | ||
|
||
Returns | ||
------- | ||
polyslab.PolySlab | ||
An instance of PolySlab with predefined vertices, axis, and slab bounds. | ||
""" | ||
vertices = np.array([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0]]) | ||
axis = 1 # 0 for x, 1 for y, 2 for z | ||
slab_bounds = (-1.0, 1.0) | ||
|
||
return polyslab.PolySlab(vertices=vertices, axis=axis, slab_bounds=slab_bounds) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good use of a fixture!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid the use of verbs like create_
in fixture names though, since they will be used implicitly as arguments. So just polyslab
would be good here.
create_polyslab : polyslab.PolySlab | ||
The PolySlab object created using pytest fixture. | ||
""" | ||
poly = create_polyslab |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to fixture name, this is a bit awkward.
The PolySlab object created using pytest fixture. | ||
""" | ||
poly = create_polyslab | ||
x, y, z = 0.1, 0.2, 0.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ideally this test would be parametrized with a few different values for x, y, z
, specifically to check edge cases, see here for reference.
new_poly = poly.translated(x, y, z) | ||
return new_poly.vertices | ||
|
||
for name in ["x", "y", "z"]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no need for the for loop here. Just explicitly check each case.
tests/test_components/test_medium.py
Outdated
@@ -464,7 +464,7 @@ def test_rotation(): | |||
axis = np.random.random(3) | |||
rot = td.RotationAroundAxis(axis=tuple(axis), angle=1.23) | |||
|
|||
R = rot.matrix | |||
R = rot.matrix() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah this is not ok, you are changing the behavior of tidy3d classes globally, i.e. you are changing the interface. Do not modify existing tests to make them pass. Fix your code instead so that they pass ;)
The tests are there for a reason.
tidy3d/components/geometry/base.py
Outdated
@@ -2792,7 +2792,7 @@ def rotation(angle: float, axis: Union[Axis, Coordinate]) -> MatrixReal4x4: | |||
Transform matrix with shape (4, 4). | |||
""" | |||
transform = np.eye(4) | |||
transform[:3, :3] = RotationAroundAxis(angle=angle, axis=axis).matrix | |||
transform[:3, :3] = RotationAroundAxis(angle=angle, axis=axis).matrix() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
tidy3d/components/transformation.py
Outdated
@abstractmethod | ||
def matrix(self) -> TensorReal: | ||
"""Rotation matrix.""" | ||
|
||
@cached_property | ||
@abstractmethod | ||
def isidentity(self) -> bool: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if you remove the caching, these still need to be properties.
tidy3d/components/transformation.py
Outdated
def isidentity(self) -> bool: | ||
"""Check whether rotation is identity.""" | ||
|
||
return np.isclose(self.angle % (2 * np.pi), 0) | ||
|
||
@cached_property | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, need to stay properties.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is starting to look pretty good :)
One thing regarding test naming: Try to make the names of your tests mirror what they are testing, this is generally an unspoken convention. So instead of test_translation_grad
, name it test_translated_grad
since you are testing PolySlab.translated
. In the same vein, we are actually only testing PolySlab
here. What if we start testing Box
and Cylinder
too? It'll be cleaner to make the test name more specific then, e.g. test_polyslab_translated_grad
, etc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking great! Only had some minor comments.
[ | ||
(0.0, 0.0, 0.0, True), # No scaling | ||
(0.1, 0.2, 0.3, False), # Small positive values | ||
(-0.1, -0.2, -0.3, True), # Small negative values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(0.0, 0, True), # No rotation around x-axis | ||
(np.pi / 6, 1, False), # Small rotation around y-axis | ||
(-np.pi / 4, 2, True), # Rotation around z-axis | ||
(np.pi / 4, 1, False), # 90-degree rotation around y-axis | ||
(np.pi, 1, False), # 180-degree rotation around y-axis |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this really only comes down to whether or not we are rotating around the polyslab's axis
, so might be better to just check whether we are rotating around that or not?
if not hasattr(new_poly, "vertices"): | ||
raise ValueError("Rotation resulted in a non-differentiable Transformed object.") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not necessary, since check_grads
will raise an exception if differentiating through Transformed
, so no need to raise one here.
K = np.array([[0, -n[2], n[1]], [n[2], 0, -n[0]], [-n[1], n[0], 0]]) | ||
R = np.eye(3) + s * K + (1 - c) * K @ K |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! This is much cleaner than before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok overall this is looking great! I think we can try to move this into the main repo.
Running pytest test_autograd.py caused errors:
This created issue as we don't want @cached_property, then we must explicitly call matrix() when using it. Same goes for self.isidentity(). Made the fixes in [/geometry/base](https://github.com/rahul-flex/tidy3d/blob/rahul-flex/diff-transformations/tidy3d/components/geometry/base.py#L2795C1-L2795C78) file.
Now after running all the tests, got 9 errors: