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

问题描述

我正在开发一个相对简单的模型,其中包含 3 个显式组件(Leg、Cable、BCan)和 1 个隐式组件(LegCableBal)。

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

enter image description here

此外,我在此设置中遇到了问题:

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',mat=cable2mat,loss=C_2loss,Cflag=2),'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 组内,我认为当我发出: prob.set_val('L_L0',31.) 在我的主要内容中设置所有初始值时,将为所有组件分配“L_L0”(或其他提升的输入) .事实并非如此,事实上,L_L0 并没有将其放入任何组件中,但是仅由 Leg 提升的变量(例如 'D_L')确实在 prob.set_val('D_L',2.1) 之后被正确分配。此评估来自 def guess_nonlinear(self,inputs,outputs,residuals) 内,我尝试使用说 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_nonlinearLegCableBal 中,我粗暴地调用其他组件的计算来获得可用的输出

        #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'],'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

解决方法

注意:根据您提供的 N2,您根本不需要组级求解器! 没有任何低对角线连接表明没有组级耦合。因此在群层面没有什么可收敛的,也不需要求解器。

您应该能够在 solve_nonlinearLegCableBal 内进行完全收敛。如果您需要任何额外的数据来在该方法中进行初始猜测,您可以向该组件添加额外的输入。如果您不想编写自己的求解器,您可以使用 OpenMDAO 的非线性求解器,方法是在组件级别分配它们,就像分配给任何组一样。或者,您可以根据需要编写自己的求解器。

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

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

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

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

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

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...