Skip to content

Time-accurate discrete adjoint gradients for unsteady problems with grid movement - #766

Merged
talbring merged 34 commits into
developfrom
feature_dynamic_mesh_discrete_adjoint
Sep 23, 2019
Merged

Time-accurate discrete adjoint gradients for unsteady problems with grid movement#766
talbring merged 34 commits into
developfrom
feature_dynamic_mesh_discrete_adjoint

Conversation

@cvencro

@cvencro cvencro commented Aug 22, 2019

Copy link
Copy Markdown
Contributor

Proposed Changes

This PR, created together with @TobiKattmann , makes the necessary changes to obtain time-accurate discrete adjoint gradients for unsteady problems with grid movement. Main changes are for the handling of grid velocities of previous time steps.

Regression test case to follow.

Related Work

depends on #767 unsteady incompressible + ALE. Then a tested discrete adjoint for unsteady incompressible flow can be merged with this.
Edit @TobiKattmann: PR767 is merged so I remove the dependent label

PR Checklist

  • 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.

Comment thread Common/src/dual_grid_structure.cpp Outdated
GridVel = new su2double[nDim];
GridVel_Old = new su2double[nDim];
GridVel_n = new su2double[nDim];
GridVel_n1 = new su2double[nDim];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we always need this arrays or just in case of the discrete adjoint ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Wrapped the allocation it in a Discrete Adjoint conditional.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

To give some background why: In the reverse sweep (say, with dual time stepping 2nd order) always the n-2 timestep is loaded from disk into memory. In that process, Coordinates and GridVels are stored. So compared to the corresponding primal timestep the adjoint had data from 2 timesteps before (...thinking in primal time) if these additional containers and corresponding data pushing wouldn't be there.
I thought it is more convenient than recomputing as all the data is already there in the restart files (and it was faster to code). I might also be beneficial for cases where GridVel is not a fixed function like in rigid motion but depends on the problem itself -> then it can be simply read from the restart file.

Comment thread Common/src/config_structure.cpp Outdated
Restart_Flow = false;

if (GetGrid_Movement()) {
SU2_MPI::Error("Dynamic mesh movement currently not supported for the discrete adjoint solver.", CURRENT_FUNCTION);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I guess it only works for rigid movement at the moment then, am I correct ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Correct. Now checks Kind_GridMovement != RIGID_MOTION and throws an error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Rigid motion cases have been used for the verification at the moment but GCL is included to handle changing volumes of a mesh in the primal solvers. Therefore the changes in this request should capture both rigid motion and deforming mesh problems for discrete adjoints as the grid velocities are now captured correctly. Please advise if I'm missing to account for something else here? If anyone can point me to a good single zone mesh deformation test case that already exists for the primal solver, I can investigate the discrete adjoint explicitly for a deforming mesh problem as well.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As of now, deformable meshes are mostly used in FSI (where the coupling terms should be accounted for) but outside of that, there are not many methods to run deformable, single-zone test cases available. I guess something could be done using SURFACE_MOVEMENT = DEFORMING and a pitching/plunging airfoil, but I don't believe the adjoint will work out of the box, as the Grid Velocities are recomputed several times in one round of deformation.

However, with the capabilities in #760, I believe it should be relatively easy to set up a case with time-dependent boundary displacements.

Comment thread Common/include/dual_grid_structure.inl Outdated
}

