-
Notifications
You must be signed in to change notification settings - Fork 56
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
Child FFD constraint tests and fixes #103
Conversation
Co-authored-by: Bernardo Pacini <[email protected]>
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 stuff, this test script was really messed up.
Take a look at my comments, I will re-check the final script tomorrow because it is hard to follow these big commits that move function blocks around
@@ -163,7 +186,11 @@ def c172_test_twist(self, DVGeo, DVCon, handler): | |||
# change the DVs | |||
xDV = DVGeo.getValues() | |||
xDV["twist"] = np.linspace(0, 10, self.nTwist) | |||
DVGeo.setDesignVars(xDV) | |||
if self.child: | |||
# Twist needs to be set on the parent FFD to get accurate derivatives |
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 can confirm this is the same approach I use, but is this documented anywhere? What is the reason behind this?
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 don't think it's documented anywhere mostly because manually setting design variables is not too common. This is not specific to twist actually. My understanding is that setDesignVars
should always be called on the parent, which will recursively set the DVs on all children. It just so happens that shape variables can be applied directly on a child FFD without causing issues. I can change the approach for all DVs to be consistent if you think that's clearer.
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 I think it makes sense to keep the shape with a different behaviour, as it is a localDV
instead of globalDV
. Can you just add a one-liner in setDesignVars
docstring?
handler.root_add_dict("funcs_deformed", funcs, rtol=1e-6, atol=1e-6) | ||
handler.root_add_dict("derivs_deformed", funcsSens, rtol=1e-6, atol=1e-6) | ||
return funcs, funcsSens | ||
|
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.
Is there a way to directly skip the class initialization down here? no biggie though
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.
Despite being outdated, I still refer to the RegTestGeograd
class
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.
You mean skip the class instead of each test if geograd is not installed? Yes, I think that's possible. I will change that.
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 don't think we do it in other repos, but if you find a way it could be nice. The initialization time for pyGeo is not that bad, but the solvers might benefit from this?
@@ -2007,6 +2017,11 @@ def addLinearConstraintsShape( | |||
|
|||
self._checkDVGeo(DVGeoName) | |||
|
|||
if childIdx is not None: | |||
DVGeo = self.DVGeometries[DVGeoName].children[childIdx] |
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.
It took me a bit of code reading, but I see how this makes sense. We have a single DVcon object which "receives" the parent DVGeo, and we were previously applying the constraint to this object instead of the children (when present) as expected. This means that we now need to add one of these for each child ffd, right? Can you add a short description of what is going on and how to extract the childIdx
index from DVGeo?
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.
Yes, without childIdx
the constraint is applied on the parent. You only need to add this constraint to each FFD that needs it. childIdx
is defined by the order in which you add the child FFD to the parent (the first is 0, second is 1, etc.). I will update the docstrings to include this description.
To be clear though, I took this approach directly from addLeTeConstraints which already worked with child FFDs.
""" | ||
The rectangular box is primarily used to test unscaled constraint function | ||
values against known values for thickness, volume, and surface area. | ||
""" |
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! Are the comments on the rest of the functions just redundant, and so you opted to remove then? I think we could use a one-liner for all the function here, even if the names are pretty self explanatory
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.
Yes, I felt the comments were redundant. Some were also incorrect (saying that a constraint does not rely on point sets when it does). What did you have in mind for the one-liners? I think they would be almost exactly the same as the test name.
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 I see, don't worry, this is fine
@@ -732,6 +778,34 @@ def test_monotonic(self, train=False, refDeriv=False): | |||
atol=1e-7, | |||
) | |||
|
|||
@unittest.skipIf(missing_geograd, "requires geograd") |
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.
So, the other test is on its own only because it cannot be used under parameterized -i.e. switch between parent/child ffd?
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.
Yes, that's right
funcs, funcsSens = self.bwb_test_deformed(DVGeo, DVCon, handler) | ||
|
||
@unittest.skipIf(missing_geograd, "requires geograd") | ||
def test_triangulatedSurface_intersected(self, train=False, refDeriv=False): |
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.
Where did this end up?
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.
That is here. I initially moved all the geograd tests into a separate class but realized I only needed to move the one with 2 DVGeos out.
def test_LERadius(self, train=False, refDeriv=False): | ||
refFile = os.path.join(self.base_path, "ref/test_DVConstraints_LERadius.ref") | ||
with BaseRegTest(refFile, train=train) as handler: | ||
DVGeo, DVCon = self.generate_dvgeo_dvcon_c172() |
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.
Maybe we can generalize the name of this function as well?
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.
Just the name or the functionality as well? I thought about creating one function that works with all the geometries because this would reduce code duplication. I can take a look at that if think it's worth it.
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.
uh, that would be nice if low-ish effort
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, I just checked the functions and I think we should definitely merge generate_dvgeo_dvcon_c172
and generate_dvgeo_dvcon_rect
. The only differences are the meshes, the location of the ref axis, the addToDVGeo
(?) option in DVCon.setSurface
, and the normalization of the testMesh.vectors
(??) and they should be pretty easy to handle with an option
Thanks @marcomangano for the thorough review! I will get started on the changes. Feel free to add other suggestions as well |
Codecov Report
@@ Coverage Diff @@
## master #103 +/- ##
==========================================
+ Coverage 55.58% 59.35% +3.76%
==========================================
Files 40 40
Lines 9608 9614 +6
==========================================
+ Hits 5341 5706 +365
+ Misses 4267 3908 -359
Continue to review full report at Codecov.
|
@@ -922,6 +831,7 @@ def test_LERadius(self, train=False, refDeriv=False): | |||
funcs, funcsSens = self.wing_test_deformed(DVGeo, DVCon, handler) | |||
|
|||
|
|||
@unittest.skipIf(missing_geograd, "requires geograd") |
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.
that was easy lol
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 work!
Purpose
This PR makes several changes related to DVConstraints and child FFDs:
Parameterized the DVConstraints tests to also run them with child FFDs. The parent FFD is a stationary box around the original FFD. We use the original reference files for the child FFD tests, which verifies that the constraint values and derivatives are identical with a fixed parent FFD.
The only test that is not parameterized is the triangulated surface (GeoGrad) test with multiple DVGeos because it is unclear how to handle multiple DVGeos with child FFDs (related to Refactor handling of multiple DVGeo objects with DVCon #57).
Fixed
addLinearConstraintsShape
andaddMonotonicConstraints
to work with child FFDs. Linear constraints need achildIdx
argument because they operate directly on the FFD.Added a test for the curvature constraint. This was one of only two constraints that were not tested, the other being the gear post constraint (which I doubt anyone still uses).
Added a test for the LE radius constraint. This was already tested in
test_Cylinder.py
, but a wing provides a more typical test case. In addition, this test is part of the same parameterized class so it is also tested with child FFDs.Renamed the DVConstraints tests and reference files to have actual names instead of numbers.
Type of change
Testing
Checklist
flake8
andblack
to make sure the code adheres to PEP-8 and is consistently formatted