Simcenter STAR-CCM+ Adjoint Optimization: Geometrical packaging constraints

Simcenter STAR-CCM+ Simcenter STAR-CCM+ Virtual Reality Teamcenter Share Simcenter Cloud HPC Simcenter STAR-CCM+ Viewer Simcenter STAR-CCM+ Application Specific Solutions


How to constraint an Adjoint optimization.


Most of the time that we do optimization then we need to be mindful of geometrical constraints that the surrounding geometry of the part that we want to optimize impose.
If one runs an adjoint calculation then the adjoint solver does not take any such constraints into account but we can account for them when we morph the geometry according to the adjoint.

This means that the constraints are not influencing the optimization and the resulting geometry might not be optimal because we are only introducing these constraints on the morpher but not on the design space itself!

WARNING: This is not a trivial method and should not be attempted if you are not experienced with adjoint.

Case description

Let's consider the following case :


We have flow going from left to right and we are interested in optimizing the pressure drop caused by this pipe, in order to do so we setup a standard adjoint mesh deformation case and run a couple of optimization cycles-ending up with this geometry :

Here we see the initial geometry in full lines and a transparent end result of the optimization.
This works very well but what if now I want to include packaging constraints into this? Let's take for example an arbitrary packaging space:

The pipe geometry (Design Space) can't go out of the red box displayed here.

The process is the following : 

1) Mesh the packaging space and assign it to regions. 
2) Setup data mapper to transfer data from the packaging space to the design space
3) Setup Field functions needed to constraint the morphing motion
4) Run optimization with constrained morphing motion while updating the constraints after each design loop.

 Here follows a detailed procedure : 

In order to do this we will have to determine what is the distance from our current design space that we are morphing up until the packaging constraint.
We require a volume representation of the packaging space in order to calculate the wall distance, thus the need for meshing it. 
Accordingly, you need to create a new continua with wall distance as one of the models and assign the packaging space to regions.

Solution must be initialized to obtain Wall Distance field function. PackagingSpace Continuum can be deactivated after initialization.

User-added image

Here one can see the mesh of the region 'Packaging Space' the wall distance gives us the distance from the current cell on to the bounds of the Packaging Space.
In addition to the scalar distance we also need to get the direction of the nearest boundary, this is done with the gradient of the WallDistance field function. Defined as:   -unit(grad(${WallDistance}))


Next we need to transfer this information to the design space so that we can know when we have/will move out of our constraints. This is done via a data mapper:


This is showed in the following image, 'gradWallDistance' are the vectors in black and the scalar displayer is MappedWallDistance.


Now we have all of the functions that we need in order to setup the constraint, here is a graphical demonstration of what we are doing :

The vector d is the gradient of wall distance and u is the displacement suggested by the adjoint.
If u will go over the limit that is the boundary of our packaging space we will limit the vector u to u_lim which is the intersection point of u with the packaging constraint.

Mathematically then u_lim is defined as :

Therefore if dot( d , u) is larger than WallDistance then that means that the node will go over the limit and we need to constrain the displacement to u_lim.
All of this is defined inside of the field functions


  • AdjointDisplacement is the translation of surface sensitivites into displacement :  
${RampFunction} > 0 ?  -$${Adjoint1::Surface Sensitivity}/max(${SS_max},1e-10)*${X_SF} : [0,0,0]
Note: ${RampFunction} is used here to exclude and ramp vertex movement near inlet boundaries to produce smoother geometries.
 ${SS_max} is the maximum sensitivity in the domain, this is used to normalize the applied sensitivity, again to make the morph smoother.
  • Displacement is the usual displacement used in adjoint :
  • LimitedAdjointDisplacement: Is the switch in between applying the full morph (U vector) or the limited version (U_lim vector) 
dot($${MappedgradWallDistance},$${AdjointDisplacement}) < ${MappedWallDistance} ?  $${AdjointDisplacement} : $${LimitedDisplacement}
  • LimitedDisplacement is the definition of u_lim from above :
${i} > 0  && ${RampFunction} > 0  && ${MappedWallDistance} > ${FirstCellHeight}  && abs(dot($${MappedgradWallDistance},$${AdjointDisplacement})) > 1e-6 ?  $${AdjointDisplacement} - $${AdjointDisplacement} * pow(dot($${MappedgradWallDistance},$${AdjointDisplacement}) - ${MappedWallDistance} , 2) / max( dot($${MappedgradWallDistance} * ( dot($${MappedgradWallDistance},$${AdjointDisplacement}) - ${MappedWallDistance})  , $${AdjointDisplacement}),1e-20) : [0,0,0]
Notes :
There is a quadruple 'and' condition in the beginning in order to make this function equal to zero in the case of:
  1. If we are in the range of the RampFunction which is used to limit the displacement near boundaries.
  2. If the adjoint hasn't been initialized before ( ${i}  ==0 means that we have zero loops) as then the adjoint vector is null and the field would have a division by zero - which is illegal !
  3. If the node is inside of the first prism layer of the packaging space mesh, this is done as if we move further then we will end up out of the packaging space which is what we want to prevent with this exercise. This parameter has to be set by the user.
  4. If the dot product in between gradWallDistance and U will yield a very low value and as it's a denominator value it can give us an overflow.

If any of these conditions are satisfied then the u_lim vector is set to zero as we should not move or it is not defined yet.
The process is then driven by SimOps. 


Here you can see that after the primal is solved then we call the mapper in order to have up to date information on how far away from the packaging space our current design resides. Afterwards we solve the adjoint and deform the mesh according to the field functions. 

The evolution of the constraint and un-constraint optimization can be found attached to this article(.gifs) in addition to the sim file. 

As mentioned at the beginning of the article, the resulting shape contains suboptimal features caused by the shape of the constraints - 90 degrees step which is clearly not decreasing pressure drop. 

Other considerations

Other workflows

Similar procedure can be incorporated into workflow with surface mesh morphing (with remeshing). 
In such cases Displacement = $${LimitedAdjointDisplacement}.

Constraint enforcement

There are a few things which might improve constraint enforcement: refined mesh for both packaging and adjoint regions, changing Interpolation Method and Limiter of the Data Mappers to Least Squares and Min/Max of Contributing Sources respectively. 

KB Article ID# KB000041850_EN_US



Associated Components

Design Manager Electronics Cooling In-Cylinder (STAR-ICE) Job Manager Simcenter STAR-CCM+