VBA:缓慢的求解器循环

我有一个代码,以简化的方式计算高炉煤气168小时(例如一周)

它读入一些input值和化学值并计算系统中的摩尔质量。 之后求解器计算出什么样的化学forms(主要是一氧化碳,二氧化碳)的气体出来。问题是,它是非常缓慢的。 如果我打开这个excel工作簿,需要花费几分钟的时间,而且我还没有打算让更多的工作簿打开到最后。

我对VBA很陌生,但是如果可以设置它来解决VBA中的方程式,而不是让excel工作表和VBA解算器之间的迭代,通过逐渐解决细胞价值 – 如果我只是知道如何,如果这是可能的或一个好主意。

其实体中的代码,首先是一般的计算:

Sub BFgas() Datamatrix = Range(Cells.Find("Datamatrix").Offset(1, 0).Address, Cells.Find("Datamatrix").Offset(21, 0).Address) ReDim BFoutput(1 To 168, 1 To 3) As Double M_pigiron_Matrix = Range(Cells.Find("BF1 Pig iron production").Offset(1, 0).Address, Cells.Find("BF1 Pig iron production").Offset(168 + 1, 0).Address) Bf_blast_Matrix = Range(Cells.Find("BF 1 - Blast").Offset(1, 0).Address, Cells.Find("BF 1 - Blast").Offset(168 + 1, 0).Address) Bf_oxygen_Matrix = Range(Cells.Find("BF 1 - Oxygen").Offset(1, 0).Address, Cells.Find("BF 1 - Oxygen").Offset(168 + 1, 0).Address) M = 1 Do M_pigiron = M_pigiron_Matrix(M, 1) 'Tons of pig iron Bf_blast = Bf_blast_Matrix(M, 1) 'Nm3 Bf_oxygen = Bf_oxygen_Matrix(M, 1) 'Nm3 If Bf_blast = 0 Or Bf_oxygen = 0 Then Do M_pigiron = M_pigiron_Matrix(M, 1) 'Tons of pig iron Bf_blast = Bf_blast_Matrix(M, 1) 'Nm3 Bf_oxygen = Bf_oxygen_Matrix(M, 1) 'Nm3 M = M + 1 Loop While Bf_oxygen = 0 Or Bf_blast = 0 End If n_N2_blast = Bf_blast * Datamatrix(19, 1) / Datamatrix(17, 1) 'kmol n_O2_blast = Bf_blast * Datamatrix(18, 1) / Datamatrix(17, 1) 'kmol n_O2_oxygenintake = Bf_oxygen / Datamatrix(17, 1) 'kmol n_total_O_in = (n_O2_blast + n_O2_oxygenintake) * 2 'kmol 'Calculates the amounts of coke, briquettes and scrap Cokeratio = Cells.Find("Input data").Offset(1, 1).Value2 Briqratio = Cells.Find("Input data").Offset(2, 1).Value2 Scrapratio = Cells.Find("Input data").Offset(3, 1).Value2 m_oil = Cells.Find("Input data").Offset(4, 1).Value2 m_coke = Cokeratio * M_pigiron * 1000 'kg m_briq = Briqratio * M_pigiron 'kg m_scrap = Scrapratio * M_pigiron 'kg 'Fe/Iron calculations 'Calculates the molar masses of iron and coal in pig iron, briqettes and scrap n_Fe_pigiron = Datamatrix(3, 1) * M_pigiron * 1000 / Datamatrix(15, 1) 'kmol n_Fe_briq = Datamatrix(12, 1) * m_briq / Datamatrix(15, 1) 'kmol n_Fe_scrap = Datamatrix(13, 1) * m_scrap / Datamatrix(15, 1) 'kmol 'Calculates how many kmol is needed from pellets n_Fe_pellets = n_Fe_pigiron - n_Fe_briq - n_Fe_scrap m_pellets = n_Fe_pellets / Datamatrix(11, 1) * Datamatrix(15, 1) 'Divides by the iron content 0.72, to get the total mass 'O/Oxygen calculations 'Calculates the total incoming oxygen '(m_pel*x_pellets,O + m_briq*x_O,briq)/M_O + n_blast,O2*2 + n_Oxygen,O2*2 Oxygen_in = m_pellets * Datamatrix(10, 1) / Datamatrix(16, 1) + m_briq * Datamatrix(9, 1) / Datamatrix(16, 1) + n_total_O_in 'kmol Cells.Find("Solutions").Offset(0, 1).Value = Oxygen_in 'C/Coal calculations 'Calculates the incoming coal minus what comes out with the pig iron, leaving what comes out with the bf-gases 'm_coke,*x_C,coke + m_oil*x_C,oil + m_br*x_br,C = m_rj*x_C,rj + V_tg*(y,co + y,co2) Coal_for_bf_gas = (m_coke * Datamatrix(4, 1) / Datamatrix(14, 1) + m_oil * Datamatrix(5, 1) / Datamatrix(14, 1) + m_briq * Datamatrix(6, 1) / Datamatrix(14, 1)) - M_pigiron * 1000 * Datamatrix(1, 1) / Datamatrix(14, 1) Cells.Find("Solutions").Offset(0, 2).Value = Coal_for_bf_gas 'N/Nitrogen 'Nitrogen is mainly what comes in with the blast N2_for_bf_gas = n_N2_blast Cells.Find("Solutions").Offset(0, 3).Value = N2_for_bf_gas 'Sets in the hydrogen just in case 'H/hydrogen 'H_for_bf_gas = m_coke * Datamatrix(21, 1) / Datamatrix(20, 1) + m_oil * Datamatrix(7, 1) / Datamatrix(20, 1) 

