-
Notifications
You must be signed in to change notification settings - Fork 12
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
Use spline surface fitting for in-vessel component CAD generation #171
base: main
Are you sure you want to change the base?
Conversation
I'd just like to mention that I started using this this weekend and have found it to be very useful, thanks @connoramoreno |
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.
A few minor changes, I think. Do we need to update examples, as well?
Will the change in interface break all the old parastell usage?
"""if self.radial_build.toroidal_angles[0] >= 0.0: | ||
toroidal_angle = (toroidal_angle + 2 * np.pi) % (2 * np.pi)""" |
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.
Do we need this? Seems like we might want it, in general?
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 I meant to delete that commented code block. In my local version of this branch (yet to be pushed) I created a utility function to check whether an input value is within a given range, accounting for a periodic domain. That function removes the need to ensure that angles are positive.
edge_list = [ | ||
edge | ||
for edge in outer_surface.Edges() | ||
if self._check_edge(edge) | ||
] | ||
wire_list = [cq.Wire.assembleEdges([edge]) for edge in edge_list] |
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.
Can't we just combine these? I don't see edge_list
used elsewhere:
edge_list = [ | |
edge | |
for edge in outer_surface.Edges() | |
if self._check_edge(edge) | |
] | |
wire_list = [cq.Wire.assembleEdges([edge]) for edge in edge_list] | |
wire_list = [cq.Wire.assembleEdges([edge]) for edge in outer_surface.Edges() | |
if self._check_edge(edge)] |
@@ -460,8 +446,11 @@ def _vmec2xyz(self, poloidal_offset=0): | |||
""" | |||
return self.scale * np.array( | |||
[ | |||
self.vmec_obj.vmec2xyz(self.s, theta, self.phi) | |||
for theta in (self.theta_list + poloidal_offset) | |||
[ |
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.
Need to update the docstring to match this new behavior
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'll be rolling this branch back a bit to preserve our lofting functionality, instead adding this spline surface capability as an additional feature. That will involve restoring the Rib
class and this method will maintain its old behavior.
@@ -619,14 +620,15 @@ def poloidal_angles(self, angle_list): | |||
self._logger.error(e.args[0]) | |||
raise e | |||
|
|||
self._poloidal_angles = angle_list | |||
if self._poloidal_angles[-1] - self._poloidal_angles[0] > 360.0: | |||
if angle_list[-1] - angle_list[0] != 360.0: |
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.
Exactly equal in floating point math is tricky.
Should we check that these are close and then move one to make them exact if they are close, or make an error if they aren't close?
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 point. I think as long as they're close (within a reasonably small tolerance) it's fine. We should raise the error if they're not close.
Overview
Modifies the in-vessel component CAD generation workflow to use CadQuery’s spline surface fitting routine, instead of its lofting routine, to define the outer surfaces of each in-vessel component (IVC). The benefits of this change are several-fold:
List of changes in branch:
Surface.generate_surface
method to use CadQuery’sFace.makeSplineApprox
surface spline technique instead of itsSolid.makeLoft
routineInVesselBuild.generate_components
method to construct CAD solids by assembling necessary surfaces, instead of performing a cut operationInVesselBuild._check_edge
methodRib
class and moves any necessary methods to theSurface
classnum_ribs
andnum_rib_pts
parameters due to removal ofRib
classrepeat
parametertranspose_fit
, which is a flag to indicate that the 2-D iterable of points through which each spline surface is fit should be transposed. This swaps the order in which the grid axes are iterated over. For a yet-to-be-understood reason, this can fix errant CAD generation.min_mesh_size
andmax_mesh_size
arguments to theInVesselBuild.export_cad_to_dagmc
methodutils.normalize
function to allow 3-D NumPy arraysIssues to be solved:
Closes #26
Closes #170
Illustration of new CAD generation workflow:
Figure 1. Create separate surfaces for outer surface and end caps (plasma/chamber).
Figure 2. Combine surfaces into single solid (plasma/chamber).
Figure 3. Create separate surfaces for inner surface (outer surface of interior component), outer surface, and end caps.
Figure 4. Combine surfaces into single solid.
Demonstration of new capabilities:
Figure 5. 360-degree geometry.
Figure 6. 360-degree geometry (cut at mid-plane, visualized in ParaView).
Figure 7. In-vessel build with thickness matrix of component defined as
200 * numpy.random.rand(9, 9)
.