Ejemplo n.º 1
0
    def compute(self, inputs, outputs):

        # Actually assemble the AIC matrix
        _assemble_AIC_mtx(self.AIC_mtx, inputs, self.surfaces)

        # Construct an flattened array with the normals of each surface in order
        # so we can do the normals with velocities to set up the right-hand-side
        # of the system.
        flattened_normals = np.zeros((self.tot_panels, 3), dtype=data_type)
        i = 0
        for surface in self.surfaces:
            name = surface['name']
            num_panels = (surface['num_x'] - 1) * (surface['num_y'] - 1)
            flattened_normals[i:i +
                              num_panels, :] = inputs[name +
                                                      '_normals'].reshape(
                                                          -1, 3, order='F')
            i += num_panels

        # Construct a matrix that is the AIC_mtx dotted by the normals at each
        # collocation point. This is used to compute the circulations
        self.mtx[:, :] = 0.
        for ind in range(3):
            self.mtx[:, :] += (self.AIC_mtx[:, :, ind].T *
                               flattened_normals[:, ind]).T

        # Obtain the freestream velocity direction and magnitude by taking
        # alpha into account
        alpha = inputs['alpha'][0] * np.pi / 180.
        cosa = np.cos(alpha)
        sina = np.sin(alpha)
        v_inf = inputs['v'][0] * np.array([cosa, 0., sina], dtype=data_type)

        # Populate the right-hand side of the linear system with the
        # expected velocities at each collocation point
        outputs['rhs'] = -flattened_normals.\
            reshape(-1, flattened_normals.shape[-1], order='F').dot(v_inf)

        outputs['AIC'] = self.mtx
