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

volume and surface areas for geometric primitives #473

Merged
merged 1 commit into from
Aug 25, 2022

Conversation

dbochkov-flexcompute
Copy link
Contributor

Calculation of volumes and surface areas (not always exact) for geometric primitives needed for better memory (see https://github.com/flexcompute/tidy3d-core/pull/130)

Comment on lines 514 to 550
@abstractmethod
def volume(self, bounds: Bound) -> float:
"""Returns object's volume. If the object extends beyound bounds then
the computed volume may be only a rough approximation

Returns
-------
float
Volume.
"""

@abstractmethod
def surface_area(self, bounds: Bound) -> float:
"""Returns object's surface area. If the object extends beyound bounds
then the computed area may be only a rough approximation

Returns
-------
float
Surface area.
"""

Copy link
Collaborator

@momchil-flex momchil-flex Aug 24, 2022

Choose a reason for hiding this comment

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

A docstring for the bounds parameter is missing.

Also, I feel like this should be an optional parameter, i.e. bounds: Bound = None. However, to implement this directly would require a lot of small changes/branching in the separate functions. One approach could be something like, in the geometry class:

    def volume(self, bounds: Bound = None):
        """Returns object's volume with optional bounds"""

        if not bounds:
            bounds = self.bounds

        return self._volume(bounds)
        
    @abstractmethod
    def _volume(self, bounds: Bound) -> float:
        """Returns object's volume given bounds."""

And then rename all subsequent methods to _volume. Same with surface. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that looks like a nice solution to me. Initially I decided not to worry about that since so many objects are used with td.inf dimension which would produce infinite outcome, so it seemed like a good idea just not to allow to call these functions without bounds

Copy link
Collaborator

Choose a reason for hiding this comment

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

Oh I see. That does make sense. When you put it this way I think it may be fine to leave as is, maybe just add the description of why bounds is needed in the docstring.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Another option is to set the default bounds to something like ((-LARGE_NUMBER, LARGE_NUMBER), (-LARGE_NUMBER, LARGE_NUMBER), (-LARGE_NUMBER, LARGE_NUMBER)). Because I think in many cases what I proposed will not return inf if there's an infinite dimension and bounds are not specified, it will just error out (numpy errors if you try math operations with np.inf).

Copy link
Collaborator

Choose a reason for hiding this comment

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

One thing that might clean things up just a bit is defining a method in Geometry:

def bounds_intersect(self, bounds: Bound) -> Bound:
    """Find the bounds intersecting the object's bounds with some supplied bounds."""
    rmin = tuple(max(c, c_) for c, c_ in zip(self.bounds[0], bounds[0]))
    rmax = tuple(min(c, c_) for c, c_ in zip(self.bounds[1], bounds[1]))
    return rmin, rmax

that can find the "intersection" between the instance bounds and some supplied bounds. Optionally, bounds could default to LARGE_NUMBERs

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, just:

  1. make sure to format the docstrings similar to the other methods
  2. iterate over range(3) instead of (0,1,2).
  3. Consider the more complex formulas for the spherical / cylindrical volume if it is useful, feel free to ignore though. Thanks!

@abstractmethod
def volume(self, bounds: Bound) -> float:
"""Returns object's volume. If the object extends beyound bounds then
the computed volume may be only a rough approximation
Copy link
Collaborator

Choose a reason for hiding this comment

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

Period after the main text ("approximation.") and yea add Parameters section too please.

"""
volume = 1

for axis in (0, 1, 2):
Copy link
Collaborator

Choose a reason for hiding this comment

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

for axis in range(3):

is the standard way to do this in python. Please replace also where this occurs in the methods below.

"""
volume = 4.0 / 3.0 * np.pi * self.radius**3

# a very loose upper bound on how much of sphere is in bounds
Copy link
Collaborator

Choose a reason for hiding this comment

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

There's a formula for this, maybe we could use it here in some more simple cases? https://en.wikipedia.org/wiki/Spherical_cap

Volume.
"""

coord_min = self.center[self.axis] - self.length / 2.0
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 coord_min and coord_max are just self.bounds[0][self.axis] and self.bounds[1][self.axis] respectively?


volume = np.pi * self.radius**2 * length

# a very loose upper bound on how much of the cylinder is in bounds
Copy link
Collaborator

Choose a reason for hiding this comment

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

Think there's also a formula for this in the wiki page: https://en.wikipedia.org/wiki/Spherical_cap but if it's not of much importance, dont worry about it.

@dbochkov-flexcompute
Copy link
Contributor Author

  • Took Momchil's suggestion to use volume and _volume
  • fixed formatting and other comments
  • regarding using more accurate formulas: yeah, I thought about addressing special cases, but it seemed like there would be a lot of them, for example even for a sphere centered in a box it is not completely trivial (https://math.stackexchange.com/questions/2074785/volume-of-sphere-cube-intersection). So, given that these functions were meant to be used in some very approximate calculations and that we were not going to try to capture intersections between objects anyway I decided not to invest into something very complicated

@momchil-flex momchil-flex merged commit 9dd6ec5 into develop Aug 25, 2022
@momchil-flex momchil-flex deleted the daniil/dispersion-better-allocation branch August 25, 2022 21:26
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.

3 participants