首页 > 解决方案 > 将初始猜测作为其他组件输出的函数传递给非线性求解器

问题描述

我正在研究一个具有 3 个显式组件(Leg、Cable、BCan)和 1 个隐式(LegCableBal)的相对简单的模型。

隐式分量有许多残差方程。对于大多数状态变量,最好的初始猜测是计算为显式组件输出的值。例如,电缆元素的最终长度最接近于其初始长度,该长度由电缆组件根据输入到该组件的端点坐标计算为“输出”。我一直在尝试guess_nonlinear对该组使用该方法,但我认为我无法访问其他组件的输出,因为它们可能尚未执行。在显式组件中,输出可以默认为输入值,这会处理它,但我不知道我是否可以为输出默认值创建传递(输入-输出)。
有针对这些情况的策略吗?还是需要对问题进行全面重新安排?先感谢您!

在此处输入图像描述

此外,我在使用此设置时遇到了问题:

self.add_subsystem('Leg',Leg(rho_w=rho_w,concrete=concrete,rebar=rebar, tie=tiesteel,tendon=tendon, nlreinf_sets=self.options['nlreinf_sets'],npreinf_sets=self.options['npreinf_sets'],nsreinf_sets=self.options['nsreinf_sets']), promotes_inputs=['*']) # 

self.add_subsystem('Cable1',Cable(rho_w=rho_w, mat=cable1mat, loss=C_1loss, Cflag=1), promotes_inputs=['L_L0','a','b','c'] )

self.add_subsystem('Cable2',Cable(rho_w=rho_w, mat=cable2mat, loss=C_2loss, Cflag=2), promotes_inputs=['L_L0','a','b','c'] )

self.add_subsystem('BCan',BCan(rho_w=rho_w, canmat=canmat,F_c=self.options['F_c']), promotes_inputs=['*'])
       self.add_subsystem('LegCableBal',LegCableBal(cable1mat=cable1mat,cable2mat=cable2mat,canmat=canmat), promotes_inputs='L_L0','b_eff','B_c','M_c','Fx_c'], promotes_outputs=['*'])

这是在LegCableBal组内,我认为当我发布时将为所有组件分配“L_L0”(或其他提升的输入): prob.set_val('L_L0', 31.)在我设置所有初始值的主目录中。事实并非如此,事实上,L_L0 并没有将其放入任何组件中,但是仅由 提升的 'D_L' 等变量Leg确实在 之后得到了很好的分配prob.set_val('D_L', 2.1)。这个评估来自def guess_nonlinear(self, inputs, outputs, residuals)我试图使用 say 的地方outputs['L_Lf']= inputs['Leg.L_L0']。这将返回 [1.](应该是我分配的 31.),但inputs['Leg.D_L']它是正确的 2.1。

只是其中的一个片段ImplicitComponent

N_C1 = outputs['N_C1'][...]

residuals['N_C1'] = N_C1 - _N_C(E_pC1, A_C1, eps_C1) #Definition of N_C1
residuals['N_C2'] = N_C2 -_N_C(E_pC2, A_C2, eps_C2) #Definition of N_C2

   alpha = np.sqrt(N_e/(E_c * J_Lxxceff)) #definition of alpha

residuals['u_B']=  N_C1 * np.cos(Tht_C1f) - N_e * np.cos(Tht_Lf) + N_C2 * np.cos(Tht_C2f) +F_c    # force balance  along normal to stem's axis

residuals['u_B']= -N_C1 * np.sin(Tht_C1f) + N_e * np.sin(Tht_Lf) + N_C2 * np.sin(Tht_C2f) +B_eff  # force balance  along stem's axis

residuals['N_e']= (E_c * A_Leff * (L_Lf-L_L0) )/L_L0 - ( -N_e - (m_eff*g*np.cos(Tht_Lf))**2 / (12.*E_c*J_Lxxceff) * L_L0**4 * (1./ (L_L0**2 * alpha**2) + 12./ (L_L0**4 * alpha**4) - 24./ (L_L0**5*alpha**5) * np.tan(alpha*L_L0/2.) ) - E_c * A_Leff * (m_eff*g*np.cos(Tht_Lf))**2 / (24.* E_c**2 *J_Lxxceff**2) * L_L0**6  * (1./ (L_L0**4 * alpha**4) - 60./ (L_L0**7 * alpha**7) * np.tan(alpha*L_L0/2) + 24./ (L_L0**6 * alpha**6) + 12.*(1.-np.cos(alpha*L_L0))/(L_L0**6 * alpha**6 * np.sin(alpha*L_L0)**2 )  ) )``````