Ejemplo n.º 2
0
            def compute_partials(self, inputs, partials):
                circ = inputs['circulations']
                alpha = inputs['alpha'] * np.pi / 180.
                rho = inputs['rho']
                cosa = np.cos(alpha)
                sina = np.sin(alpha)

                # Assemble a different matrix here than the AIC_mtx from above; Note
                # that the collocation points used here are the midpoints of each
                # bound vortex filament, not the collocation points from above
                _assemble_AIC_mtx(self.mtx, inputs, self.surfaces, skip=True)

                # Compute the induced velocities at the midpoints of the
                # bound vortex filaments
                for ind in range(3):
                    self.v[:, ind] = self.mtx[:, :, ind].dot(circ)

                # Add the freestream velocity to the induced velocity so that
                # self.v is the total velocity seen at the point
                self.v[:, 0] += cosa * inputs['v']
                self.v[:, 2] += sina * inputs['v']

                not_real_outputs = {}

                i = 0
                for surface in self.surfaces:
                    name = surface['name']
                    nx = surface['num_x']
                    ny = surface['num_y']
                    num_panels = (nx - 1) * (ny - 1)

                    b_pts = inputs[name + '_b_pts']

                    sec_forces = OAS_API.oas_api.forcecalc(
                        self.v[i:i + num_panels, :], circ[i:i + num_panels],
                        rho, b_pts)

                    # Reshape the forces into the expected form
                    not_real_outputs[name +
                                     '_sec_forces'] = sec_forces.reshape(
                                         (nx - 1, ny - 1, 3), order='F')

                    i += num_panels

                for surface in self.surfaces:

                    name = surface['name']
                    dS = partials[name + '_sec_forces',
                                  name + '_cos_sweep'].copy()
                    d_inputs = {}
                    sec_forcesb = np.zeros(
                        (surface['num_x'] - 1, surface['num_y'] - 1, 3))

                    sweep_angle = inputs[name +
                                         '_cos_sweep'] / inputs[name +
                                                                '_widths']
                    beta = np.sqrt(1 - inputs['M']**2 * sweep_angle**2)

                    if not compressible:
                        beta[:] = 1.

                    for k, val in enumerate(sec_forcesb.flatten()):
                        for key in inputs:
                            d_inputs[key] = inputs[key].copy()
                            d_inputs[key][:] = 0.

                        sec_forcesb[:] = 0.
                        sec_forcesb = sec_forcesb.flatten()
                        sec_forcesb[k] = 1.
                        sec_forcesb = sec_forcesb.reshape(
                            surface['num_x'] - 1, surface['num_y'] - 1, 3)

                        for i, B in enumerate(beta):
                            sec_forcesb[:, i, :] /= B

                        sec_forcesb = sec_forcesb.reshape((-1, 3), order='F')

                        circ = inputs['circulations']
                        alpha = inputs['alpha'] * np.pi / 180.
                        cosa = np.cos(alpha)
                        sina = np.sin(alpha)

                        ind = 0
                        rho = inputs['rho'].real
                        v = inputs['v']
                        vb = np.zeros(self.v.shape)

                        for surface_ in self.surfaces:
                            name_ = surface_['name']
                            nx_ = surface_['num_x']
                            ny_ = surface_['num_y']
                            num_panels_ = (nx_ - 1) * (ny_ - 1)

                            if name == name_:
                                b_pts = inputs[name_ + '_b_pts']

                                v_b, circb, rhob, bptsb, _ = OAS_API.oas_api.forcecalc_b(
                                    self.v[ind:ind + num_panels_, :],
                                    circ[ind:ind + num_panels_], rho, b_pts,
                                    sec_forcesb)

                                if 'circulations' in d_inputs:
                                    d_inputs['circulations'][
                                        ind:ind + num_panels_] += circb
                                vb[ind:ind + num_panels_] = v_b
                                if 'rho' in d_inputs:
                                    d_inputs['rho'] += rhob
                                if name + '_b_pts' in d_inputs:
                                    d_inputs[name_ + '_b_pts'] += bptsb

                            ind += num_panels_

                        sinab = inputs['v'] * np.sum(vb[:, 2])
                        if 'v' in d_inputs:
                            d_inputs['v'] += cosa * np.sum(
                                vb[:, 0]) + sina * np.sum(vb[:, 2])
                        cosab = inputs['v'] * np.sum(vb[:, 0])
                        ab = np.cos(alpha) * sinab - np.sin(alpha) * cosab
                        if 'alpha' in d_inputs:
                            d_inputs['alpha'] += np.pi * ab / 180.

                        mtxb = np.zeros(self.mtx.shape)
                        circb = np.zeros(circ.shape)
                        for i in range(3):
                            for j in range(self.tot_panels):
                                mtxb[j, :, i] += circ * vb[j, i]
                                circb += self.mtx[j, :, i].real * vb[j, i]

                        if 'circulations' in d_inputs:
                            d_inputs['circulations'] += circb

                        _assemble_AIC_mtx_b(mtxb,
                                            inputs,
                                            d_inputs,
                                            self.surfaces,
                                            skip=True)

                        for key in d_inputs:
                            partials[name + '_sec_forces',
                                     key][k, :] = d_inputs[key].flatten()

                    if compressible:

                        M = inputs['M']
                        S = inputs[name + '_cos_sweep']
                        X = not_real_outputs[name + '_sec_forces']
                        W = inputs[name + '_widths']
                        nx = surface['num_x']
                        ny = surface['num_y']
                        d_M = np.zeros((nx - 1, ny - 1, 3))
                        d_S = np.zeros((nx - 1, ny - 1, 3))
                        d_W = np.zeros((nx - 1, ny - 1, 3))
                        for ix in range(nx - 1):
                            for ind in range(3):
                                d_M[ix, :,
                                    ind] = (M * S**2 * X[ix, :, ind]) / (
                                        W**2 * (1 - (M**2 * S**2) / W**2)**1.5)
                                d_S[ix, :,
                                    ind] = (M**2 * S * X[ix, :, ind]) / (
                                        W**2 * (1 - (M**2 * S**2) / W**2)**1.5)
                                d_W[ix, :,
                                    ind] = (M**2 * S**2 * X[ix, :, ind]) / (
                                        W**3 * (1 - (M**2 * S**2) / W**2)**1.5)

                        partials[name + '_sec_forces', 'M'] = d_M.flatten()

                        ny3 = (ny - 1) * 3
                        for i in range(ny - 1):
                            for ix in range(nx - 1):
                                for ind in range(3):
                                    partials[name + '_sec_forces', name +
                                             '_cos_sweep'][3 * i + ix * ny3:3 *
                                                           (i + 1) + ix * ny3,
                                                           i][ind] = d_S[ix, i,
                                                                         ind]
                                    partials[name + '_sec_forces', name +
                                             '_widths'][3 * i + ix * ny3:3 *
                                                        (i + 1) + ix * ny3,
                                                        i][ind] = -d_W[ix, i,
                                                                       ind]