inline void CPoint::SetGridVel_Old(su2double *val_gridvel) {
for (unsigned short iDim = 0; iDim < nDim; iDim++)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please change these tabs to spaces.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yep, went over all 'Files changed' and fixed all indentation mismatches I saw.
Btw: In e.g. dual_grid_structure.hpp, most indentations are done using tabs and there are a lot of trailing whitespaces. Is it useful to change it in the whole file? Would be work of a few minutes but the latest git blame would be kindof misleading. I also noticed (which is probably) @WallyMaier in a branch cleanup just doing that cosmetic stuff. This is only a style(-guide) question.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Since we are currently restructuring the files anyway, we should do that clean up when creating/moving new files. This way we avoid duplicate conflicts.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yep, please wait on the larger white space cleanup until we divide dual_grid_structure.hpp into files for each subclass.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi all, I did start to create a clean up branch, referencing the the style guide. I can continue with it (and skip the dual grid). But I think with new version coming in, we should clean up files that are going to be restructured.

@economon economon left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM. Thanks @cvencro @TobiKattmann for getting this working (and finding/fixing a couple of bugs in the process).

Comment thread SU2_CFD/src/iteration_structure.cpp Outdated
unsigned short iMesh;
int Direct_Iter;
bool heat = config[val_iZone]->GetWeakly_Coupled_Heat();
bool grid_movement_bool = config[val_iZone]->GetGrid_Movement();

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you please switch 'grid_movement_bool' to 'grid_movement' to keep with the convention throughout the rest of the code? Eventually, we could use something more expressive for the name like 'gridIsMoving' (find and replace everywhere), but for now, consistency is enough

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yep, but I would actually prefer bool gridIsMoving as grid_movement is used as a larger container for CVolumetricMovement ***grid_movement.

@rsanfer rsanfer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hi @cvencro, @TobiKattmann ,
thank you so much for this PR, which addresses a certainly interesting capability to compute adjoints on moving meshes. However, I have a question and would like to open a discussion about the generalization of the feature.

I have seen that this PR allocates a lot of memory for GridVel_Old, GridVel_n, and GridVel_n1, and additionally Coord_Old. I see how this can work for rigid grid movement, as the Grid Velocities are then imposed (so, they are independent variables) and the grid is not really moving physically.

However, for deforming cases we might run into problems, as in that case the Grid Velocities are magnitudes that are derived from the grid positions. In fact, at time n, only the grid velocity u enters the dual-time stepping equation ALE-NS equation, but the dependency of u on previous time steps n, n-1 links directly to the mesh deformations z,
,
where at the same time we would need to differentiate with respect to the variables z for correct geometrical adjoint sensitivities.

Additionally, we already have those variables allocated as Coord_p1, Coord_n and Coord_n1 (in this mesh solver) or Solution, Solution_time_n and Solution_time_n1 in #760. So, really, obtaining the GridVel vector would just be an additional FD computation both for rigid movement and dynamic grids, and a lot of memory savings are possible.

Do you think it could be possible to adapt it for this PR? If not, it should be something to consider as further work (as I would expect there is quite a bit of interest on dynamic meshes), maybe using the basis of #760 (which should make it easier).

Comment thread Common/src/config_structure.cpp Outdated
Restart_Flow = false;

if (GetGrid_Movement()) {
SU2_MPI::Error("Dynamic mesh movement currently not supported for the discrete adjoint solver.", CURRENT_FUNCTION);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

As of now, deformable meshes are mostly used in FSI (where the coupling terms should be accounted for) but outside of that, there are not many methods to run deformable, single-zone test cases available. I guess something could be done using SURFACE_MOVEMENT = DEFORMING and a pitching/plunging airfoil, but I don't believe the adjoint will work out of the box, as the Grid Velocities are recomputed several times in one round of deformation.

However, with the capabilities in #760, I believe it should be relatively easy to set up a case with time-dependent boundary displacements.

unsigned short iMesh;
int Direct_Iter;
bool heat = config[val_iZone]->GetWeakly_Coupled_Heat();
bool grid_IsMoving = config[val_iZone]->GetGrid_Movement();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

For consistency, could you rename grid_IsMoving to grid_movement?

@TobiKattmann TobiKattmann Aug 23, 2019

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@economon mentions that as well above :) but CVolumetricMovement ***grid_movement is an input to that function, so the compiler throws an error declaration of ‘bool grid_movement’ shadows a parameter

Comment thread Common/include/dual_grid_structure.hpp Outdated
* \return Grid velocity at the point.
*/
su2double *GetGridVel(void);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can you indent these functions to align with the rest of the file?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

In the file mostly tabs are used for indentation, and github seems to display 4 spaces per tab. The added code follows https://su2code.github.io/docs/Style-Guide/ using 2 spaces as indentation.
I can of course change it to be consistent with the file using tabs if that is wanted. Above in pedros review that topic came already up.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Oh sorry, I didn't notice before. Let's leave it like that then.

Comment thread Common/include/dual_grid_structure.hpp Outdated
* \param[in] val_value - Value of the gradient.
*/
void SetGridVel_Grad(unsigned short val_var, unsigned short val_dim, su2double val_value);
* \brief Set the value of the grid velocity at the point.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Same here

@rsanfer rsanfer left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I hadn't noticed there was an approval already, so I will just put the PR in standby temporarily to follow the discussion above.

@TobiKattmann

Copy link
Copy Markdown
Contributor

So, really, obtaining the GridVel vector would just be an additional FD computation both for rigid movement and dynamic grids, and a lot of memory savings are possible.

Hey @rsanfer, I think that is ok for this PR. After a short search I guess such a routine does not exist yet. Or can you point me to the right direction?
Otherwise CVolumetricMovement::ComputeGridVel_from_Coord(..) would be a naming suggestion. What do think?

@talbring

Copy link
Copy Markdown
Member

The routine you are looking for is probably this one:

void CPhysicalGeometry::SetGridVelocity(CConfig *config, unsigned long iter) geometry_structure.cpp:14760 (cannot paste a link, the file is too big)

@cvencro

cvencro commented Aug 24, 2019

Copy link
Copy Markdown
Contributor Author

Hi @rsanfer and @TobiKattmann , I agree with the more generalised solution for rigid and deforming meshes too and this is excellent timing of #760 to combine the new approach.
I have FSI cases I can use, but thought it would be a good stepping stone to use fluid-only case to begin with to avoid the coupling terms for this verification. Using dynamic surface movement definitions for the single-zone pitching airfoil test which has previously been used for rigid motion, the primal solutions and gradients from finite differences for both are very similar as expected. Therefore this should be a good reference to check the discrete adjoints for deforming mesh when the adaptations for grid velocities are made using #760.


/*--- Secondary sensitivities must be computed with a certain frequency. ---*/
/*--- It is also done at the beginning so all memory gets allocated. ---*/
if ((Adjoint_Iter % config->GetWrt_Sol_Freq() == 0) && (SecondaryVariables != NONE)){

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This SecondaryRecording is now removed entirely, as it introduces a bug for the unsteady adjoint. The Volume Mesh Sensitivity setting is a += in each physical timestep for unsteady cases and SecondaryRecording is also called in Postprocess() right after the Run(). I.e. if it is called multiple times in one physical timestep the sensitivity adds up. With this code modification SecondaryRecording gets only called once per timestep in Postprocess.

For steady cases the implications are: The memory for the secondary recording gets allocated after the 'flow adjoint iteration' ... so it could be really annoying if the simulation crashes due to lack of memory after waiting for convergence. More importantly: You cannot use an intermediate restart file for e.g. DOT_AD as it is does not hold any/correct sensitivities. So it might be better to only disable this conditional for unsteady computations as I see the advantage of having this for steady computations. What do you think @rsanfer

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I honestly prefer it that way as it is much faster for steady-state computations in moving meshes (a lot less unnecessary recordings). In fact that was my first implementation, but then I added this SecondaryRecording after discussion with @talbring, because of the drawbacks you mention. No 100% what's the best approach...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

My only concern is the memory thing, because usually the recording with coordinates as inputs takes more memory than the one with the solution variables. I am not so worried about the intermediate restart files, since you can just do a restart to get the correct sensitivity values.

Lets do it without the SecondaryRecording. If it really leads to problems, we can always change it back.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Ok, sounds good to me.

@TobiKattmann

Copy link
Copy Markdown
Contributor

A little gradient validation using the added Testcase (comp euler, 150 timesteps, pitching airfoil, FFD points as DV, Efficiency obj function).

gradient

@TobiKattmann TobiKattmann changed the title WIP Feature dynamic mesh discrete adjoint Feature dynamic mesh discrete adjoint Sep 17, 2019
@dep dep Bot added the dependent label Sep 17, 2019
@talbring

Copy link
Copy Markdown
Member

@TobiKattmann The validation looks perfect. Happy that it works now.

@talbring

Copy link
Copy Markdown
Member

Remember to revert the Travis changes.

@TobiKattmann

TobiKattmann commented Sep 23, 2019

Copy link
Copy Markdown
Contributor

Alright, the su2code/Testcases repo is already merged, .travis.yml is reverted. If there are no further request than this can be merged from my standpoint.
Big thanks to @cvencro for the collaboration :)

@talbring

Copy link
Copy Markdown
Member

Thanks. Merging it in. Just as a reminder: without a Tutorial or Documentation, there will be no advertising :/

@talbring
talbring merged commit 1ef7788 into develop Sep 23, 2019
@talbring
talbring deleted the feature_dynamic_mesh_discrete_adjoint branch September 23, 2019 10:13
@talbring talbring changed the title Feature dynamic mesh discrete adjoint Time-accurate discrete adjoint gradients for unsteady problems with grid movement Nov 8, 2019
@cvencro cvencro mentioned this pull request Dec 8, 2019
5 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants