pygeo icon indicating copy to clipboard operation
pygeo copied to clipboard

Child FFD deltas not calculated with the same point set as parent.

Open joanibal opened this issue 6 years ago • 3 comments

Previously known issue written here for documentation.

The Problem

When working with a child FFD embed in a parent FFD, a sub set of the points embedded in the parent will also be embed in the child. When calculating the additional movement of embed points due to the modification of the child FFD, the child FFD will first update the points embed inside of itself according to how the control points of the child were moved when the parent deformed. However, updating the points according to how the control points of the child were moved will not produce a point set identical to those embed in the parent! So when the child calculates deltas (additional position modifications) and they are added to the modifications caused by the motion of the parent FFD, the deltas will not have the intended geometric effect. For example in cases where the parent FFD does shape modifications and the child rotates a subset of these points (think morphing LE/TE), the rotation will skew the shape modifications. An example of this is shown in the picture below. shapeModificationsSkewed

When it's an Issue

  • when combining parent shape variables with child shape deformation that isn't uniform for each point (child shape variables and rotation will cause issues, but translation will not).
  • Especially apparent when using large child FFD modifications

Work Around

  • use a linear spline surface for the Child FFD (works well for rotations, but not for child shape variables)

long term fix

  • change the data structure for child FFDs so that it references the same point set as the parent (same object in memory) but only works with a sub set of these points (the ones inside the child FFD). This way the points that the child FFD uses to calculate its additional modifications will always be the same as the points warped by the parent deformation.

joanibal avatar Apr 16 '19 18:04 joanibal

@joanibal can you post the global design variable function you used in the child?

While writing the tutorial I wanted to understand why global variable funcs that use += operations work properly. When self.update() is called, the FFD coefficients are set back to their original (baseline) locations and then the global DVs are computed in order of their addition, then sectionlocal and local variables. So you don't accumulate changes across iterations via += operations.

On the other hand, child FFDs do some weird stuff that I don't totally understand, but I don't think it's doing the same reset. So if you used += or *= operations in your child global dv funcs, it could lead to some weird behavior. It may or may not be relevant to your debugging here

        if not self.isChild:
            self.FFD.coef = self.origFFDCoef.copy()
            self._setInitialValues()
        else:
            # Update all coef
            self.FFD._updateVolumeCoef()

            # Evaluate starting pointset
            Xstart = self.FFD.getAttachedPoints(ptSetName)

            if self.complex:
                # Now we have to propagate the complex part through Xstart
                tempCoef = self.FFD.coef.copy().astype('D')
                Xstart = Xstart.astype('D')
                imag_part = numpy.imag(tempCoef)
                imag_j = 1j

                dPtdCoef = self.FFD.embededVolumes[ptSetName].dPtdCoef
                if dPtdCoef is not None:
                    for ii in range(3):
                        Xstart[:, ii] += imag_j*dPtdCoef.dot(imag_part[:, ii])

bbrelje avatar Feb 28 '21 18:02 bbrelje

Here are the functions I used with child FFDs



def twist_flap(val, geo):
    geo.rot_z['flap_axis'].coef[:] = val[:] - 29.5


def translate_x_flap(val, geo):
    C = geo.extractCoef('flap_axis')
    C[:, 0] += val[:] + 0.15421028
    geo.restoreCoef(C, 'flap_axis')


def translate_y_flap(val, geo):
    C = geo.extractCoef('flap_axis')
    C[:, 1] += val[:] - 0.0816069
    geo.restoreCoef(C, 'flap_axis')


def twist_slat(val, geo):
    geo.rot_z['slat_axis'].coef[:] = val[:] + 29.0


def translate_x_slat(val, geo):
    C = geo.extractCoef('slat_axis')
    C[:, 0] += val[:] - .0911552
    geo.restoreCoef(C, 'slat_axis')


def translate_y_slat(val, geo):
    C = geo.extractCoef('slat_axis')
    C[:, 1] += val[:] - 0.0735696
    geo.restoreCoef(C, 'slat_axis')



joanibal avatar Mar 01 '21 17:03 joanibal

Yeah I can't say for certain that the weird behavior is caused by the per-iteration reset behavior of the coefficients referenced by C = geo.extractCoef('slat_axis') but it's possible.

bbrelje avatar Mar 01 '21 20:03 bbrelje