Ejemplo n.º 3
0
            def compute_jacvec_product(self, inputs, outputs, d_inputs,
                                       d_outputs, mode):
                circ = inputs['circulations']
                alpha = inputs['alpha'] * np.pi / 180.
                rho = inputs['rho']
                cosa = np.cos(alpha)
                sina = np.sin(alpha)

                # Assemble a different matrix here than the AIC_mtx from above; Note
                # that the collocation points used here are the midpoints of each
                # bound vortex filament, not the collocation points from above
                _assemble_AIC_mtx(self.mtx, inputs, self.surfaces, skip=True)

                # Compute the induced velocities at the midpoints of the
                # bound vortex filaments
                for ind in range(3):
                    self.v[:, ind] = self.mtx[:, :, ind].dot(circ)

                # Add the freestream velocity to the induced velocity so that
                # self.v is the total velocity seen at the point
                self.v[:, 0] += cosa * inputs['v']
                self.v[:, 2] += sina * inputs['v']

                if mode == 'fwd':

                    circ = inputs['circulations']
                    alpha = inputs['alpha'] * np.pi / 180.
                    if 'alpha' in d_inputs:
                        alphad = d_inputs['alpha'] * np.pi / 180.
                    else:
                        alphad = 0.

                    if 'circulations' in d_inputs:
                        circ_d = d_inputs['circulations']
                    else:
                        circ_d = np.zeros(circ.shape)
                    cosa = np.cos(alpha)
                    sina = np.sin(alpha)
                    cosad = -sina * alphad
                    sinad = cosa * alphad
                    rho = inputs['rho']
                    v = inputs['v']

                    mtxd = np.zeros(self.mtx.shape)

                    # Actually assemble the AIC matrix
                    _assemble_AIC_mtx_d(mtxd,
                                        inputs,
                                        d_inputs,
                                        self.surfaces,
                                        skip=True)

                    vd = np.zeros(self.v.shape)

                    # Compute the induced velocities at the midpoints of the
                    # bound vortex filaments
                    for ind in range(3):
                        vd[:, ind] += mtxd[:, :, ind].dot(circ)
                        vd[:, ind] += self.mtx[:, :, ind].real.dot(circ_d)

                    # Add the freestream velocity to the induced velocity so that
                    # self.v is the total velocity seen at the point
                    if 'v' in d_inputs:
                        v_d = d_inputs['v']
                    else:
                        v_d = 0.
                    vd[:, 0] += cosa * v_d
                    vd[:, 2] += sina * v_d
                    vd[:, 0] += cosad * v
                    vd[:, 2] += sinad * v

                    if 'rho' in d_inputs:
                        rho_d = d_inputs['rho']
                    else:
                        rho_d = 0.

                    i = 0
                    rho = inputs['rho'].real
                    for surface in self.surfaces:
                        name = surface['name']
                        nx = surface['num_x']
                        ny = surface['num_y']

                        num_panels = (nx - 1) * (ny - 1)

                        b_pts = inputs[name + '_b_pts']
                        if name + '_b_pts' in d_inputs:
                            b_pts_d = d_inputs[name + '_b_pts']
                        else:
                            b_pts_d = np.zeros(b_pts.shape)

                        self.compute(inputs, outputs)

                        sec_forces = outputs[name + '_sec_forces'].real

                        sec_forces, sec_forcesd = OAS_API.oas_api.forcecalc_d(
                            self.v[i:i + num_panels, :], vd[i:i + num_panels],
                            circ[i:i + num_panels], circ_d[i:i + num_panels],
                            rho, rho_d, b_pts, b_pts_d)

                        d_outputs[name + '_sec_forces'] += sec_forcesd.reshape(
                            (nx - 1, ny - 1, 3), order='F')
                        i += num_panels

                if mode == 'rev':

                    circ = inputs['circulations']
                    alpha = inputs['alpha'] * np.pi / 180.
                    cosa = np.cos(alpha)
                    sina = np.sin(alpha)

                    i = 0
                    rho = inputs['rho'].real
                    v = inputs['v']
                    vb = np.zeros(self.v.shape)

                    for surface in self.surfaces:
                        name = surface['name']
                        nx = surface['num_x']
                        ny = surface['num_y']
                        num_panels = (nx - 1) * (ny - 1)

                        b_pts = inputs[name + '_b_pts']

                        sec_forcesb = d_outputs[name + '_sec_forces'].reshape(
                            (num_panels, 3), order='F')

                        v_b, circb, rhob, bptsb, _ = OAS_API.oas_api.forcecalc_b(
                            self.v[i:i + num_panels, :],
                            circ[i:i + num_panels], rho, b_pts, sec_forcesb)

                        if 'circulations' in d_inputs:
                            d_inputs['circulations'][i:i + num_panels] += circb
                        vb[i:i + num_panels] = v_b
                        if 'rho' in d_inputs:
                            d_inputs['rho'] += rhob
                        if name + '_b_pts' in d_inputs:
                            d_inputs[name + '_b_pts'] += bptsb

                        i += num_panels

                    sinab = inputs['v'] * np.sum(vb[:, 2])
                    if 'v' in d_inputs:
                        d_inputs['v'] += cosa * np.sum(
                            vb[:, 0]) + sina * np.sum(vb[:, 2])
                    cosab = inputs['v'] * np.sum(vb[:, 0])
                    ab = np.cos(alpha) * sinab - np.sin(alpha) * cosab
                    if 'alpha' in d_inputs:
                        d_inputs['alpha'] += np.pi * ab / 180.

                    mtxb = np.zeros(self.mtx.shape)
                    circb = np.zeros(circ.shape)
                    for i in range(3):
                        for j in range(self.tot_panels):
                            mtxb[j, :, i] += circ * vb[j, i]
                            circb += self.mtx[j, :, i].real * vb[j, i]

                    if 'circulations' in d_inputs:
                        d_inputs['circulations'] += circb

                    _assemble_AIC_mtx_b(mtxb,
                                        inputs,
                                        d_inputs,
                                        self.surfaces,
                                        skip=True)
