Python 处理可变长度输入/输出阵列,在满足条件时终止计算(边界层计算)
我正试图编写代码来计算机翼上的边界层发展 我从一组点开始,描述机翼的形状 我在这些点上运行无粘解算器并提取停滞点,它将是S的一个元素 点集S现在由驻点分为两组su和sl,它们描述了上下边界层下方的机翼形状 这是我的第一个问题。假设我写了一个组件,BoundaryLayerSolve,它取边界层中点的向量s,以及边界层边缘速度的向量ue。s和ue的长度相同。如果我想使用一个组件两次,一次用于机翼的每一侧,我需要事先知道停滞点的位置,在模型已经设置并运行无粘解算器之前,无法找到停滞点。如何设置它,以便处理这些未知的输入数组大小 现在已知上下边界层的输入s和ue阵列,可以计算边界层。我将使用两个模型,一个用于边界层的层流区域,另一个用于湍流区域。假设这两个模型使用完全不同的计算,并且这些计算足够复杂,为了找到它们的解析偏导数,必须将它们分解为子成分 层流计算从驻点开始,沿着s行进。在每一步中,计算动量厚度的值。如果达到过渡阈值,层流计算必须停止,湍流计算必须用于剩余的s。我要强调的是,对所有s进行层流,对所有s进行湍流,然后简单地切断层流输出的后部和湍流输出的前部,这不是一个选项。湍流计算必须从过渡点层流计算的值开始 在psuedocode中,这类似于:Python 处理可变长度输入/输出阵列,在满足条件时终止计算(边界层计算),python,arrays,openmdao,Python,Arrays,Openmdao,我正试图编写代码来计算机翼上的边界层发展 我从一组点开始,描述机翼的形状 我在这些点上运行无粘解算器并提取停滞点,它将是S的一个元素 点集S现在由驻点分为两组su和sl,它们描述了上下边界层下方的机翼形状 这是我的第一个问题。假设我写了一个组件,BoundaryLayerSolve,它取边界层中点的向量s,以及边界层边缘速度的向量ue。s和ue的长度相同。如果我想使用一个组件两次,一次用于机翼的每一侧,我需要事先知道停滞点的位置,在模型已经设置并运行无粘解算器之前,无法找到停滞点。如何设置
转换点=0
对于索引,枚举中的点:
过渡点+=1
动量_厚度=层流(点)
如果动量\厚度>过渡\阈值:
打破
对于s中的点[过渡点+1:]:
湍流的(s)
这是我的第二个问题。过渡点直到层流计算期间才知道,因此层流计算的输出动量_厚度阵列的长度是未知的。因此,湍流计算的输入点阵列的长度也是未知的。我怎样才能解决这个问题
这是我的第三个问题。如何让一个组件在满足条件后终止其计算,并传递给另一个组件以完成阵列其余部分的计算
收集我的问题:
我理解这是一个很长的问题,可能会被打破。感谢您提前阅读。关于问题1和2:目前OpenMDAO不处理执行期间输入和输出的动态大小调整,目前也没有任何计划改变这一点。我们提供了
shape\u by\u conn
,允许根据变量的来源/目标对变量进行塑造,但我认为这不是您想要的,因为在您的公式中双方都是不确定的
问题3:如果我们隐式地处理这个问题,那么我们可以强制两个计算之间的转换发生在层流和湍流区域的交界处。例如,在Dymos中,当我们传播轨迹时,我们没有像典型的时间步进模拟那样使用事件触发器。相反,我们在轨迹的“阶段”的开始或结束处使用约束,以迫使过渡条件发生在连接处
我倾向于用这种方式来解释这个问题:
x
发生变化时,红色圆圈的点在机翼周围连续滑动
N_-l
和N_
)。确定过渡点的参数x
的值可以前后“滑动”,直到假定的过渡点值x与实际期望值匹配(通过在过渡点强制执行残差或约束,将x
作为隐式变量或设计变量)
import numpy as np
import openmdao.api as om
class VectorChain(om.ExplicitComponent):
def initialize(self):
self.options.declare('vec_size', types=int)
self.options.declare('step_size', types=int)
def setup(self):
vec_size = self.options['vec_size']
step_size = self.options['vec_size']
# this is the index of the last valid value in the data array
self.add_input('in_idx', shape=1, val=0)
# NOTE: though this could be done as a discrete variable,
# that will confuse OpenMDAO's derivative system, so just pass it as a float.
# actual data array
self.add_input('in_vec', shape=vec_size, val=np.zeros(vec_size))
self.add_output('out_idx', shape=1)
self.add_output('out_vec', shape=vec_size)
# NOTES: You do **NOT** define derivatives wrt the idx variable!!
self.declare_partials('out_vec', 'in_vec', method='CS')
def compute(self, inputs, outputs):
in_vec = inputs['in_vec']
out_vec = outputs['out_vec']
out_vec[:] = in_vec.copy()
# always use the first two entries to
# indicate the start/end of the valid data
i_start_idx = int(inputs['in_idx'])
i_end_idx = i_start_idx + self.options['step_size']
i_size = i_end_idx - i_start_idx
if i_start_idx == 0:
out_vec[0] = 1 # get the counting started
i_start_idx = 1
# note: careful to account for the open end of the
# interval when computing the end_idx value
# print(self.pathname)
for i in range(i_start_idx,i_start_idx+self.options['step_size']):
out_vec[i] = out_vec[i-1] + 1
o_end_idx = i_start_idx + i_size
outputs['out_idx'] = o_end_idx
if __name__ == "__main__":
p = om.Problem()
VEC_SIZE = 12
STEP_SIZE = 3
c0 = p.model.add_subsystem('c0', VectorChain(vec_size=VEC_SIZE, step_size=STEP_SIZE))
c1 = p.model.add_subsystem('c1', VectorChain(vec_size=VEC_SIZE, step_size=STEP_SIZE))
c2 = p.model.add_subsystem('c2', VectorChain(vec_size=VEC_SIZE, step_size=STEP_SIZE))
p.model.connect('c0.out_idx', 'c1.in_idx')
p.model.connect('c0.out_vec', 'c1.in_vec')
p.model.connect('c1.out_idx', 'c2.in_idx')
p.model.connect('c1.out_vec', 'c2.in_vec')
p.setup()
p.run_model()
p.model.list_outputs(print_arrays=True)