这里这些方程中的所有项要么是来自其他组件输出的输入,要么是我有其他残差方程的其他状态(例如,'N_C1')。

guess_nonlinear小组LegCableBal中,我粗暴地调用其他组件的计算来获得可用的输出。

        #Get some guesses by executing the cable component, horrible but I am not sure how else to pass these initial guesses that should just be the outputs of other components
        Cable1=Cable(rho_w=self.options['rho_w'],loss=self.options['C_1loss'], mat=self.options['cable1mat'],Cflag=1)
        Cable2=Cable(rho_w=self.options['rho_w'],loss=self.options['C_2loss'], mat=self.options['cable2mat'],Cflag=2)
        
        cable1_ins={'D_C':inputs['Cable1.D_C'],'L_L0':inputs['Leg.L_L0'],'a':inputs['Cable1.a'],'b':inputs['Cable1.b'],'c':inputs['Cable1.c'],'sig_Cpt0':inputs['Cable1.sig_Cpt0']}
        cable2_ins={'D_C':inputs['Cable2.D_C'],'L_L0':inputs['Leg.L_L0'],'a':inputs['Cable1.a'],'b':inputs['Cable1.b'],'c':inputs['Cable1.c'],'sig_Cpt0':inputs['Cable2.sig_Cpt0']}
        cable1_outs={}
        cable2_outs={}
        Cable1.compute(cable1_ins,cable1_outs)             
        Cable2.compute(cable2_ins,cable2_outs)             

        #Now set the initial guesses
        outputs['L_C1f']= cable1_outs['L_C0']```

谢谢你的时间贾斯汀,R

标签: openmdao

解决方案


注意:根据您提供的 N2,您根本不需要组级求解器! 没有任何组级耦合,正如没有任何下对角线连接所表明的那样。因此,在组级别没有什么可以收敛的,也不需要求解器。

您应该能够solve_nonlinearLegCableBal. 如果您需要任何额外的数据来对该方法进行初步猜测,您可以向该组件添加额外的输入。如果您不想编写自己的求解器,可以使用 OpenMDAO 的非线性求解器,方法是在组件级别将它们分配给任何组。或者,如果您愿意,您可以编写自己的求解器。

你真的不应该在这里根本不需要任何guess_nonlinear方法。根据您的要求和您展示的 N2,似乎有些不对劲。

您是正确的,组级别的guess_nonlinear 还没有调用任何子组件,因此它们的输出将不可用。层次结构中任何级别的guess_nonlinear 方法只能期望访问该级别的输入。

因此,如果您需要某个组件上游的计算值作为其猜测的一部分,那么您需要做的是将这些值作为额外输入添加到该组件并使用它的guess_nonlinear 方法。这种方法在使用 NewtonSolver 时很常见,但在使用 NonlinearBlockGaussSeidel (NLBGS) 时并不常见

使用 NLBGS,您总是有某种循环连接。最常见的情况是您必须从某个值的猜测开始(我们会说长度),然后在计算链的末尾,您最终得到该值的计算副本。你想迭代直到它们匹配。在这种情况下,您根本不需要任何隐式组件,因为您只需将计算的输出直接连接到链开始处的输入即可。这就是用户指南中的 Sellar 问题的处理方式。在这种情况下,唯一需要猜测的值是计算链开始处的值,但您不能使用计算值,因为您还没有它。因此,组级别的guess_nonlinear 可以根据您知道的任何输入进行某种估计,但组件级别的guess_nonlinear 没有意义。

你说过你确实有一个隐式组件,所以我假设你出于某种原因需要它。它在自己的solve_nonlinear方法内部进行一些隐式计算。(注意:如果你有一个隐式组件,使用 NLBGS 那么它必须有自己的 solve_nonlinear 方法它不会工作)。如果您已将隐式组件作为第一个在模型中运行,那么您可能难以猜测它的值。您可以将它移到最后,首先运行所有其他的,然后将您需要的任何计算值作为附加输入传递给它(即使输入仅用于“猜测”)。但是在这种情况下,您根本不需要guess_nonlinear,因为您可以计算猜测值作为计算的第一步solve_nonlinear

如果您可以将其提炼成可运行的脚本(或提供指向要点或其他内容的链接),我可以提供一个更具体的答案来说明我会做什么……但您真的不应该需要您级别的求解器把它放在层次结构中。


推荐阅读