Source code for openaerostruct.aerodynamics.horseshoe_circulations

import numpy as np
from scipy.sparse import csc_matrix

import openmdao.api as om


[docs] class HorseshoeCirculations(om.ExplicitComponent): """ Convert the previously-computed vortex ring circulations into horseshoe circulations. Vortex rings and horseshoe vortices produce the same linear space, but with a different parameterization. It's easier to compute the circulations using a vortex ring approach, but it's easier to compute the forces acting on the surface by using the horseshoe circulations. That's why we have this component, to convert from one circulation space to the other. Parameters ---------- circulations[system_size] : numpy array The vortex ring circulations obtained by solving the AIC linear system. Returns ------- horseshoe_circulations[system_size] : numpy array The equivalent horseshoe circulations obtained by intelligently summing the vortex ring circulations, accounting for overlaps between rings. """ def initialize(self): self.options.declare("surfaces", types=list) def setup(self): surfaces = self.options["surfaces"] system_size = 0 # Loop through all the surfaces to obtain the total system size, # which is the number of panels in the total system. for surface in surfaces: mesh = surface["mesh"] nx = mesh.shape[0] ny = mesh.shape[1] system_size += (nx - 1) * (ny - 1) self.system_size = system_size self.add_input("circulations", shape=system_size, units="m**2/s", tags=["mphys_coupling"]) self.add_output("horseshoe_circulations", shape=system_size, units="m**2/s") # To convert between the two circulations, we simply need to set up a # matrix that linearly transforms the vortex ring circulations to # the horseshoe circulations. Again, because this is a linear # transformation, the derivatives are in fact the matrix itself. data = [np.ones(system_size)] rows = [np.arange(system_size)] cols = [np.arange(system_size)] ind_1 = 0 ind_2 = 0 for surface in surfaces: mesh = surface["mesh"] nx = mesh.shape[0] ny = mesh.shape[1] num = (nx - 1) * (ny - 1) ind_2 += num arange = np.arange(num).reshape((nx - 1), (ny - 1)) data_ = -np.ones((nx - 2) * (ny - 1)) rows_ = ind_1 + arange[1:, :].flatten() cols_ = ind_1 + arange[:-1, :].flatten() data.append(data_) rows.append(rows_) cols.append(cols_) ind_1 += num data = np.concatenate(data) rows = np.concatenate(rows) cols = np.concatenate(cols) # Actually create the sparse matrix based on these rows and cols self.mtx = csc_matrix((data, (rows, cols)), shape=(system_size, system_size)) self.declare_partials("horseshoe_circulations", "circulations", val=data, rows=rows, cols=cols) def compute(self, inputs, outputs): outputs["horseshoe_circulations"] = self.mtx.dot(inputs["circulations"])