Ejemplo n.º 4
0
    def compute(self, inputs, outputs):
        circ = inputs['circulations']
        alpha = inputs['alpha'] * np.pi / 180.
        rho = inputs['rho']
        cosa = np.cos(alpha)
        sina = np.sin(alpha)

        # that the collocation points used here are the midpoints of each
        # bound vortex filament, not the collocation points from above
        _assemble_AIC_mtx(self.mtx, inputs, self.surfaces, skip=True)

        # Compute the induced velocities at the midpoints of the
        # bound vortex filaments
        for ind in range(3):
            self.v[:, ind] = self.mtx[:, :, ind].dot(circ)

        # Add the freestream velocity to the induced velocity so that
        # self.v is the total velocity seen at the point
        self.v[:, 0] += cosa * inputs['v']
        self.v[:, 2] += sina * inputs['v']

        i = 0
        for surface in self.surfaces:
            name = surface['name']
            nx = surface['num_x']
            ny = surface['num_y']
            num_panels = (nx - 1) * (ny - 1)

            b_pts = inputs[name + '_b_pts']

            if fortran_flag:
                sec_forces = OAS_API.oas_api.forcecalc(
                    self.v[i:i + num_panels, :], circ[i:i + num_panels], rho,
                    b_pts)
            else:

                # Get the vectors for each bound vortex of the horseshoe vortices
                bound = b_pts[:, 1:, :] - b_pts[:, :-1, :]

                # Cross the obtained velocities with the bound vortex filament
                # vectors
                cross = np.cross(self.v[i:i + num_panels],
                                 bound.reshape(-1, bound.shape[-1], order='F'))

                sec_forces = np.zeros((num_panels, 3), dtype=data_type)
                # Compute the sectional forces acting on each panel
                for ind in range(3):
                    sec_forces[:, ind] = \
                        (inputs['rho'] * circ[i:i+num_panels] * cross[:, ind])

            # Reshape the forces into the expected form
            forces = sec_forces.reshape((nx - 1, ny - 1, 3), order='F')

            sweep_angle = inputs[name + '_cos_sweep'] / inputs[name +
                                                               '_widths']
            beta = np.sqrt(1 - inputs['M']**2 * sweep_angle**2)

            if not compressible:
                beta[:] = 1.

            for j, B in enumerate(beta):
                outputs[name + '_sec_forces'][:, j, :] = forces[:, j, :] / B

            i += num_panels