Added prevention of intersections in grid elements after deformation#1076
Conversation
…orm deformation. After deformation, the surface points are checked for self-intersection within the FFD box. If that is the case, a recursive procedure is done to prevent those. After grid deformation, all elements are checked on convexity. If there are nonconvex elements, a procedure is started that starts from the undeformed mesh and recursively changes the deformation magnitude until no nonconvex elements are present.
pcarruscag
left a comment
There was a problem hiding this comment.
Thank you for opening the PR Lennaertt, some comments below regarding making use of a few things we developed recently, and regarding our modernization efforts.
| for (iDim = 0; iDim < nDim; iDim++) { | ||
| edgeVector_1[iDim] = Coords_k[iDim] - Coords_i[iDim]; | ||
| edgeVector_2[iDim] = Coords_j[iDim] - Coords_i[iDim]; | ||
| } | ||
|
|
||
| /*--- Calculate cross product of edge vectors and its length---*/ | ||
| ev1 = edgeVector_1; | ||
| ev2 = edgeVector_2; | ||
|
|
||
| crossProduct[0] = ev1[1]*ev2[2] - ev1[2]*ev2[1]; | ||
| crossProduct[1] = ev1[2]*ev2[0] - ev1[0]*ev2[2]; | ||
| crossProduct[2] = ev1[0]*ev2[1] - ev1[1]*ev2[0]; | ||
|
|
||
| for (iDim = 0; iDim < nDim; iDim++) { | ||
| crossProductLength += crossProduct[iDim]*crossProduct[iDim]; | ||
| } | ||
|
|
||
| crossProductLength = sqrt(crossProductLength); |
There was a problem hiding this comment.
There is a geometry toolbox that implements all these, please use it.
There was a problem hiding this comment.
Thanks! There a few more things that the toolbox could do, like computing distance between 2 points, but we can do that latter.
| void CVolumetricMovement::ComputenNonconvexElements(CGeometry *geometry, bool Screen_Output) { | ||
| unsigned long iElem, PointCorners[8]; |
There was a problem hiding this comment.
If this routine is not super expensive we should include it in the mesh quality metrics.
|
Hi Lennaert, I've un-commented the items 'added a testcase' and 'added documentation'. We can use the testcase that you've worked on, and we can use one of your presentations as documentation, but it needs to be put somewhere. |
|
@tollennaert, can you comment on the points raised by @pcarruscag ? I think you tried to address all points in your latest update? That makes it clear to everybody that all points have been addressed. I hope you still have time for this. |
I indeed tried to solve all issues that were mentioned earlier. Could you take another look to see whether I have done this well enough? |
With respect to the test case and documentation: I have tried to find the best location to put this, but I could not find this. How can this be done best? |
should we add a testcase to the SU2/TestCases/incomp_navierstokes repository? |
| tuple<bool, unsigned short, unsigned short> GetFFD_IntPrev(void) { | ||
| return make_tuple(FFD_IntPrev, FFD_IntPrev_MaxIter, FFD_IntPrev_MaxDepth); | ||
| } | ||
|
|
||
| /*! | ||
| * \brief Get information about whether to do a check on convexity of the mesh elements. | ||
| * \param[out] ConvexityCheck: <code>TRUE</code> if convexity check is active; otherwise <code>FALSE</code>. | ||
| * \param[out] ConvexityCheck_MaxIter: Maximum number of iterations in the convexity check. | ||
| * \param[out] ConvexityCheck_MaxDepth: Maximum recursion depth in the convexity check. | ||
| */ | ||
| tuple<bool, unsigned short, unsigned short> GetConvexityCheck(void) { |
There was a problem hiding this comment.
Thanks for changing the return type 👍 these 2 methods can be const
| * \brief Get the amount of nonconvex elements in the mesh. | ||
| * \param[out] nNonconvexElements- amount of nonconvex elements in the mesh | ||
| */ | ||
| unsigned long GetnNonconvexElements(void) {return nNonconvexElements;} |
| * \param[in] config - Definition of the particular problem. | ||
| */ | ||
| void SetSurface_Deformation(CGeometry *geometry, CConfig *config) override; | ||
| void SetSurface_Deformation(CGeometry *geometry, CConfig *config, su2double** totaldeformation = nullptr); |
There was a problem hiding this comment.
The compiler is probably giving a warning about this function no? (because it has the same signature but it no longer overrides, instead it "hides" the original virtual SetSurface_Deformation)
| TotalDeformation[iDV] = new su2double[config_container[iZone]->GetnDV_Value(iDV)]; | ||
| for (iDV_Value = 0; iDV_Value < config_container[iZone]->GetnDV_Value(iDV); iDV_Value++){ | ||
| TotalDeformation[iDV][iDV_Value] = 0.0; |
There was a problem hiding this comment.
You can use the following syntax to initialize to zero:
TotalDeformation[iDV] = new su2double[config_container[iZone]->GetnDV_Value(iDV)] ();
(note the () at the end).
SU2_DEF/src/SU2_DEF.cpp
Outdated
| unsigned long iPoint, nPoint = geometry_container[iZone]->GetnPoint(); | ||
| unsigned short iDim, nDim = geometry_container[iZone]->GetnDim(); | ||
| su2double OriginalCoordinates[nPoint][nDim]; | ||
|
|
||
| for (iPoint = 0; iPoint < nPoint; iPoint++) { | ||
| for (iDim = 0; iDim < nDim; iDim++) { | ||
| OriginalCoordinates[iPoint][iDim] = geometry_container[iZone]->nodes->GetCoord(iPoint, iDim); | ||
| } | ||
| } |
There was a problem hiding this comment.
There is an easier way to do this.
auto OriginalCoordinates = geometry_container[iZone]->nodes->GetCoord();
or su2activematrix instead of auto.
This: su2double OriginalCoordinates[nPoint][nDim]; is actually not standard c++
|
Thank you @tollennaert, I added a few notes but if you don't have time we can take care of it after this is merged (I understand that your project is finished). |
There was a problem hiding this comment.
Hi @tollennaert, the code looks generally really tidy and thanks a lot for the contribution 💐
I have just a very few minor things, some of which are also up to debate.
With respect to the test case and documentation: I have tried to find the best location to put this, but I could not find this. How can this be done best?
For a start if you have a pdf, pptx you can share you can just dump them in here for now, so we can look at it together. And in terms of regression test I think just like pedro mentioned to take an existing testcase and modify it so it showcases your contributions. Or of course if you have a nice case at hand you can just add it as a new one.
As you have already finished your project it is ok if you dont want to spend any more time on it. But if you want to finish it: perfect, and disregard the following paragraph, otherwise:
Please allow us to push commits by checking one box on the side if it isn't enabled yet (not sure though who qualifies as 'maintainer' here). If you don't want us to push on your forks branch we could merge this and open a follow-up PR directly if changes are necessary.
Cheers, Tobi
Edit: Oh right and I didn't really understand what the depth-variables are for exactly tbh. I guess you half-en the DV_VALUE and check whether that solved the problem and try that a max of iter times. So what is the depth for 🤔
| /* DESCRIPTION: Procedure to prevent self-intersections within the FFD box based on Jacobian determinant */ | ||
| addBoolOption("FFD_INTPREV", FFD_IntPrev, NO); |
There was a problem hiding this comment.
I am in favor of FFD_INTERSECTION_PREVENTION just for the cfg-name not the c++ variable name (same for the other two) to be a bit more intuitive. No need to save a few chars here imo
| /* DESCRIPTION: Convexity check on all mesh elements */ | ||
| addBoolOption("CONVEXITY_CHECK", ConvexityCheck, NO); |
There was a problem hiding this comment.
And here I would go maybe for MESH_CONVEXITY_CHECK just to add a little more intuition
|
|
||
| } | ||
|
|
||
| /*--- Set total deformation values in config ---*/ |
There was a problem hiding this comment.
well, not anymore in config right?
| /*--- Calculate Jacobian determinant for FFD-deformation to check for self-intersection in FFD box. | ||
| Procedure from J.E. Gain & N.A. Dodgson, "Preventing Self-Intersection under Free Form Deformation". | ||
| IEEE transactions on Visualization and Computer Graphics, vol. 7 no. 4. October-December 2001 ---*/ |
There was a problem hiding this comment.
👍 for including the resource
| unsigned long iSurfacePoints; | ||
| unsigned short iMarker; | ||
| unsigned long negative_determinants = 0; | ||
|
|
||
| /*--- Loop over the surface points ---*/ | ||
| for (iSurfacePoints = 0; iSurfacePoints < FFDBox->GetnSurfacePoint(); iSurfacePoints++) { |
There was a problem hiding this comment.
Here one could use:
for(auto iSurfacePoints = 0ul; ...)for unsigned long also for the i,j,kdegree loops below i guess the with 0us... but that's nothing important
| } | ||
| } | ||
|
|
||
| unsigned long negative_determinants_local = negative_determinants; negative_determinants = 0; |
There was a problem hiding this comment.
I would spend 2 lines here.
| for (iZone = 0; iZone < nZone; iZone++){ | ||
|
|
||
| /*--- Initialize total deformation of design variables to zero ---*/ | ||
| su2double **TotalDeformation; |
There was a problem hiding this comment.
Use su2activematrix instead of su2double**. from @pcarruscag prob still applies here in the new home of TotalDeformation?
You then would most likely
su2activematrix TotalDeformation;
TotalDeformation.resize(nDV,nDV_Value) = su2double(0.0);... that resizing in the loop is not that nice, so I would like to hear pedros opinion before anything is changed here
| % Parameters for prevention of self-intersections within FFD box | ||
| FFD_INTPREV = YES | ||
| FFD_INTPREV_ITER = 10 | ||
| FFD_INTPREV_DEPTH = 3 | ||
|
|
There was a problem hiding this comment.
Here in the config template I would prefer to have an explanation for each option. Imo the best way is to have a suitable explanation in the CConfig.cpp and just pasting it here.
|
Hello all, My apologies for taking so much time to respond. As much as I would have liked to finish this part of the project nicely, I am afraid I must come to the conclusion that I have taken on too many responsibilities to finish the code andfinalize the pull request. I have attached a pptx to this comment that explains a little more about how the procedures work, the "allow edits by maintainers" box is checked. If you have any questions for me I will still be available to answer them, but I am not able to actively work on this anymore. The test cases should be available for @bigfooted, is it possible for you to place them where they are required? As for the depth that was mentioned in an earlier comment of @TobiKattmann : the depth is an option that can be used as a stopping criterion. For every iteration without problems the recursion depth is increased. This way, it can be used as a measure for how close to the limit you are going to stop, as opposed to stopping after the maximum amount of iterations. |
|
Merged because it is a pain to push to branches in forks. |
|
@bigfooted please open a PR to add the testcases @tollennaert mentioned you have. |
Address comments from #1076...
Proposed Changes
After surface deformation, the surface points are checked for self-intersection within the FFD box. If that is the case, a recursive procedure is done to prevent those. After grid deformation, all elements are checked on convexity. If there are nonconvex elements, a procedure is started that starts from the undeformed mesh and recursively changes the deformation magnitude until no nonconvex elements are present.
Related Work
None that I know of.
PR Checklist
Put an X by all that apply. You can fill this out after submitting the PR. If you have any questions, don't hesitate to ask! We want to help. These are a guide for you to know what the reviewers will be looking for in your contribution.
I am submitting my contribution to the develop branch.
My contribution generates no new compiler warnings (try with the '-Wall -Wextra -Wno-unused-parameter -Wno-empty-body' compiler flags).
My contribution is commented and consistent with SU2 style.
I have added a test case that demonstrates my contribution, if necessary.
I have updated appropriate documentation (Tutorials, Docs Page, config_template.cpp) , if necessary.
With respect to the test case: this can be used with virtually any case that has deformation. If the scale in OPT_OBJECTIVE is set to a high enough value, the deformation will be so big that intersections will occur.