VBA: Slow solver-loop - excel
I have a code that in a simplified way calculates blast furnace gases for 168 hours (eg a week)
It reads in some input values and chemical values and calculated the molar masses in the system. After that the solver calculates in what chemical form (mainly CO, CO2) the gases exit in.
The problem is that it's extremely slow. If I have this excel workbook open it takes minutes and I haven't even bothered to let it run to the end when there are more workbooks open.
I'm very new to VBA, but I'd expect it to be a bit faster if I could set it to solve the equations in VBA instead of letting the values "iterate" back and forth between the excel worksheet and the VBA solver, by gradually solving the cell values - if I just knew how, IF it is possible or a good idea.
The code in its entity, first the general calculations:
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)
The solver part:
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
I'm not a chemical engineer, so I don't know the equations you're trying to solve.
I'm guessing that they're non-linear, transient, and iterative. 168*3 = 504 degrees of freedom doesn't seem that large to me, but it could be a lot of work if you have lots of small time steps with iterations for each one.
I can't tell if you're doing a transient or steady state problem from the code you posted.
The numerical problems that I'm more familiar with (solid mechanics and heat transfer) are very sensitive to algorithm. The equations can be subject to time step restrictions for stability reasons, depending on the integration scheme chosen.
If you're solving a non-linear steady state problem the same comments would apply, except for iteration step size instead of time step size.
I can't glean much about this from your VB code, but I'll offer these recommendations:
Write out your equations, do a Fourier transform, and see if there are any stability restrictions.
Think about a tool kit like Matlab. They've got out of the box implementations that might be more highly optimized than your custom code.
I'm not aware of any profiling capabilities for VB or Excel, but you can't fix a problem without data. I'd see if I could get some information about where the time is being spent before hypothesizing about a solution.
Related
Inserting simply SUM in a cell formula results in Run-time error 1004
While trying to set some data from one spreadsheet to another in the same excel file it gives a Run-time error 1004: Application-defined or object-defined error. By debugging the code stops to work below when I'm trying to assign to that cell s. Worksheets("Lista Sc").Select With Sheets("Lista Sc") .Range(Cells(riga, 3), Cells(riga + n, 3)).MergeCells = True .Range(Cells(riga, 5), Cells(riga + n, 5)).MergeCells = True .Range(Cells(riga, 21), Cells(riga + n, 21)).MergeCells = True s = "=SOMMA(S" + CStr(riga) + ";T" + CStr(riga + 1) + ":T" + CStr(riga + n) + ")-L" + CStr(riga) .Cells(riga, 21).FormulaLocal = s It's the first time I'm trying to face problems with excel macro, so I have no idea on what's going on.
I suggest you use English with the Formula property, which will work regardless of the user's language settings: .Cells(riga, 21).Formula = "=SUM(S" + CStr(riga) + ",T" + CStr(riga + 1) + ":T" + CStr(riga + n) + ")-L" + CStr(riga)
VBA convert time on Number
I need to convert my time to Number. i need it because letter i'm going to divide this dates by yourself to calculate % (agent productive time ). I tried something like this 'cells(2,3) = 22:12:2 cells(2,3) / (60*60*1000) Thanks in advance
You can do like this: a = "78:19:41" b = "74:23:58" ta = (Split(a, ":")(0) / 24) + TimeValue("00:" & Split(a, ":", 2)(1)) tb = (Split(b, ":")(0) / 24) + TimeValue("00:" & Split(b, ":", 2)(1)) p = tb / ta * 100 p -> 94.9844138434859
Excel VBA function terminates after first loop of for/next loop without finishing function
I just wrote this code to perform an iterative calculation. It finds the X,Y coordinates where an unknown parabola is tangent to a known circle. It is based on other iterative functions I've written that have worked flawlessly. I'm stumped as to what the issue is. Here is the code: Public Function Jext(PA As Double, Xcl As Double, Ycl As Double, Ctr As Double, Rnl As Double, Finl As Double) As Double Pi = 3.14159265358979 tol = 0.00000001 Dim x(20) As Double Dim Yc(20) As Double Dim Yp(20) As Double Dim A(20) As Double Dim Diff(20) As Double Dim It As Integer Dim hF As Double Dim Sf As Double 'Xcl is the horizontal position of the root radius center line 'Ycl is the vertical position of the root radius center line 'Ctr is root radius. It's an approximation of the trochoid and is typically the cutter tip radius 'Rnl is the radius to the point where the load line intersects the tooth centerline. It is the apex of the parabola 'x is the horizontal position that is common to the parabola and circle. It is the independent variable 'Yc is the vertical position on the circle at point x 'Yp is the vertical position on the parabola at point x 'A is the leading term of the parabolic equation 'Diff is the calculated difference in vertical positions of circle and parabola 'Set initial guess values. x(0) is 5% of the radius (left edge of circle) and x(1) is 95% of the radius(bottom of the circle) x(0) = (Xcl - Ctr) + 0.05 * Ctr x(1) = (Xcl - Ctr) + 0.95 * Ctr Yc(0) = Ycl - (Ctr ^ 2 - (x(0) - Xcl) ^ 2) ^ 0.5 Yc(1) = Ycl - (Ctr ^ 2 - (x(1) - Xcl) ^ 2) ^ 0.5 A(0) = Tan(WorksheetFunction.Acos((Xcl - x(0)) / Ctr) + Pi / 2) / (2 * x(0)) A(1) = Tan(WorksheetFunction.Acos((Xcl - x(1)) / Ctr) + Pi / 2) / (2 * x(1)) Yp(0) = A(0) * x(0) ^ 2 + Rnl Yp(1) = A(1) * x(1) ^ 2 + Rnl Diff(0) = Yp(0) - Yc(0) Diff(1) = Yp(1) - Yc(1) For It = 1 To 19 Step 1 x(It + 1) = x(It) - (Diff(It) - 0) * (x(It - 1) - x(It)) / (Diff(It - 1) - Diff(It)) Yc(It + 1) = Ycl - (Ctr ^ 2 - (x(It + 1) - Xcl) ^ 2) ^ 0.5 A(It + 1) = Tan(WorksheetFunction.Acos((Xcl - x(It + 1)) / Ctr) + Pi / 2) / (2 * x(It + 1)) Yp(It + 1) = A(It + 1) * x(It + 1) ^ 2 + Rnl Diff(It + 1) = Yp(It + 1) - Yc(It + 1) If Abs(Diff(It + 1)) < tol Then Exit For Debug.Print Diff(It + 1) Next It hF = Rnl - Yp(t + 1) Sf = 2 * x(t + 1) Jext = 1 / (Cos(Finl) / Cos(PA) * (6 * hF / Sf ^ 2 - Tan(Finl) / Sf)) End Function I put a stop at the "Next It" line to check the values as it went through the iterative loops. When I execute the code, all of the values are as expected and the value of Abs(Diff(It+1)) is not small enough to exit the for loop in the IF statement. I put the Debug.Print statement in there to make sure it was getting that far in the code and it did print Diff(It+1). So it executes everything to that point. Then when I continue the function it just stops and returns a #VALUE error in the spreadsheet. I've no idea why it won't continue the for loop. Anyone see something I've missed?
Step gives error sound but not description
I am trying to run some code on Visual basic and about an hour ago it was working fine. I did something(not sure what) and now it gives an error sound but no description. This only happens when I try to create my own function in a module. I have tried turning my pc on then off. I have opened different excel spreadsheets and yet it still won't let me run my function even with steps. My code below is incomplete but I'm sure it isn't the code itself thats the problem. Function onetube(Thi As Double, Tho As Double, Tci As Double, Tco As Double) As Double Dim phih, phic, phicf As Double Dim ai(1 To 4, 1 To 4) As Variant phih = (Thi - Tho) / (Thi - Tci) phic = (Tco - Tci) / (Thi - Tci) phicf = (phih - phic) / Application.WorksheetFunction.Ln((1 - phic) / (1 - phih)) ai(1, 1) = -0.462 ai(1, 2) = -0.0313 ai(1, 3) = -0.174 ai(1, 4) = -0.042 ai(2, 1) = 5.08 ai(2, 2) = 0.529 ai(2, 3) = 1.32 ai(2, 4) = 0.347 ai(3, 1) = -15.7 ai(3, 2) = -2.37 ai(3, 3) = -2.93 ai(3, 4) = -0.853 ai(4, 1) = 17.2 ai(4, 2) = 3.18 ai(4, 3) = 1.99 ai(4, 4) = 0.649 onetube = phicf End Function
Absolute Value of the Differences In Two (2) Ranges - PART II
Hopefully this is easier to read than yesterday. Trying to find a way to vary the number of periods "N" that measure "VOLATILITY" The code for the complete function as suggested yesterday is below and fixes "N" at 10. Function works just fine for KAMA with the default value for "N" (N0Addr and N1Addr are not needed in this default version of the KAMA function but are steps to get to a variable "N") This formula works in Excel: =SUMPRODUCT((ABS(I26:I36-I25:I35))) I can also obtain the correct sum of differences in the two ranges but not the absolute value. This VBA Code does that with the named ranges "N0Addr" and "N1Addr": Rng0 = WorksheetFunction.Sum(Range(N0Addr)) - WorksheetFunction.Sum(Range(N1Addr)) Function nTEST(Price, nPer, mPer, N) 'Variables Fast = 2 / (nPer + 1) Slow = 2 / (mPer + 1) 'One(1) Prior Period Calculation nTEST1 = Application.Caller.Offset(-1) N0Addr = Application.WorksheetFunction.Concat(Price.Offset(-N, 0).Address & ":" & Price.Address) N1Addr = Application.WorksheetFunction.Concat(Price.Offset(-(N + 1), 0).Address & ":" & (Price.Offset(-1, 0).Address)) 'Change Formula (Y - Yn) E = Abs(Price - Price.Offset(-N, 0)) 'Volatility Formula { =SUM(ABS(Y:Yn)-(Y1:Yn1))) } 'VOLATILITY (N = 10) '1-10 R = Abs(Price - Price.Offset(-1, 0)) + Abs(Price.Offset(-1, 0) - Price.Offset(-2, 0)) _ + Abs(Price.Offset(-2, 0) - Price.Offset(-3, 0)) _ + Abs(Price.Offset(-3, 0) - Price.Offset(-4, 0)) + Abs(Price.Offset(-4, 0) - Price.Offset(-5, 0)) _ + Abs(Price.Offset(-5, 0) - Price.Offset(-6, 0)) + Abs(Price.Offset(-6, 0) - Price.Offset(-7, 0)) _ + Abs(Price.Offset(-7, 0) - Price.Offset(-8, 0)) + Abs(Price.Offset(-8, 0) - Price.Offset(-9, 0)) _ + Abs(Price.Offset(-9, 0) - Price.Offset(-10, 0)) 'EFFICIENCY RATIO ER = E / R Smooth = (ER * (Fast - Slow) + Slow) ^ 2 'Formula Calculation nKAMA = Smooth * Price + (1 - Smooth) * nKAMA1 End Function Looking for an VBA formula or method to input a working formula for "volatility" that can vary over N periods. I can get the sum of differences but not the sum of absolute differences. Rng0 = WorksheetFunction.Sum(Range(N0Addr)) - WorksheetFunction.Sum(Range(N1Addr)) I can also enter one formula in Excel that accomplishes provides the sum of absolute differences. =SUMPRODUCT((ABS(I26:I36-I25:I35)))