是否可以在 ExplicitComponent 中对 ExplicitComponents 进行分组?
Is it possible to group ExplicitComponents inside an ExplicitComponent?
我有一个 ExplicitComponent 'CSTSurface',它需要一些权重并生成一条曲线。
我想将其中两个组合在一起以生成双表面机翼 ('CSTAerofoil')。
目前,我使用一个带有别名提升变量的组。我宁愿使用一个仅采用一个输入权重向量的组件(如 ExplicitComponent),然后将它们分派给两个 CSTSurface 组件。
这可能吗?实现此目标的最佳方法是什么?
我的代码(暂时原谅懒惰的 'fd'!):
import openmdao.api as om
import numpy as np
import scipy.special as scsp
from types import FunctionType
class CSTSurface(om.ExplicitComponent):
def initialize(self):
self.options.declare('nBP', types=int)
self.options.declare('nPoints', types=int)
self.options.declare('classFunc', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
nPoints = self.options['nPoints']
nBP = self.options['nBP']
self.add_input('xArray', shape=nPoints)
self.add_input('weights', shape=nBP) # Must be a row vector for multiplication to work right.
self.add_output('surfaceArray', shape=nPoints)
self.declare_partials('surfaceArray', ['xArray', 'weights'], method='fd')
def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
x = inputs['xArray']
weights = np.append(inputs['weights'], [0.0, 0.0])
C = self.options['classFunc']
nBP = self.options['nBP']
nPoints = self.options['nPoints']
# Build bezier matrix
B = np.zeros((nPoints, nBP + 2))
for r in range(nBP):
S = scsp.binom(nBP, r)*(x**r)*((1-x)**(nBP-r)) # Shape function
B[:, r] = C(x)*S
B[:, nBP] = x # Trailing edge thickness terms
B[:, nBP+1] = x*((1-x)**0.5)*((1-x)**nBP) # Leading edge modification
# Multiply by weights
B = B * weights
# Sum each row to get points
surfaceArray = np.sum(B, axis=1)
outputs['surfaceArray'] = surfaceArray
class CSTAerofoil(om.Group):
def initialize(self):
self.options.declare('nBPUpper', types=int)
self.options.declare('nBPLower', types=int)
self.options.declare('nPoints', types=int)
self.options.declare('classFunc', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
nPoints = self.options['nPoints']
nBPUpper = self.options['nBPUpper']
nBPLower = self.options['nBPLower']
C = self.options['classFunc']
self.add_subsystem('upperCSTSurface', CSTSurface(nBP=nBPUpper, nPoints=nPoints, classFunc=C),
promotes_inputs=[('weights', 'upperWeights'), 'xArray'],
promotes_outputs=[('surfaceArray', 'upperSurfaceArray')])
self.add_subsystem('lowerCSTSurface', CSTSurface(nBP=nBPLower, nPoints=nPoints, classFunc=C),
promotes_inputs=[('weights', 'lowerWeights'), 'xArray'],
promotes_outputs=[('surfaceArray', 'lowerSurfaceArray')])
当您开始学习如何在 OpenMDAO 中构建东西时,有时很想尝试对所有内容使用 OpenMDAO 结构。例如,在 OpenMDAO 中,组件代表最小的计算工作单元,您可以根据需要剔除多个副本。然后组允许您根据需要组织这些副本。这就是您所做的,但正如您所指出的那样,这并不是您想要从组件中构造出您想要的结构,因此您想知道如何将组件嵌套在它们自身中。
在其他组件实例的计算中嵌套组件实例在技术上并非不可能,但我不推荐这样做。你必须做大量的工作来构建额外的字典并传递它们。这是不值得的。
相反,我们可以使用基本的 a python class 和方法(即 compute
和 compute_partials
)恢复到更基本的对象组合设计争论。
助手 class 可以处理 CST 计算,然后一个组件有两个实例,根据需要从权重数组中提取。
像这样:
import openmdao.api as om
import numpy as np
import scipy.special as scsp
from types import FunctionType
class CSTSurface():
def __init__(self, n_Bp, n_points, class_func):
self.n_Bp = n_Bp
self.n_points = n_points
self.class_func = class_func
def compute_surface(self, x_array, weights):
x = x_array
weights = np.append(weights, [0.0, 0.0])
C = self.class_func
n_BP = self.n_Bp
n_points = self.n_points
# Build bezier matrix
B = np.zeros((n_points, n_BP + 2))
for r in range(n_BP):
S = scsp.binom(n_BP, r)*(x**r)*((1-x)**(n_BP-r)) # Shape function
B[:, r] = C(x)*S
B[:, n_BP] = x # Trailing edge thickness terms
B[:, n_BP+1] = x*((1-x)**0.5)*((1-x)**n_BP) # Leading edge modification
# Multiply by weights
B = B * weights
# Sum each row to get points
surface_array = np.sum(B, axis=1)
return surface_array
class CSTAerofoil(om.ExplicitComponent):
def initialize(self):
self.options.declare('n_Bp_upper', types=int)
self.options.declare('n_Bp_lower', types=int)
self.options.declare('n_points', types=int)
self.options.declare('class_func', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
n_points = self.options['n_points']
n_Bp_upper = self.options['n_Bp_upper']
n_Bp_lower = self.options['n_Bp_lower']
C = self.options['class_func']
self.cst_upper = CSTSurface(n_Bp_upper, n_points, C)
self.cst_lower = CSTSurface(n_Bp_lower, n_points, C)
self.add_input('x_array', shape=n_points)
self.add_input('weights', shape=n_Bp_upper+n_Bp_lower)
self.add_output('surface', shape=2*n_points)
def compute(self, inputs, outputs):
n_points = self.options['n_points']
n_Bp_upper = self.options['n_Bp_upper']
n_Bp_lower = self.options['n_Bp_lower']
outputs['surface'][:n_points] = self.cst_upper.compute_surface(inputs['x_array'], inputs['weights'][:n_Bp_upper])
outputs['surface'][n_points:] = self.cst_lower.compute_surface(inputs['x_array'], inputs['weights'][n_Bp_upper:])
if __name__ == "__main__":
p = om.Problem()
p.model.add_subsystem('cst', CSTAerofoil(n_points=10, n_Bp_upper=3, n_Bp_lower=4))
p.setup()
p['cst.weights'] = [1,2,3,1,2,3,4]
p['cst.x_array'] = np.linspace(0,1,10)
p.run_model()
p.model.list_outputs(print_arrays=True)
我有一个 ExplicitComponent 'CSTSurface',它需要一些权重并生成一条曲线。 我想将其中两个组合在一起以生成双表面机翼 ('CSTAerofoil')。
目前,我使用一个带有别名提升变量的组。我宁愿使用一个仅采用一个输入权重向量的组件(如 ExplicitComponent),然后将它们分派给两个 CSTSurface 组件。
这可能吗?实现此目标的最佳方法是什么?
我的代码(暂时原谅懒惰的 'fd'!):
import openmdao.api as om
import numpy as np
import scipy.special as scsp
from types import FunctionType
class CSTSurface(om.ExplicitComponent):
def initialize(self):
self.options.declare('nBP', types=int)
self.options.declare('nPoints', types=int)
self.options.declare('classFunc', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
nPoints = self.options['nPoints']
nBP = self.options['nBP']
self.add_input('xArray', shape=nPoints)
self.add_input('weights', shape=nBP) # Must be a row vector for multiplication to work right.
self.add_output('surfaceArray', shape=nPoints)
self.declare_partials('surfaceArray', ['xArray', 'weights'], method='fd')
def compute(self, inputs, outputs, discrete_inputs=None, discrete_outputs=None):
x = inputs['xArray']
weights = np.append(inputs['weights'], [0.0, 0.0])
C = self.options['classFunc']
nBP = self.options['nBP']
nPoints = self.options['nPoints']
# Build bezier matrix
B = np.zeros((nPoints, nBP + 2))
for r in range(nBP):
S = scsp.binom(nBP, r)*(x**r)*((1-x)**(nBP-r)) # Shape function
B[:, r] = C(x)*S
B[:, nBP] = x # Trailing edge thickness terms
B[:, nBP+1] = x*((1-x)**0.5)*((1-x)**nBP) # Leading edge modification
# Multiply by weights
B = B * weights
# Sum each row to get points
surfaceArray = np.sum(B, axis=1)
outputs['surfaceArray'] = surfaceArray
class CSTAerofoil(om.Group):
def initialize(self):
self.options.declare('nBPUpper', types=int)
self.options.declare('nBPLower', types=int)
self.options.declare('nPoints', types=int)
self.options.declare('classFunc', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
nPoints = self.options['nPoints']
nBPUpper = self.options['nBPUpper']
nBPLower = self.options['nBPLower']
C = self.options['classFunc']
self.add_subsystem('upperCSTSurface', CSTSurface(nBP=nBPUpper, nPoints=nPoints, classFunc=C),
promotes_inputs=[('weights', 'upperWeights'), 'xArray'],
promotes_outputs=[('surfaceArray', 'upperSurfaceArray')])
self.add_subsystem('lowerCSTSurface', CSTSurface(nBP=nBPLower, nPoints=nPoints, classFunc=C),
promotes_inputs=[('weights', 'lowerWeights'), 'xArray'],
promotes_outputs=[('surfaceArray', 'lowerSurfaceArray')])
当您开始学习如何在 OpenMDAO 中构建东西时,有时很想尝试对所有内容使用 OpenMDAO 结构。例如,在 OpenMDAO 中,组件代表最小的计算工作单元,您可以根据需要剔除多个副本。然后组允许您根据需要组织这些副本。这就是您所做的,但正如您所指出的那样,这并不是您想要从组件中构造出您想要的结构,因此您想知道如何将组件嵌套在它们自身中。
在其他组件实例的计算中嵌套组件实例在技术上并非不可能,但我不推荐这样做。你必须做大量的工作来构建额外的字典并传递它们。这是不值得的。
相反,我们可以使用基本的 a python class 和方法(即 compute
和 compute_partials
)恢复到更基本的对象组合设计争论。
助手 class 可以处理 CST 计算,然后一个组件有两个实例,根据需要从权重数组中提取。
像这样:
import openmdao.api as om
import numpy as np
import scipy.special as scsp
from types import FunctionType
class CSTSurface():
def __init__(self, n_Bp, n_points, class_func):
self.n_Bp = n_Bp
self.n_points = n_points
self.class_func = class_func
def compute_surface(self, x_array, weights):
x = x_array
weights = np.append(weights, [0.0, 0.0])
C = self.class_func
n_BP = self.n_Bp
n_points = self.n_points
# Build bezier matrix
B = np.zeros((n_points, n_BP + 2))
for r in range(n_BP):
S = scsp.binom(n_BP, r)*(x**r)*((1-x)**(n_BP-r)) # Shape function
B[:, r] = C(x)*S
B[:, n_BP] = x # Trailing edge thickness terms
B[:, n_BP+1] = x*((1-x)**0.5)*((1-x)**n_BP) # Leading edge modification
# Multiply by weights
B = B * weights
# Sum each row to get points
surface_array = np.sum(B, axis=1)
return surface_array
class CSTAerofoil(om.ExplicitComponent):
def initialize(self):
self.options.declare('n_Bp_upper', types=int)
self.options.declare('n_Bp_lower', types=int)
self.options.declare('n_points', types=int)
self.options.declare('class_func', default=lambda x: (x**0.5)*(1-x), types=FunctionType, recordable=False) # A little experimental, allow class functions to be passed as an option?
def setup(self):
n_points = self.options['n_points']
n_Bp_upper = self.options['n_Bp_upper']
n_Bp_lower = self.options['n_Bp_lower']
C = self.options['class_func']
self.cst_upper = CSTSurface(n_Bp_upper, n_points, C)
self.cst_lower = CSTSurface(n_Bp_lower, n_points, C)
self.add_input('x_array', shape=n_points)
self.add_input('weights', shape=n_Bp_upper+n_Bp_lower)
self.add_output('surface', shape=2*n_points)
def compute(self, inputs, outputs):
n_points = self.options['n_points']
n_Bp_upper = self.options['n_Bp_upper']
n_Bp_lower = self.options['n_Bp_lower']
outputs['surface'][:n_points] = self.cst_upper.compute_surface(inputs['x_array'], inputs['weights'][:n_Bp_upper])
outputs['surface'][n_points:] = self.cst_lower.compute_surface(inputs['x_array'], inputs['weights'][n_Bp_upper:])
if __name__ == "__main__":
p = om.Problem()
p.model.add_subsystem('cst', CSTAerofoil(n_points=10, n_Bp_upper=3, n_Bp_lower=4))
p.setup()
p['cst.weights'] = [1,2,3,1,2,3,4]
p['cst.x_array'] = np.linspace(0,1,10)
p.run_model()
p.model.list_outputs(print_arrays=True)