解算器部分:

 SolverReset 'Code solves the problem for a specific set of lines, in this case meaning hours SolverOptions Precision:=1, Iterations:=100, AssumeNonNeg:=True SolverOk setCell:=Cells.Find("Differences").Offset(1, 0).Address, MaxMinVal:=3, ValueOf:="0", ByChange:=Range(Cells.Find("Testing here").Offset(0, 1).Address, Cells.Find("Testing here").Offset(0, 3).Address) SolverAdd cellRef:=Range(Cells.Find("Testing here").Offset(0, 2).Address, Cells.Find("Testing here").Offset(0, 3).Address), _ relation:=3, _ formulaText:=0.1 SolverAdd cellRef:=Range(Cells.Find("Testing here").Offset(0, 2).Address, Cells.Find("Testing here").Offset(0, 3).Address), _ relation:=1, _ formulaText:=0.4 SolverAdd cellRef:=Cells.Find("Testing here").Offset(0, 1).Address, _ relation:=3, _ formulaText:=(Bf_blast + Bf_oxygen) * 1.2 SolverAdd cellRef:=Cells.Find("Testing here").Offset(0, 1).Address, _ relation:=1, _ formulaText:=(Bf_blast + Bf_oxygen) * 2 SolverSolve userFinish:=True BFoutput(M, 1) = Cells.Find("Testing here").Offset(0, 1).Value BFoutput(M, 2) = Cells.Find("Testing here").Offset(0, 2).Value BFoutput(M, 3) = Cells.Find("Testing here").Offset(0, 3).Value M = M + 1 Loop While M < 169 Cells.Find("BF1 - Output data").Offset(2, 0).Resize(UBound(BFoutput, 1), 3).Value = BFoutput 

我不是化学工程师,所以我不知道你想要解决的方程式。

我猜测他们是非线性的,瞬态的,迭代的。 168 * 3 = 504自由度对我来说似乎并不大,但是如果您有很多时间步骤,并且每个步骤都有迭代,那么可能会有很多工作要做。

我无法确定您是否正在从您发布的代码中执行暂时或稳定状态问题。

我更熟悉的数值问题(固体力学和热传导)对algorithm非常敏感。 由于稳定性的原因,这些方程可能受时间步长的限制,具体取决于所选的积分scheme。

如果你正在解决一个非线性稳态问题,相同的意见将适用,除了迭代步长而不是时间步长。

我不能从你的VB代码中得到这些,但是我会提供这些build议:

  1. 写出你的方程,做一个傅里叶变换,看看是否有任何稳定性的限制。
  2. 想想像Matlab这样的工具包。 他们已经开箱即用,可能比您的自定义代码更优化。
  3. 我不知道有任何VB或Excel的性能分析function,但是如果没有数据,则无法解决问题。 我想知道是否可以在假设解决scheme之前获得有关在何处花费时间的信息。