Error 400, 1004 in VBA-Excel - vba

I am trying to use a macro written and shared as the supplemental material of a scientific paper published in 1999.
I believe the macro has been written under Excel 1997 environment.
Unfortunately, I have very poor knowledge of VBA-Excel, and as far as I could understand, there might be a problem regarding the call of method .Select or .Range for the ActiveSheet, due to/along with an incompatibility between Excel 1997 and nowadays Excel 2010 (the one I am using).
It seems that VBA-Excel environment has quite a powerful debugging interface, although my poor knowledge of this language doesn't provide sufficient understanding to debug by myself.
My question is: can you try to run the macro, face the bug and corresponding error message, and fix (or help me fixing) the code?
Thank you very much.
Here is the macro:
'
'PSD MACRO
'Macro 7/24/97 by Wayne Lukens
'
'New Sheet Column assignments
'1 - Pressure, Pr = p/p0
'2 - Gas Volume adsorbed, Vg
'3 - Volume adsorbed as liquid, V1
'4 - Critical thickness, Tcr
'5 - Critical Radius, Rcr
'6 - Critical Pressure for Rave, Pave
'7 - Critical Thickness for Rave, Pave
'8 - Average Pore Radius, Rave
'9 - Average Pore Diameter, Dave
'10 - Volume of the Kelvin cores, Vc
'11 - Cross Sectional Area
'12 - Number of pores at a given pressure, Lp
'13 - Total volume of pores of radius Rave, Vc
'14 - Volume of gas desorbed in a step, Vd
'15 - Dave again
'
Sub PSD()
'
'Set up variables
'
Dim Pr(100), Rcr(100), V1(100), Tcr(100), Vd(100), Csa(100), Vc(100), Pave(100)
Dim PoreV(100), Lp(100), Tave(100), Rc(100), Rave(100), Te(100, 100)
Dim Te1 As String
Dim C(10), T, f, df, dx, Tlast As Double
PageTitle = "Adsorp in "
MeniscusTitle = "Hemisperical Meniscus"
Pi = 3.14159
a = 5 * (3.54 ^ 3)
' factoroot = 4.05*Log(10)
R = 0.8314
T = 77.2
RT = R * T
Gamma = 8.72
Vm = 34.68
factoroot = 2 * Gamma * Vm / (R * T)
PoreType = ""
' Welcome = MsgBox("Welcome to Broekhoff-de-Boer analysis with a Frenkel-Halsey-Hill isotherm.",vbOKOnly)
On Error Resume Next
Set dData = Application.InputBox("Please select the cells which contain your isotherm data. The data must " & "contain p/p0 in column 1 and the volume of gas adsorbed (as gas) in column 2.", "Select Isotherm Data", Type:=8)
If Err <> 0 Then
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
'
'Get information from the user to determine pore model and meniscus shape
'
Do Until PoreType = "sphere" Or PoreType = "s" Or PoreType = "cylinder" Or PoreType = "c" Or PoreType = False
PoreType = Application.InputBox("Which pore model are you using, cylinder or sphere (c or s)?", "Pore Model")
Loop
If PoreType = False Then
Exit Sub
End If
answer1 = MsgBox("Is this an adsorption isotherm?", vbYesNo)
Answer2 = MsgBox("Does the isotherm display hysteresis?", vbYesNo)
alpha = InputBox("What is the value of the FHH parameter, alpha? (Default = 5*3.54^3)", "Enter alpha", a)
If answer1 = vbNo Then
PoreType = "c"
PageTitle = "Desorp from"
End If
If PoreType = "sphere" Or PoreType = "s" Then
ModelSheet = "Spheres"
PoreType = "s"
factory = factoroot
PoreTitle = "Spherical Pores"
Else
ModelSheet = "Cylinders"
PoreType = "c"
factory = factoroot / 2
PoreTitle = "Cylindrical Pores"
End If
If Answer2 = vbNo Then ModelSheet = ModelSheet & "no Hy"
If alpha = "" Then
Exit Sub
End If
If answer1 = vbYes Then
celltitle = "Adsorption in " & ModelSheet
Else
celltitle = "Desorption from " & ModelSheet
End If
ModelSheet = PageTitle & ModelSheet
'
'Copy selected data to new sheets.
'
ActiveSheet.Activate
dData.Select
Selection.Copy
'Application.Workbook.Add
ActiveSheet.Activate
Sheets.Add
ActiveSheet.Paste
ActiveSheet.Name = ModelSheet
Sheets(ModelSheet).Activate
Selection.Sort Key1:=ActiveCell, Order1:=xlDescending, Header:=xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBotom
'
'Convert gas volumes into liquid volumes
'
iRows = Selection.Rows.Count
Cells(1, 3).Formula = " =B1*0.0015468"
Cells(1, 3).Select
Selection.AutoFill Destination:=Range(Cells(1, 3), Cells(iRows, 3)), Type:=x1FillDefault
'
'Fill array
'
For I = 1 To iRows
Pr(I) = Cells(I, 1)
V1(I) = Cells(I, 3)
Next I
If answer1 = vbNo Or Answer2 = vbNo Then
'
'Calculate Critical Radius and Pore Diameter at each Pressure for a Desorption Branch
'
If answer1 = vbNo Then
BranchTitle = "Desorption from"
Else
BranchTitle = "Adsorption w/o Hysteresis" & Chr(13) & "in"
End If
fa = factoroot / 2
For I = 1 To iRows
Inp = -Log(Pr(I))
THigh = 5 * (alpha / Inp) ^ (1 / 3)
TLow = 0.5 * (alpha / Inp) ^ (1 / 3)
T = 3 * (alpha / Inp) ^ (1 / 3)
C(1) = alpha * alpha / Inp
C(2) = 0#
C(3) = -2 * alpha * fa / Inp
C(4) = -2 * alpha
C(5) = 0#
C(6) = fa
C(7) = Inp
For K = 1 To 20
f = C(1) + T * T * (C(3) + T * (C(4) + T * T * (C(6) + T * C(7))))
df = T * (2 * C(3) + T * (3 * C(4) + T * T * (5 * C(6) + T * 6 * C(7))))
dx = f / df
If dx > 0 Then
THigh = T
End If
If dx < 0 Then
TLow = T
End If
T = T - dx
If (Abs(dx) < 0.00000000000001) Then Exit For
If T > THigh Then
T = (THigh + Tlast) / 2
End If
If T < TLow Then
T = (TLow + Tlast / 2)
End If
Tlast = T
Next K
Tcr(I) = T
Cells(I, 4) = T
Rcr(I) = Tcr(I) + fa / (Inp - alpha / (Tcr(I) ^ 3))
Next I
Else
'
'Calculate Critical Radius and Pore Diameter at each pressure for an Adsorption Branch
'
If PoreType = "c" Then MeniscusTitle = "Cylindrical Meniscus"
BranchTitle = "Adsorption in"
For I = 1 To iRows
logprel = Log(Pr(I))
q = -((alpha * factory / 3) ^ 0.5) / logprel
R = alpha / (2 * logprel)
If R ^ 2 < q ^ 3 Then
x = R / Sqr(q ^ 3)
theta = Atn(-x / Sqr(-x * x + 1)) + 1.5708
root2 = -2 * Sqr(q) * Cos((theta + 2 * 3.14159) / 3)
Tcr(I) = root2
Else
a = -Sgn(R) * (Abs(R) + Sqr(R ^ 2 - q ^ 3)) ^ (1 / 3)
b = q / a
Tcr(I) = a + b
End If
Rcr(I) = Tcr(I) + factory / (-logprel - alpha / Tcr(I) ^ 3)
Next I
End If
'
'Calculate the average pore radius for this desorption step
'
For I = 1 To iRows - 1
Rave(I) = (Rcr(I) + Rcr(I + 1)) * Rcr(I) * Rcr(I + 1) / (Rcr(I) ^ 2 + Rcr(I + 1) ^ 2)
'
'Calculate the critical thickness and pressure for each Rave since Rave is known
'
a = Sqr(factory)
b = Sqr(3 * alpha)
d = -Rave(I) * b
q = -0.5 * (b + Sgn(b) * Sqr(b ^ 2 - 4 * a * d))
Tave(I) = d / q
Pave(I) = Exp(-(factory / (Rave(I) - Tave(I)) + alpha / Tave(I) ^ 3))
Next I
'
'Calculate Equilibrium Thickness at every pressure for each pore radius using the Newton-Raphson method
'
C(2) = alpha
C(3) = 0#
For I = 2 To iRows
Rcrit = Rave(I - 1)
C(1) = -alpha * Rcrit
T = Tcr(I)
For J = I + 1 To iRows + 1
Prel = Pr(J - 1)
Plog = -Log(Prel)
C(5) = -Plog
C(4) = Rcrit * Plog - factory
For K = 1 To 20
f = C(1) + T * (C(2) + T ^ 2 * (C(4) + T * C(5)))
df = C(2) + T * (T * (3 * C(4) + T * 4 * C(5)))
dx = f / df
T = T - dx
If (Abs(dx) < 0.0000000001) Then Exit For
Next K
Te(J - 1, I - 1) = T
Next J
Next I
'
'Do the iterative part of the analysis
'
For I = 1 To iRows - 1
'
'Calculate volume change for all previously opened pores
'
Vd(I) = 0#
If I = 1 Then
Vd(I) = 0#
Else
For J = 1 To I - 1
'
'Calculate the total volume desorbed from the open pores during this interval
'
If PoreType = "s" Then
Vd(I) = Vd(I) + 1E-24 * (4 / 3) * Pi * ((Rave(J) - Te(I + 1, J)) ^ 3 - (Rave(J) - Te(I, J)) ^ 3) * Lp(J)
'Note : In this case, Lp(J) is the number of spherical pores
Else
If PoreType = "c" Then
Vd(I) = Vd(I) + 1E-16 * Pi * ((Rave(J) - Te(I + 1, J)) ^ 2 - (Rave(J) - Te(I, J)) ^ 2) * Lp(J)
'Note : in this case, Lp(J) is the length of the cylindrical pore in cm.
Else
sorry = MsgBox("error at Vd(I) stae", vbOKOnly)
Exit Sub
End If
End If
Next J
End If
'
'Determine what's going on
'
If Vd(I) >= (V1(I) - V1(I + 1)) Then
'
'The volume desorbed is less than the volume expected from desorption from opened pores, set the volume of the new pores to zero
'
'
Lp(I) = 0#
Vc(I) = 0#
Csa(I) = 0#
Else
'
'The volume desorbed is greater thant the volume expected, so the new pores must have opened
'
Vc(I) = V1(I) - V1(I + 1) + Vd(I)
'
'Calculate the volume of the newly opened pores in cm3 at the end of the interval
'
If PoreType = "s" Then
Csa(I) = 4E-24 * (Pi / 3) * (Rave(I) - Te(I + 1, I)) ^ 3
Else
If PoreType = "c" Then
Csa(I) = Pi * 1E-16 * (Rave(I) - Te(I + 1, I)) ^ 2
Else
sorry = MsgBox("error at Csa calculation", vbOKOnly)
Exit Sub
End If
End If
'
'Calculate the number of pores
'
Lp(I) = Vc(I) / Csa(I)
End If
'
'Write values of important numbers to the worksheet"
'
If PoreType = "s" Then
PoreV(I) = 4E-24 * (Pi / 3) * Lp(I) * Rave(I) ^ 3
Else
If PoreType = "c" Then
PoreV(I) = 1E-16 * Lp(I) * Pi * Rave(I) ^ 2
Else
sorry = MsgBox("error at PoreV calculation", vbOKOnly)
Exit Sub
End If
End If
Next I
'
'Do calculations for Incremental Pore Volumee
'
Bigpoint = 0
BigPointNumber = 1
CumSA = 0
CumPV = 0
For J = 1 To iRows - 1
Cells(J, 4) = Tcr(J)
Cells(J, 5) = Rcr(J)
Cells(J, 6) = Pave(J)
Cells(J, 7) = Tave(J)
Cells(J, 8) = Rave(J)
Cells(J, 9) = Rave(J) * 2
Cells(J, 10) = Vc(J)
Cells(J, 11) = Csa(J)
Cells(J, 12) = Lp(J)
Cells(J, 13) = PoreV(J)
Cells(J, 14) = Vd(J)
Cells(J, 15) = Rave(J) * 2
Cells(J, 16) = PoreV(J)
If Rave(J) < 10 Then Exit For
If Cells(J, 16) > Bigpoint Then
BigPointNumber = J
Bigpoint = Cells(J, 16)
End If
'
'Calculate Surface Area in m2/g
'
If PoreType = "s" Then
Cells(J, 17) = 4E-20 * Pi * Lp(J) * Rave(J) ^ 2
Else
If PoreType = "c" Then
Cells(J, 17) = 0.000000000002 * Pi * Lp(J) * Rave(J)
Else
sorry = MsgBox("Error at cumulative surface area calculation", vbOKOnly)
Exit Sub
End If
End If
CumSA = CumSA + Cells(J, 17)
CumPV = CumPV + PoreV(J)
Cells(J, 18) = CumSA
Cells(J, 19) = CumPV
Next J
'
'Give Cells Headings
'
Cells(1, 1).Select
Selection.EntireRow.Insert
Cells(1, 1) = "Rel pres"
Cells(1, 2) = "Vol as gas"
Cells(1, 3) = "vol as liq"
Cells(1, 4) = "Crit thick"
Cells(1, 5) = "Crit radius"
Cells(1, 6) = "Avg pres"
Cells(1, 7) = "Avg thick"
Cells(1, 8) = "Avg radius"
Cells(1, 9) = "Avg diam"
Cells(1, 10) = "Vol cores"
Cells(1, 11) = "X sect area"
Cells(1, 12) = "Pore length"
Cells(1, 13) = celltitle
Cells(1, 14) = "Vol desorp"
Cells(1, 15) = "Avg diam"
Cells(1, 16) = celltitle
Cells(1, 17) = "Surf area"
Cells(1, 18) = "Cumul SA"
Cells(1, 19) = "Cumul PoreV"
SurfaceArea = Fix(CumSA + 0.5)
PoreVolume = Fix(100 * CumPV + 0.5) / 100
'
'Create a chart
'
Columns("O:O").Select
Selection.NumberFormat = "0"
Charts.Add
ActiveChart.ChartWizard Source:=Sheets(ModelSheet).Range("$O:$P"), Gallery:=xlXYScatter, Format:=2, PlotBy:=xlColumns, CategoryLabels:=1, SeriesLabels:=1, HasLegend:=2, Title:="Plot for" & celltitle, CategoryTitle:="Pore Diameter in Angstroms", ValueTitle:="Pore Volume in cc per gram", ExtraTitle:=""
ActiveChart.PlotArea.Select
Nombre = ModelSheet & "Plot"
ActiveSheet.Name = Nombre
End Sub
One can try the macro with the following set of data to embed in the sheet:
0.0106908 103.046
0.031249 120.144
0.0515578 129.808
0.0772499 138.616
0.100304 144.98
0.120399 149.797
0.140559 154.187
0.160819 158.255
0.18104 162.065
0.20132 165.698
0.24889 173.67
0.278214 178.398
0.303499 182.434
0.350487 189.809
0.375365 193.778
0.400622 197.828
0.425556 201.949
0.450624 206.146
0.475636 210.459
0.50072 214.991
0.525794 219.652
0.550631 224.562
0.575897 229.666
0.600643 235.066
0.625847 240.934
0.650973 247.074
0.675899 253.657
0.701025 260.816
0.725913 268.534
0.75098 277.212
0.776003 287.031
0.801318 298.016
0.813639 304.484
0.826658 311.591
0.838517 318.99
0.851442 327.799
0.863629 337.611
0.876573 349.305
0.888307 362.915
0.900328 383.552
0.911067 419.354
0.92187 475.714
0.952079 631.959
0.97104 817.134
0.979005 1038.01
0.984323 1250.95
0.99039 1436.81
Thanks again.

Here's an updated version of the code. I've done the following:
Declared and sorted all variables
Given the code a good structure (tab-wise)
Made the code run in background (speeded up code from 10s to >1s)
The code begins with removing old data (generated charts and sheets)
Option Explicit
' Books & Sheets
Dim Wb1 As Workbook
Dim Sh1 As Worksheet, Sh2 As Worksheet
' Doubles: One letter
Dim A As Double, B As Double, D As Double, F As Double, J As Double, K As Double
Dim R As Double, Q As Double, T As Double, X As Double
' Doubles: Two letters
Dim dF As Double, dX As Double, fA As Double, Vm As Double, Rt As Double, Pi As Double
' Doubles: Three or more letters
Dim Alpha As Double, BigPoint As Double, BigPointNumber As Double, CumSA As Double, CumPV As Double
Dim Factory As Double, Gamma As Double, Inp As Double, LogpRel As Double, pLog As Double
Dim PoreVolume As Double, pRel As Double, rCrit As Double, Root2 As Double, SurfaceArea As Double
Dim Theta As Double, tHigh As Double, tLast As Double, tLow As Double
' Doubles: Arrays
Dim C(10) As Double, Csa(100) As Double, Lp(100) As Double, Pave(100) As Double, PoreV(100) As Double
Dim Pr(100) As Double, Rave(100) As Double, Rc(100) As Double, Rcr(100) As Double, Tave(100) As Double
Dim Tcr(100) As Double, Te(100, 100) As Double, V1(100) As Double, Vc(100) As Double, Vd(100) As Double
' Longs
Dim i&, iRows&
' Strings ($)
Dim BranchTitle$, CellTitle$, FactoRoot$, MeniscusTitle$, ModelSheet$
Dim PageTitle$, PoreTitle$, PoreType$, Spheres$, Te1$
' Booleans (True or False)
Dim Answer1 As Boolean, Answer2 As Boolean
' Range
Dim dData As Range
' PSD MACRO
' Macro 7/24/97 by Wayne Lukens
'
' New Sheet Column assignments
' 1 - Pressure, Pr = p/p0
' 2 - Gas Volume adsorbed, Vg
' 3 - Volume adsorbed as liquid, V1
' 4 - Critical thickness, Tcr
' 5 - Critical Radius, Rcr
' 6 - Critical Pressure for Rave, Pave
' 7 - Critical Thickness for Rave, Pave
' 8 - Average Pore Radius, Rave
' 9 - Average Pore Diameter, Dave
' 10 - Volume of the Kelvin cores, Vc
' 11 - Cross Sectional Area
' 12 - Number of pores at a given pressure, Lp
' 13 - Total volume of pores of radius Rave, Vc
' 14 - Volume of gas desorbed in a step, Vd
' 15 - Dave again
Sub PSD()
' Declare books and sheets
Set Wb1 = ThisWorkbook
Set Sh1 = Wb1.Sheets("Data")
' Delete old sheets if existing (graph and database)
Application.DisplayAlerts = False
Application.Calculation = xlCalculationManual
On Error Resume Next
Sheets("Adsorp in Cylinders").Delete
Sheets("Adsorp in Spheres").Delete
Sheets("Adsorp in CylindersPlot").Delete
Sheets("Adsorp in SpheresPlot").Delete
Sheets("CylindersPlot").Delete
Sheets("SpheresPlot").Delete
On Error GoTo 0
Application.DisplayAlerts = True
' Set up variables
PageTitle = "Adsorp in "
MeniscusTitle = "Hemisperical Meniscus"
Pi = WorksheetFunction.Pi
A = 5 * (3.54 ^ 3)
' factoroot = 4.05*Log(10)
R = 0.8314
T = 77.2
Rt = R * T
Gamma = 8.72
Vm = 34.68
FactoRoot = 2 * Gamma * Vm / (R * T)
PoreType = ""
' Welcome = MsgBox("Welcome to Broekhoff-de-Boer analysis with a Frenkel-Halsey-Hill isotherm.",vbOKOnly)
On Error Resume Next
Set dData = Application.InputBox("Please select the cells which contain your isotherm data." & _
"The data must " & "contain p/p0 in column 1 and the volume of gas adsorbed (as gas) in column 2.", _
"Select Isotherm Data", Type:=8)
If Err <> 0 Then
On Error GoTo 0
Exit Sub
End If
On Error GoTo 0
' Run everything in background (code runs faster)
Application.ScreenUpdating = False
Set dData = dData.SpecialCells(xlCellTypeConstants) ' Removes all cells but constants from selection
' Get information from the user to determine pore model and meniscus shape
Do Until PoreType = "sphere" Or PoreType = "s" Or PoreType = "cylinder" Or PoreType = "c"
PoreType = Application.InputBox("Which pore model are you using, cylinder or sphere (c or s)?", "Pore Model")
If PoreType = "" Then Exit Sub
Loop
Answer1 = MsgBox("Is this an adsorption isotherm?", vbYesNo)
Answer2 = MsgBox("Does the isotherm display hysteresis?", vbYesNo)
Alpha = InputBox("What is the value of the FHH parameter, alpha? (Default = 5*3.54^3)", "Enter alpha", A)
If Answer1 = False Then
PoreType = "c"
PageTitle = "Desorp from"
End If
If PoreType = "sphere" Or PoreType = "s" Then
ModelSheet = "Spheres"
PoreType = "s"
Factory = FactoRoot
PoreTitle = "Spherical Pores"
Else
ModelSheet = "Cylinders"
PoreType = "c"
Factory = FactoRoot / 2
PoreTitle = "Cylindrical Pores"
End If
If Answer2 = False Then ModelSheet = ModelSheet & "no Hy"
If Alpha = 0 Then Exit Sub
If Answer1 = True Then
CellTitle = "Adsorption in " & ModelSheet
Else
CellTitle = "Desorption from " & ModelSheet
End If
' Copy selected data to new sheets
dData.Copy
Sheets.Add After:=Sh1
ActiveSheet.Paste
ActiveSheet.Name = PageTitle & ModelSheet
Set Sh2 = Wb1.Sheets(PageTitle & ModelSheet)
Selection.Sort Key1:=ActiveCell, Order1:=xlDescending, Header:=xlGuess, OrderCustom:=1, MatchCase:=False, Orientation:=xlTopToBottom
' Convert gas volumes into liquid volumes
iRows = Selection.Rows.Count
Cells(1, 3).Formula = "=B1*0.0015468"
Range(Cells(2, 3), Cells(iRows, 3)).Formula = Cells(1, 3).Formula
' Fill array
For i = 1 To iRows
Pr(i) = Cells(i, 1)
V1(i) = Cells(i, 3)
Next i
If Answer1 = False Or Answer2 = False Then
' Calculate Critical Radius and Pore Diameter at each Pressure for a Desorption Branch
If Answer1 = vbNo Then
BranchTitle = "Desorption from"
Else
BranchTitle = "Adsorption w/o Hysteresis" & Chr(13) & "in"
End If
fA = FactoRoot / 2
For i = 1 To iRows
Inp = -Log(Pr(i))
tHigh = 5 * (Alpha / Inp) ^ (1 / 3)
tLow = 0.5 * (Alpha / Inp) ^ (1 / 3)
T = 3 * (Alpha / Inp) ^ (1 / 3)
C(1) = Alpha * Alpha / Inp
C(2) = 0#
C(3) = -2 * Alpha * fA / Inp
C(4) = -2 * Alpha
C(5) = 0#
C(6) = fA
C(7) = Inp
For K = 1 To 20
F = C(1) + T * T * (C(3) + T * (C(4) + T * T * (C(6) + T * C(7))))
dF = T * (2 * C(3) + T * (3 * C(4) + T * T * (5 * C(6) + T * 6 * C(7))))
dX = F / dF
If dX > 0 Then tHigh = T
If dX < 0 Then tLow = T
T = T - dX
If (Abs(dX) < 0.00000000000001) Then Exit For
If T > tHigh Then T = (tHigh + tLast) / 2
If T < tLow Then T = (tLow + tLast / 2)
tLast = T
Next K
Tcr(i) = T
Cells(i, 4) = T
Rcr(i) = Tcr(i) + fA / (Inp - Alpha / (Tcr(i) ^ 3))
Next i
Else
' Calculate Critical Radius and Pore Diameter at each pressure for an Adsorption Branch
If PoreType = "c" Then MeniscusTitle = "Cylindrical Meniscus"
BranchTitle = "Adsorption in"
For i = 1 To iRows
LogpRel = Log(Pr(i))
Q = -((Alpha * Factory / 3) ^ 0.5) / LogpRel
R = Alpha / (2 * LogpRel)
If R ^ 2 < Q ^ 3 Then
X = R / Sqr(Q ^ 3)
Theta = Atn(-X / Sqr(-X * X + 1)) + 1.5708
Root2 = -2 * Sqr(Q) * Cos((Theta + 2 * 3.14159) / 3)
Tcr(i) = Root2
Else
A = -Sgn(R) * (Abs(R) + Sqr(R ^ 2 - Q ^ 3)) ^ (1 / 3)
B = Q / A
Tcr(i) = A + B
End If
Rcr(i) = Tcr(i) + Factory / (-LogpRel - Alpha / Tcr(i) ^ 3)
Next i
End If
' Calculate the average pore radius for this desorption step
For i = 1 To iRows - 1
Rave(i) = (Rcr(i) + Rcr(i + 1)) * Rcr(i) * Rcr(i + 1) / (Rcr(i) ^ 2 + Rcr(i + 1) ^ 2)
' Calculate the critical thickness and pressure for each Rave since Rave is known
A = Sqr(Factory)
B = Sqr(3 * Alpha)
D = -Rave(i) * B
Q = -0.5 * (B + Sgn(B) * Sqr(B ^ 2 - 4 * A * D))
Tave(i) = D / Q
Pave(i) = Exp(-(Factory / (Rave(i) - Tave(i)) + Alpha / Tave(i) ^ 3))
Next i
'Calculate Equilibrium Thickness at every pressure for each pore radius using the Newton-Raphson method
C(2) = Alpha
C(3) = 0#
For i = 2 To iRows
rCrit = Rave(i - 1)
C(1) = -Alpha * rCrit
T = Tcr(i)
For J = i + 1 To iRows + 1
pRel = Pr(J - 1)
pLog = -Log(pRel)
C(5) = -pLog
C(4) = rCrit * pLog - Factory
For K = 1 To 20
F = C(1) + T * (C(2) + T ^ 2 * (C(4) + T * C(5)))
dF = C(2) + T * (T * (3 * C(4) + T * 4 * C(5)))
dX = F / dF
T = T - dX
If (Abs(dX) < 0.0000000001) Then Exit For
Next K
Te(J - 1, i - 1) = T
Next J
Next i
' Do the iterative part of the analysis
For i = 1 To iRows - 1
' Calculate volume change for all previously opened pores
Vd(i) = 0#
If i = 1 Then
Vd(i) = 0#
Else
For J = 1 To i - 1
' Calculate the total volume desorbed from the open pores during this interval
If PoreType = "s" Then
Vd(i) = Vd(i) + 1E-24 * (4 / 3) * Pi * ((Rave(J) - Te(i + 1, J)) ^ 3 - (Rave(J) - Te(i, J)) ^ 3) * Lp(J)
' Note : In this case, Lp(J) is the number of spherical pores
Else
If PoreType = "c" Then
Vd(i) = Vd(i) + 1E-16 * Pi * ((Rave(J) - Te(i + 1, J)) ^ 2 - (Rave(J) - Te(i, J)) ^ 2) * Lp(J)
' Note : in this case, Lp(J) is the length of the cylindrical pore in cm.
Else
MsgBox "Error at Vd(I) stae", vbOKOnly
Exit Sub
End If
End If
Next J
End If
' Determine what's going on
If Vd(i) >= (V1(i) - V1(i + 1)) Then
' The volume desorbed is less than the volume expected from desorption from opened pores, set the volume of the new pores to zero
Lp(i) = 0#
Vc(i) = 0#
Csa(i) = 0#
Else
' The volume desorbed is greater thant the volume expected, so the new pores must have opened
Vc(i) = V1(i) - V1(i + 1) + Vd(i)
' Calculate the volume of the newly opened pores in cm3 at the end of the interval
If PoreType = "s" Then
Csa(i) = 4E-24 * (Pi / 3) * (Rave(i) - Te(i + 1, i)) ^ 3
Else
If PoreType = "c" Then
Csa(i) = Pi * 1E-16 * (Rave(i) - Te(i + 1, i)) ^ 2
Else
MsgBox "Error at Csa calculation", vbOKOnly
Exit Sub
End If
End If
' Calculate the number of pores
Lp(i) = Vc(i) / Csa(i)
End If
' Write values of important numbers to the worksheet
If PoreType = "s" Then
PoreV(i) = 4E-24 * (Pi / 3) * Lp(i) * Rave(i) ^ 3
Else
If PoreType = "c" Then
PoreV(i) = 1E-16 * Lp(i) * Pi * Rave(i) ^ 2
Else
MsgBox "Error at PoreV calculation", vbOKOnly
Exit Sub
End If
End If
Next i
'Do calculations for Incremental Pore Volumee
BigPoint = 0
BigPointNumber = 1
CumSA = 0
CumPV = 0
For J = 1 To iRows - 1
Cells(J, 4) = Tcr(J)
Cells(J, 5) = Rcr(J)
Cells(J, 6) = Pave(J)
Cells(J, 7) = Tave(J)
Cells(J, 8) = Rave(J)
Cells(J, 9) = Rave(J) * 2
Cells(J, 10) = Vc(J)
Cells(J, 11) = Csa(J)
Cells(J, 12) = Lp(J)
Cells(J, 13) = PoreV(J)
Cells(J, 14) = Vd(J)
Cells(J, 15) = Rave(J) * 2
Cells(J, 16) = PoreV(J)
If Rave(J) < 10 Then Exit For
If Cells(J, 16) > BigPoint Then
BigPointNumber = J
BigPoint = Cells(J, 16)
End If
'Calculate Surface Area in m2/g
If PoreType = "s" Then
Cells(J, 17) = 4E-20 * Pi * Lp(J) * Rave(J) ^ 2
Else
If PoreType = "c" Then
Cells(J, 17) = 0.000000000002 * Pi * Lp(J) * Rave(J)
Else
MsgBox "Error at cumulative surface area calculation", vbOKOnly
Exit Sub
End If
End If
CumSA = CumSA + Cells(J, 17)
CumPV = CumPV + PoreV(J)
Cells(J, 18) = CumSA
Cells(J, 19) = CumPV
Next J
'Give Cells Headings
Rows(1).Insert
Cells(1, 1) = "Rel pres"
Cells(1, 2) = "Vol as gas"
Cells(1, 3) = "vol as liq"
Cells(1, 4) = "Crit thick"
Cells(1, 5) = "Crit radius"
Cells(1, 6) = "Avg pres"
Cells(1, 7) = "Avg thick"
Cells(1, 8) = "Avg radius"
Cells(1, 9) = "Avg diam"
Cells(1, 10) = "Vol cores"
Cells(1, 11) = "X sect area"
Cells(1, 12) = "Pore length"
Cells(1, 13) = CellTitle
Cells(1, 14) = "Vol desorp"
Cells(1, 15) = "Avg diam"
Cells(1, 16) = CellTitle
Cells(1, 17) = "Surf area"
Cells(1, 18) = "Cumul SA"
Cells(1, 19) = "Cumul PoreV"
SurfaceArea = Fix(CumSA + 0.5)
PoreVolume = Fix(100 * CumPV + 0.5) / 100
'Create a chart
Columns("O:O").NumberFormat = "0"
Range("A1").Select
ActiveSheet.UsedRange.Columns.AutoFit
Charts.Add After:=Sh1
ActiveChart.ChartWizard Source:=Sheets(PageTitle & ModelSheet).Range("$O:$P"), Gallery:=xlXYScatter, _
Format:=2, PlotBy:=xlColumns, CategoryLabels:=1, SeriesLabels:=1, HasLegend:=2, _
Title:="Plot for" & CellTitle, CategoryTitle:="Pore Diameter in Angstroms", _
ValueTitle:="Pore Volume in cc per gram", ExtraTitle:=""
ActiveSheet.Name = ModelSheet & "Plot"
Calculate
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub

Couple of simple issues:
Cells(1, 3).Formula = " =B1*0.0015468"
needs to be:
Cells(1, 3).Formula = "=B1*0.0015468"
without the space before the '=' sign.
Also,
xlTopToBotom is misspelled - it needs to be xlTopToBottom. Similarly, x1FillDefault needs to be xlFillDefault (XL at the start, not X1)

Related

Format of long strings in VBA IDE

I'm writing a macro which takes a VBA code module, exports it, reads the exported file into a 64 bit string and saves this as a constant in another VBA module (by using VBComponent.codeModule.InsertLines). For some reason, my 64 bit strings have linebreaks every 72 characters in the IDE (see image)
For some reason the strings generated from exporting files do this, but not a string generated with String(500,"a"). I wonder whether anyone can provide any insight into this behaviour, I would like the entire expression to be on a single line.
Sub test() 'in a module named "testModule"
exampleString = String(500, "a")
ThisWorkbook.VBProject.VBComponents.Item("testModule").codeModule.InsertLines _
2, "Const str As String = """ & exampleString & """"
End Sub
gives
Sub test() 'in a module named "testModule"
Const str As String = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
exampleString = String(500, "a")
ThisWorkbook.VBProject.VBComponents.Item("testModule").codeModule.InsertLines _
2, "Const str As String = """ & exampleString & """"
End Sub
while
exampleString = Base64EncodedModule()
results in that bizarre behaviour in the image. Maybe there's something really obvious I'm missing, but the base64 string looks exactly like something I could type, so I don't know why it's being split over multiple lines when I write it to the codeModule programmatically.
A minimum bit of code
Function Base64EncodedModule() As String
'export module
Dim exportPath As String: exportPath = Environ("temp") & "\" & "tempModule.bas"
ThisWorkbook.VBProject.VBComponents("Module1").Export exportPath
'read file as bytes
Dim inStream As Object: Set inStream = CreateObject("ADODB.Stream")
inStream.Open
inStream.Type = 1 'Binary file
inStream.LoadFromFile exportPath
'encode as base 64
Dim objXML As MSXML2.DOMDocument
Dim objNode As MSXML2.IXMLDOMElement
Set objXML = New MSXML2.DOMDocument
Set objNode = objXML.createElement("b64")
objNode.DataType = "bin.base64"
objNode.nodeTypedValue = inStream.Read() 'read bytes from file
Base64EncodedModule = objNode.text
Kill exportPath 'remove temp file
End Function
The string is base64 encoded and can contain line separators every n blocks of 4 chars depending on the encoding algorithm. It seems to be the case here.
So either remove the line breaks with Replace or use a decoding/encoding algorithm without line break like this one:
'
' Base 64 encoding '
'
Public Sub FromBase64(Text As String, Out() As Byte)
Dim b64(0 To 255) As Byte, str() As Byte, i&, j&, v&, b0&, b1&, b2&, b3&
Out = ""
If Len(Text) Then Else Exit Sub
str = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
For i = 2 To UBound(str) Step 2
b64(str(i)) = i \ 2
Next
ReDim Out(0 To ((Len(Text) + 3) \ 4) * 3 - 1)
str = Text & String$(2, 0)
For i = 0 To UBound(str) - 7 Step 2
b0 = b64(str(i))
If b0 Then
b1 = b64(str(i + 2))
b2 = b64(str(i + 4))
b3 = b64(str(i + 6))
v = b0 * 262144 + b1 * 4096& + b2 * 64& + b3 - 266305
Out(j) = v \ 65536
Out(j + 1) = (v \ 256&) Mod 256
Out(j + 2) = v Mod 256
j = j + 3
i = i + 6
End If
Next
If b2 = 0 Then
Out(j - 3) = (v + 65) \ 65536
j = j - 2
ElseIf b3 = 0 Then
Out(j - 3) = (v + 1) \ 65536
Out(j - 2) = ((v + 1) \ 256&) Mod 256
j = j - 1
End If
ReDim Preserve Out(j - 1)
End Sub
Public Function ToBase64(data() As Byte) As String
Dim b64(0 To 63) As Byte, str() As Byte, i&, j&, v&, n&
n = UBound(data) - LBound(data) + 1
If n Then Else Exit Function
str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
For i = 0 To 127 Step 2
b64(i \ 2) = str(i)
Next
ReDim str(0 To ((n + 2) \ 3) * 8 - 1)
For i = LBound(data) To UBound(data) - (n Mod 3) Step 3
v = data(i) * 65536 + data(i + 1) * 256& + data(i + 2)
str(j) = b64(v \ 262144)
str(j + 2) = b64((v \ 4096) Mod 64)
str(j + 4) = b64((v \ 64) Mod 64)
str(j + 6) = b64(v Mod 64)
j = j + 8
Next
If n Mod 3 = 2 Then
v = data(n - 2) * 256& + data(n - 1)
str(j) = b64((v \ 1024&) Mod 64)
str(j + 2) = b64((v \ 16) Mod 64)
str(j + 4) = b64((v * 4) Mod 64)
str(j + 6) = 61 ' = '
ElseIf n Mod 3 = 1 Then
v = data(n - 1)
str(j) = b64(v \ 4 Mod 64)
str(j + 2) = b64(v * 16 Mod 64)
str(j + 4) = 61 ' = '
str(j + 6) = 61 ' = '
End If
ToBase64 = str
End Function

Why does this VBA-generated QR-Code stutter? (barcode-vba-macro-only)

Context
I am using barcode-vba-macro-only (mentioned in this SO post) in MS Excel 2010 to generate a QR code.
(The bar code will be used to facilitate paying a bill using Girocode, but that is not important here, except to say I need to structure the input exactly the way shown below.)
The problem
The VBA macro creates great QR-Codes, but somehow, when given certain input, the output (encoded in the QR code) "stutters", i.e. repeats part of the text.
E.g., when given this input:
BCD
001
1
SCT
SOLADES1HDB
Recipient First and Last Name
DE86672500200000123456
EUR123.45
it produces this output:
which oddly repeats part of the content:
BCD
001
1
SCT
SOLADES1HDB
Recipient First and Last Name
DE
Recipient First and Last Name
DE86672500200000123456
EUR123.45
(Note the DE and the line Recipient First and Last Name which appear twice.)
What I want
A working, free/GPL solution in Excel to generate such codes ;-) ... for example by understanding why this happens, and fixing the VBA code.
What I have tried (Update 1)
I have played around with different inputs and found that just adding some extra "AAA" to the end of the long number solves the stuttering... so I am intrigued what causes this.
I forked to code on GitHub, added some code comments and translated a few of the existing (Czech) comments
Through some debugging, I found that the implementation messes up the starting position of different encodings (which it stores in array eb): after encoding the "Recipient First and Last Name" including newline and "DE" as "Byte", it probably tries to switch to "Decimal" or "Alphanum" encoding (only 3.33 or 5.5 bit per character instead of 8)... but then falls back to encoding in "Byte" format and thereby gets the starting position wrong.
The code
You can download my test XLSM file here, and access my improved code file on GitHub.
I think the issue is probably in the core function shown below, in the section where the array eb() is filled.
Function qr_gen(ptext As String, poptions As String) As String
Dim encoded1() As Byte ' byte mode (ASCII) all max 3200 bytes
Dim encix1%
Dim ecx_cnt(3) As Integer
Dim ecx_pos(3) As Integer
Dim ecx_poc(3) As Integer
Dim eb(1 To 20, 1 To 4) As Integer 'store how many characters should be in which ECI mode. This is a list of rows, each row corresponding a the next batch of characters with a different ECI mode.
' eb(i, 1) - ECI mode (1 = numeric, 2 = alphanumeric, 3 = byte)
' eb(i, 2) - last character in previous row
' eb(i, 3) - number of characters in THIS row
' eb(i, 4) - number of bits for THIS row
Dim ascimatrix$, mode$, err$
Dim ecl%, r%, c%, mask%, utf8%, ebcnt%
Dim i&, j&, k&, m&
Dim ch%, s%, siz%
Dim x As Boolean
Dim qrarr() As Byte ' final matrix
Dim qrpos As Integer
Dim qrp(15) As Integer ' 1:version,2:size,3:ccs,4:ccb,5:totby,6-12:syncs(7),13-15:versinfo(3)
Dim qrsync1(1 To 8) As Byte
Dim qrsync2(1 To 5) As Byte
ascimatrix = ""
err = ""
mode = "M"
i = InStr(poptions, "mode=")
If i > 0 Then mode = Mid(poptions, i + 5, 1)
' M=0,L=1,H=2,Q=3
ecl = InStr("MLHQ", mode) - 1
If ecl < 0 Then mode = "M": ecl = 0
If ptext = "" Then
err = "Not data"
Exit Function
End If
For i = 1 To 3
ecx_pos(i) = 0
ecx_cnt(i) = 0
ecx_poc(i) = 0
Next i
ebcnt = 1
utf8 = 0
For i = 1 To Len(ptext) + 1
' Decide how many bytes this character has
If i > Len(ptext) Then
k = -5 ' End of text --> skip several code sections
Else ' need to parse character i of ptext and decide how many bytes it has
k = AscL(Mid(ptext, i, 1))
If k >= &H1FFFFF Then ' FFFF - 1FFFFFFF
m = 4
k = -1
ElseIf k >= &H7FF Then ' 7FF-FFFF 3 bytes
m = 3
k = -1
ElseIf k >= 128 Then
m = 2
k = -1
Else ' normal 7bit ASCII character, so it is worth it to check if it belong to the Numeric or Alphanumeric subsets defined in ECI (array qralnum)
m = 1
k = InStr(qralnum, Mid(ptext, i, 1)) - 1
End If
End If
' Depending on k and a lot of other things, increase ebcnt
If (k < 0) Then ' Treat mult-byte case or exit? (bude byte nebo konec)
If ecx_cnt(1) >= 9 Or (k = -5 And ecx_cnt(1) = ecx_cnt(3)) Then ' Until now it was possible numeric??? (Az dosud bylo mozno pouzitelne numeric)
If (ecx_cnt(2) - ecx_cnt(1)) >= 8 Or (ecx_cnt(3) = ecx_cnt(2)) Then ' pred num je i pouzitelny alnum
If (ecx_cnt(3) > ecx_cnt(2)) Then ' Jeste pred alnum bylo byte
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position pozice
eb(ebcnt, 3) = ecx_cnt(3) - ecx_cnt(2) ' delka
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
eb(ebcnt, 1) = 2 ' Typ alnum
eb(ebcnt, 2) = ecx_pos(2)
eb(ebcnt, 3) = ecx_cnt(2) - ecx_cnt(1) ' delka
ebcnt = ebcnt + 1
ecx_poc(2) = ecx_poc(2) + 1
ecx_cnt(2) = 0
ElseIf ecx_cnt(3) > ecx_cnt(1) Then ' byly bytes pred numeric
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position pozice
eb(ebcnt, 3) = ecx_cnt(3) - ecx_cnt(1) ' delka
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
ElseIf (ecx_cnt(2) >= 8) Or (k = -5 And ecx_cnt(2) = ecx_cnt(3)) Then ' Az dosud bylo mozno pouzitelne alnum
If (ecx_cnt(3) > ecx_cnt(2)) Then ' Jeste pred alnum bylo byte
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position pozice
eb(ebcnt, 3) = ecx_cnt(3) - ecx_cnt(2) ' delka
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
eb(ebcnt, 1) = 2 ' Typ alnum
eb(ebcnt, 2) = ecx_pos(2)
eb(ebcnt, 3) = ecx_cnt(2) ' delka
ebcnt = ebcnt + 1
ecx_poc(2) = ecx_poc(2) + 1
ecx_cnt(3) = 0
ecx_cnt(2) = 0 ' vse zpracovano
ElseIf (k = -5 And ecx_cnt(3) > 0) Then ' konec ale mam co ulozit
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position pozice
eb(ebcnt, 3) = ecx_cnt(3) ' delka
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
End If
If k = -5 Then Exit For
If (k >= 0) Then ' We can alphanumeric? (Muzeme alnum)
If (k >= 10 And ecx_cnt(1) >= 12) Then ' Until now it was perhaps numeric (Az dosud bylo mozno num)
If (ecx_cnt(2) - ecx_cnt(1)) >= 8 Or (ecx_cnt(3) = ecx_cnt(2)) Then ' There is also an alphanumeric which is worth it(Je tam i alnum ktery stoji za to)
If (ecx_cnt(3) > ecx_cnt(2)) Then ' Even before it was alnum byte (Jeste pred alnum bylo byte)
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position (pozice)
eb(ebcnt, 3) = ecx_cnt(3) - ecx_cnt(2) ' length (delka)
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
eb(ebcnt, 1) = 2 ' Typ alnum
eb(ebcnt, 2) = ecx_pos(2)
eb(ebcnt, 3) = ecx_cnt(2) - ecx_cnt(1) ' length (delka)
ebcnt = ebcnt + 1
ecx_poc(2) = ecx_poc(2) + 1
ecx_cnt(2) = 0 ' processed everything (vse zpracovano)
ElseIf (ecx_cnt(3) > ecx_cnt(1)) Then ' Previous Num is byte (Pred Num je byte)
eb(ebcnt, 1) = 3 ' Typ byte
eb(ebcnt, 2) = ecx_pos(3) ' Position (pozice)
eb(ebcnt, 3) = ecx_cnt(3) - ecx_cnt(1) ' length (delka)
ebcnt = ebcnt + 1
ecx_poc(3) = ecx_poc(3) + 1
End If
eb(ebcnt, 1) = 1 ' Typ numerix
eb(ebcnt, 2) = ecx_pos(1)
eb(ebcnt, 3) = ecx_cnt(1) ' length (delka)
ebcnt = ebcnt + 1
ecx_poc(1) = ecx_poc(1) + 1
ecx_cnt(1) = 0
ecx_cnt(2) = 0
ecx_cnt(3) = 0 ' processed everything (vse zpracovano)
End If
If ecx_cnt(2) = 0 Then ecx_pos(2) = i
ecx_cnt(2) = ecx_cnt(2) + 1
Else ' possible alnum (mozno alnum)
ecx_cnt(2) = 0
End If
If k >= 0 And k < 10 Then ' Can be numeric (muze byt numeric)
If ecx_cnt(1) = 0 Then ecx_pos(1) = i
ecx_cnt(1) = ecx_cnt(1) + 1
Else
ecx_cnt(1) = 0
End If
If ecx_cnt(3) = 0 Then ecx_pos(3) = i
ecx_cnt(3) = ecx_cnt(3) + m
utf8 = utf8 + m
If ebcnt >= 16 Then ' We have already taken 3 other blocks of bits (Uz by se mi tri dalsi bloky stejne nevesli)
ecx_cnt(1) = 0
ecx_cnt(2) = 0
End If
Debug.Print "Character:'" & Mid(ptext, i, 1) & "'(" & k & _
") ebn=" & ecx_pos(1) & "." & ecx_cnt(1) & _
" eba=" & ecx_pos(2) & "." & ecx_cnt(2) & _
" ebb=" & ecx_pos(3) & "." & ecx_cnt(3)
Next
ebcnt = ebcnt - 1 ' ebcnt now has its final value
Debug.Print ("ebcnt=" & ebcnt)
c = 0
For i = 1 To ebcnt
Select Case eb(i, 1)
Case 1: eb(i, 4) = Int(eb(i, 3) / 3) * 10 + (eb(i, 3) Mod 3) * 3 + IIf((eb(i, 3) Mod 3) > 0, 1, 0)
Case 2: eb(i, 4) = Int(eb(i, 3) / 2) * 11 + (eb(i, 3) Mod 2) * 6
Case 3: eb(i, 4) = eb(i, 3) * 8
End Select
c = c + eb(i, 4)
Next i
Debug.Print ("c=" & c)
' UTF-8 is default not need ECI value - zxing cannot recognize
' Call qr_params(i * 8 + utf8,mode,qrp)
Call qr_params(c, ecl, qrp, ecx_poc)
If qrp(1) <= 0 Then
err = "Too long"
Exit Function
End If
siz = qrp(2)
Debug.Print "ver:" & qrp(1) & mode & " size " & siz & " ecc:" & qrp(3) & "x" & qrp(4) & " d:" & (qrp(5) - qrp(3) * qrp(4))
'MsgBox "ver:" & qrp(1) & mode & " size " & siz & " ecc:" & qrp(3) & "x" & qrp(4) & " d:" & (qrp(5) - qrp(3) * qrp(4))
ReDim encoded1(qrp(5) + 2)
' Table 3 — Number of bits in character count indicator for QR Code 2005:
' mode indicator (1=num,2=AlNum,4=Byte,8=kanji,ECI=7)
' mode: Byte Alphanum Numeric Kanji
' ver 1..9 : 8 9 10 8
' 10..26 : 16 11 12 10
' 27..40 : 16 13 14 12
' UTF-8 is default not need ECI value - zxing cannot recognize
' if utf8 > 0 Then
' k = &H700 + 26 ' UTF-8=26 ; Win1250 = 21; 8859-2 = 4 viz http://strokescribe.com/en/ECI.html
' bb_putbits(encoded1,encix1,k,12)
' End If
encix1 = 0
For i = 1 To ebcnt
Select Case eb(i, 1)
Case 1: c = IIf(qrp(1) < 10, 10, IIf(qrp(1) < 27, 12, 14)): k = 2 ^ c + eb(i, 3) ' encoding mode "Numeric"
Case 2: c = IIf(qrp(1) < 10, 9, IIf(qrp(1) < 27, 11, 13)): k = 2 * (2 ^ c) + eb(i, 3) ' encoding mode "alphanum
Case 3: c = IIf(qrp(1) < 10, 8, 16): k = 4 * (2 ^ c) + eb(i, 3) ' encoding mode "Byte"
End Select
Call bb_putbits(encoded1, encix1, k, c + 4)
Debug.Print "ver:" & qrp(1) & mode & " size " & siz & " ecc:" & qrp(3) & "x" & qrp(4) & " d:" & (qrp(5) - qrp(3) * qrp(4))
j = 0 ' count characters that have been output in THIS row eb(i,...)
m = eb(i, 2) 'Start (after) last character of input from previous row
r = 0
While j < eb(i, 3)
k = AscL(Mid(ptext, m, 1))
m = m + 1
If eb(i, 1) = 1 Then
' parse numeric input - output 3 decimal digits into 10 bit
r = (r * 10) + ((k - &H30) Mod 10)
If (j Mod 3) = 2 Then
Call bb_putbits(encoded1, encix1, r, 10)
r = 0
End If
j = j + 1
ElseIf eb(i, 1) = 2 Then
' parse alphanumeric input - output 2 alphanumeric characters into 11 bit
r = (r * 45) + ((InStr(qralnum, Chr(k)) - 1) Mod 45)
If (j Mod 2) = 1 Then
Call bb_putbits(encoded1, encix1, r, 11)
r = 0
End If
j = j + 1
Else
' Okay, byte mode: coding according to Chapter "6.4.2 Extended Channel Interpretation (ECI) mode" of ISOIEC 18004_2006Cor 1_2009.pdf
If k > &H1FFFFF Then ' FFFF - 1FFFFFFF
ch = &HF0 + Int(k / &H40000) Mod 8
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + Int(k / &H1000) Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + Int(k / 64) Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + k Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
j = j + 4
ElseIf k > &H7FF Then ' 7FF-FFFF 3 bytes
ch = &HE0 + Int(k / &H1000) Mod 16
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + Int(k / 64) Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + k Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
j = j + 3
ElseIf k > &H7F Then ' 2 bytes
ch = &HC0 + Int(k / 64) Mod 32
Call bb_putbits(encoded1, encix1, ch, 8)
ch = 128 + k Mod 64
Call bb_putbits(encoded1, encix1, ch, 8)
j = j + 2
Else
ch = k Mod 256
Call bb_putbits(encoded1, encix1, ch, 8)
j = j + 1
End If
End If
Wend
Select Case eb(i, 1)
Case 1:
If (j Mod 3) = 1 Then
Call bb_putbits(encoded1, encix1, r, 4)
ElseIf (j Mod 3) = 2 Then
Call bb_putbits(encoded1, encix1, r, 7)
End If
Case 2:
If (j Mod 2) = 1 Then Call bb_putbits(encoded1, encix1, r, 6)
End Select
'MsgBox "blk[" & i & "] t:" & eb(i,1) & "from " & eb(i,2) & " to " & eb(i,3) + eb(i,2) & " bits=" & encix1
Next i
Call bb_putbits(encoded1, encix1, 0, 4) ' end of chain
If (encix1 Mod 8) <> 0 Then ' round to byte
Call bb_putbits(encoded1, encix1, 0, 8 - (encix1 Mod 8))
End If
' padding
i = (qrp(5) - qrp(3) * qrp(4)) * 8
If encix1 > i Then
err = "Encode length error"
Exit Function
End If
' padding 0xEC,0x11,0xEC,0x11...
Do While encix1 < i
Call bb_putbits(encoded1, encix1, &HEC11, 16)
Loop
' doplnime ECC
i = qrp(3) * qrp(4) 'ppoly, pmemptr , psize , plen , pblocks
Call qr_rs(&H11D, encoded1, qrp(5) - i, i, qrp(4))
'Call arr2hexstr(encoded1)
encix1 = qrp(5)
' Pole pro vystup
ReDim qrarr(0)
ReDim qrarr(1, qrp(2) * 24& + 24&) ' 24 bytes per row
qrarr(0, 0) = 0
ch = 0
Call bb_putbits(qrsync1, ch, Array(&HFE, &H82, &HBA, &HBA, &HBA, &H82, &HFE, 0), 64)
Call qr_mask(qrarr, qrsync1, 8, 0, 0) ' sync UL
Call qr_mask(qrarr, 0, 8, 8, 0) ' fmtinfo UL under - bity 14..9 SYNC 8
Call qr_mask(qrarr, qrsync1, 8, 0, siz - 7) ' sync UR ( o bit vlevo )
Call qr_mask(qrarr, 0, 8, 8, siz - 8) ' fmtinfo UR - bity 7..0
Call qr_mask(qrarr, qrsync1, 8, siz - 7, 0) ' sync DL (zasahuje i do quiet zony)
Call qr_mask(qrarr, 0, 8, siz - 8, 0) ' blank nad DL
For i = 0 To 6
x = qr_bit(qrarr, -1, i, 8, 0) ' svisle fmtinfo UL - bity 0..5 SYNC 6,7
x = qr_bit(qrarr, -1, i, siz - 8, 0) ' svisly blank pred UR
x = qr_bit(qrarr, -1, siz - 1 - i, 8, 0) ' svisle fmtinfo DL - bity 14..8
Next
x = qr_bit(qrarr, -1, 7, 8, 0) ' svisle fmtinfo UL - bity 0..5 SYNC 6,7
x = qr_bit(qrarr, -1, 7, siz - 8, 0) ' svisly blank pred UR
x = qr_bit(qrarr, -1, 8, 8, 0) ' svisle fmtinfo UL - bity 0..5 SYNC 6,7
x = qr_bit(qrarr, -1, siz - 8, 8, 1) ' black dot DL
If qrp(13) <> 0 Or qrp(14) <> 0 Then ' versioninfo
' UR ver 0 1 2;3 4 5;...;15 16 17
' LL ver 0 3 6 9 12 15;1 4 7 10 13 16; 2 5 8 11 14 17
k = 65536 * qrp(13) + 256& * qrp(14) + 1& * qrp(15)
c = 0: r = 0
For i = 0 To 17
ch = k Mod 2
x = qr_bit(qrarr, -1, r, siz - 11 + c, ch) ' UR ver
x = qr_bit(qrarr, -1, siz - 11 + c, r, ch) ' DL ver
c = c + 1
If c > 2 Then c = 0: r = r + 1
k = Int(k / 2&)
Next
End If
c = 1
For i = 8 To siz - 9 ' sync lines
x = qr_bit(qrarr, -1, i, 6, c) ' vertical on column 6
x = qr_bit(qrarr, -1, 6, i, c) ' horizontal on row 6
c = (c + 1) Mod 2
Next
' other syncs
ch = 0
Call bb_putbits(qrsync2, ch, Array(&H1F, &H11, &H15, &H11, &H1F), 40)
ch = 6
Do While ch > 0 And qrp(6 + ch) = 0
ch = ch - 1
Loop
If ch > 0 Then
For c = 0 To ch
For r = 0 To ch
' corners
If (c <> 0 Or r <> 0) And _
(c <> ch Or r <> 0) And _
(c <> 0 Or r <> ch) Then
Call qr_mask(qrarr, qrsync2, 5, qrp(r + 6) - 2, qrp(c + 6) - 2)
End If
Next r
Next c
End If
' qr_fill(parr as Variant, psiz%, pb as Variant, pblocks%, pdlen%, ptlen%)
' vyplni pole parr (psiz x 24 bytes) z pole pb pdlen = pocet dbytes, pblocks = bloku, ptlen celkem
Call qr_fill(qrarr, siz, encoded1, qrp(4), qrp(5) - qrp(3) * qrp(4), qrp(5))
mask = 8 ' auto
i = InStr(poptions, "mask=")
If i > 0 Then mask = val(Mid(poptions, i + 5, 1))
If mask < 0 Or mask > 7 Then
j = -1
For mask = 0 To 7
GoSub addmm
i = qr_xormask(qrarr, siz, mask, False)
' MsgBox "score mask " & mask & " is " & i
If i < j Or j = -1 Then j = i: s = mask
Next mask
mask = s
' MsgBox "best is " & mask & " with score " & j
End If
GoSub addmm
i = qr_xormask(qrarr, siz, mask, True)
ascimatrix = ""
For r = 0 To siz Step 2
s = 0
For c = 0 To siz Step 2
If (c Mod 8) = 0 Then
ch = qrarr(1, s + 24 * r)
If r < siz Then i = qrarr(1, s + 24 * (r + 1)) Else i = 0
s = s + 1
End If
ascimatrix = ascimatrix _
& Chr(97 + (ch Mod 4) + 4 * (i Mod 4))
ch = Int(ch / 4)
i = Int(i / 4)
Next
ascimatrix = ascimatrix & vbNewLine
Next r
ReDim qrarr(0)
qr_gen = ascimatrix
Exit Function
addmm:
k = ecl * 8 + mask
' poly: 101 0011 0111
Call qr_bch_calc(k, &H537)
'MsgBox "mask :" & hex(k,3) & " " & hex(k xor &H5412,3)
k = k Xor &H5412 ' micro xor &H4445
r = 0
c = siz - 1
For i = 0 To 14
ch = k Mod 2
k = Int(k / 2)
x = qr_bit(qrarr, -1, r, 8, ch) ' svisle fmtinfo UL - bity 0..5 SYNC 6,7 .... 8..14 dole
x = qr_bit(qrarr, -1, 8, c, ch) ' vodorovne odzadu 0..7 ............ 8,SYNC,9..14
c = c - 1
r = r + 1
If i = 7 Then c = 7: r = siz - 7
If i = 5 Then r = r + 1 ' preskoc sync vodorvny
If i = 8 Then c = c - 1 ' preskoc sync svisly
Next
Return
End Function ' qr_gen
Why this happens
Through some debugging, I found that the original implementation messes up the starting position of different encodings (which it stores in array eb): after encoding the "Recipient First and Last Name" including newline and "DE" as "Byte", it probably tries to switch to "Decimal" or "Alphanum" encoding (only 3.33 or 5.5 bit per character instead of 8)... but then falls back to encoding in "Byte" format and thereby gets the starting position wrong.
The solution
I have now added some error checking to the code which manually removes the stuttering.
You can find my improved code on Github, see in particular barcody.bas.
The key addition is this part:
i = 1
While i < (ebcnt - 1)
If eb(i, 2) + eb(i, 3) <> eb(i + 1, 2) Then
' oops, this should not happen. First document it:
Debug.Print ("eb() rows " & i & " and " & i + 1 & " are overlapping!")
' Now Lets see if we can fix it:
wasfixed = False
For k = i To 1 Step -1
If eb(k, 2) = eb(i + 1, 2) Then
' okay, the row k to i seem to be contained in i+1 and following. Delete k to i ...
For j = k To ebcnt - (i - k + 1) ' ... by copying upwards all later rows...
eb(j, 1) = eb(j + (i - k + 1), 1)
eb(j, 2) = eb(j + (i - k + 1), 2)
eb(j, 3) = eb(j + (i - k + 1), 3)
eb(j, 4) = eb(j + (i - k + 1), 4)
Next j
ebcnt = ebcnt - (i - k + 1) ' and correcting the total rowcount
wasfixed = True
Exit For
End If
Next k
If Not (wasfixed) Then
MsgBox ("The input text analysis failed - entering debug mode...")
Debug.Assert False
End If
End If
i = i + 1
Wend
I have noticed this same issue with certain character being a trigger for this problem when it comes after something. In your case, it looks like something after "DE" Since I didn't write the code I haven't thoroughly search in the code why this would trigger a repeat but I'm guessing that some of the hex conversion in the function causes this problem. In my case, I avoided the issue by having a space in front of the entire string being input to the generator. For some reasons, having the space at the beginning somehow prevent the triggering of the repeat. The reader program that reads the barcode in my case would remove the space from the string anyway so it doesn't matter.
I don't know whether it's a problem for your application, but try putting a blank space (" ") in front of the problematic string (DE86672500200000123456 )and see whether that works.
BCD
001
1
SCT
SOLADES1HDB
Recipient First and Last Name
DE86672500200000123456
EUR123.45

Sum cone to surface with variable size

I am trying to develop develop a model to calculate the sum of a cone to row 1 given an array of variable size only if the value of the cell is > 0.
If the sum is then >=1 I wish to color the range of the cone to display this. If the cone hits the A row boundary I need it not to error and for it to extend in the cone shape the other boundary. Here is what I have at the moment:
Public Sub MC()
Worksheets("SC").Cells.Clear
Dim i&, j&
For j = 1 To Worksheets("Data").Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To Worksheets("Data").Cells(Rows.Count, "A").End(xlUp).Row
If Worksheets("Data").Cells(i, j) > 0 Then
Worksheets("SC").Cells(i, j).Address , SumAndColorCone(Cells(i, j))
Else: If Worksheets("Data").Cells(i, j) <= 0 Then Worksheets("SC").Cells(i, j) = "0"
End If
Next
Next
End Sub
Public Function SumAndColorCone(r As Range) As Double
Dim i&, k&, c As Range
Set c = r
For i = r.Row - 1 To 1 Step -1
If r.Column - k < 2 Then Exit For
Set c = Union(c, r(-k, -k).Resize(, (k + 1) * 2 + 1))
k = k + 1
Next
c.Interior.Color = vbRed
SumAndColorCone = Application.Sum(c)
End Function
Try this:
Public Sub MC()
Dim c&, i&, j&
For j = 1 To Cells(1, Columns.Count).End(xlToLeft).Column
For i = 1 To Cells(Rows.Count, "A").End(xlUp).Row
If Val(Cells(i, j)) > 0 Then
c = RGB(Int(Rnd * 255) + 1, Int(Rnd * 255) + 1, Int(Rnd * 255) + 1)
Debug.Print "Testing value at: " & Cells(i, j).Address & vbLf & "Cone sum: " & SumAndColorCone(Cells(i, j), c) & vbLf
End If
Next
Next
End Sub
Private Function SumAndColorCone(r As Range, color&) As Double
Dim i&, k&, c As Range
Set c = r
For i = r.Row - 1 To 1 Step -1
If r.Column - k < 2 Then
Set c = Union(c, r(-k, -r.Column + 2).Resize(, r.Column + k + 1))
Else
Set c = Union(c, r(-k, -k).Resize(, (k + 1) * 2 + 1))
End If
k = k + 1
Next
SumAndColorCone = Application.Sum(c)
If SumAndColorCone > 1 Then c.Interior.color = color
End Function

VBA Run-Time Error 1004

I am debugging a VBA macro which ends with the following error message:
"Run-time error '1004':
"could not be found. Check the spelling of the file name, and verify
that the file location is correct.
If you are trying to open the file from your list of most recently used files, make sure that the file has not been remnamed, moved, or deleted."
I checked that I was not using deleted/removed/renamed files and they were not coming from my Recent Files list.
The offending portion of the code which triggers the error message:
Workbooks.OpenText Filename:=vCPath _
, Origin:=437, StartRow:=1, DataType:=xlDelimited, TextQualifier:= _
xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, Semicolon:=False _
, Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), _
Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), Array(8, 1), _
Array(9, 1), Array(10, 1), Array(11, 1), Array(12, 1), Array(13, 1)), _
TrailingMinusNumbers:=True
Here is all of the code:
' Changes to program to make
' Exclude outliers in average
' Develop fake data to at glance recognize whether program works.
' Source http://www.cpearson.com/excel/optimize.htm
' Declare .Filters
Option Explicit
Sub DataProcessingExperiment7()
On Error GoTo ErrorHandler
' Declare as strings, as integers, as variants, decDecimals, as Office.FileDialog
Dim strPath, strFileN, strDirN, strRangeNOut, strRangeNIn, strFilename, strTLCorn, strBRCorn, strSelectedFile, strtemp_name As String
Dim vResMatrix(), vCPath, vFileN As Variant
Dim vRangeNOut, vRangeNIn, decInd6, decInd4, decInd5, decStep2, decMRow, decColIn, decInd3, decMcol As Double
Dim decMxRNo, decBgrSum, decRowIn, decInd, decM40eff, decStep, decColNo, decStartcol, decStartrow As Double
Dim decPlateNo, decMonoVal, decInd1, decEntryRow2, decEntryRow, decInd2, decBgrValP, decBgrRow As Double
Dim decBrgSum, decBgrVal, decRangeNIn, decRangeNOut, decTLCorn, decVolcorr, decBRCorn, decMEeff As Double
Dim decMediaVal, M40Eff, decMeanComp As Double
' MEeff = measure of efflux due to crudely purified HDL in scintillation
' Math operations are fastest with Integers / UIntegers: https://msdn.microsoft.com/en-us/library/ae55hdtk.aspx
' Start File Explorer to select file containing data
Dim lngCount As Long
' Open the file dialog
With Application.FileDialog(msoFileDialogOpen)
.AllowMultiSelect = True
.Show
' Display paths of each file selected
For lngCount = 1 To .SelectedItems.Count
Next lngCount
For Each strFilename In .SelectedItems
MsgBox strFilename
Next
End With
' Excel 2003 is a good filter choice: Excel Viewer, OpenOffice, + Excel versions can open these files
' If .Show = - 1 user picked at least one file
' The user pressed cancel.
' Assign strings to param locations from (1,2) to (7,2). This matches template
' Now using relative references to increase portability and NOT SELECTING the cells to increase macro speed, shorten code
With ActiveCell
.Offset(1, 2) = decPlateNo
.Offset(2, 2) = decStartrow
.Offset(3, 2) = decStartcol
.Offset(4, 2) = decColNo
.Offset(5, 2) = decStep
.Offset(6, 2) = strDirN
.Offset(7, 2) = strFileN
End With
' Measure of efflux of 2 plates of scint-40
M40Eff = 4.37
M40Eff = 2.4
' Select and copy data and range
Range("A1:O22").Select
Selection.Copy
MsgBox "start"
' Use the array
For decInd = 1 To decPlateNo / 2 - 1
decRowIn = 1 + decStep * 2 * decInd
decRangeNIn = "A" + CStr(decRowIn)
Range(decRangeNIn).Select
ActiveSheet.Paste
Next decInd 'Go to next indice
Application.CutCopyMode = False ' Have the data in both sheets
Workbooks.OpenText Filename:=vCPath _
, Origin:=437, StartRow:=1, DataType:=xlDelimited, TextQualifier:= _
xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=False, Semicolon:=False _
, Comma:=True, Space:=False, Other:=False, FieldInfo:=Array(Array(1, 1), _
Array(2, 1), Array(3, 1), Array(4, 1), Array(5, 1), Array(6, 1), Array(7, 1), Array(8, 1), _
Array(9, 1), Array(10, 1), Array(11, 1), Array(12, 1), Array(13, 1)), _
TrailingMinusNumbers:=True
For decInd1 = 1 To decPlateNo 'Between these 2 columns
decTLCorn = "B" + CStr(decStartrow + (decInd1 - 1) * decStep)
decBRCorn = "M" + CStr(decStartrow + 7 + (decInd1 - 1) * decStep)
decRangeNOut = decTLCorn + ":" + decBRCorn
decRangeNIn = decTLCorn
Windows(vFileN).Activate
Range(vRangeNOut).Select
Selection.Copy
Windows(strtemp_name).Activate
Sheets("Data").Select
Range(vRangeNIn).Select
Selection.PasteSpecial Paste:=xlPasteValues, Operation:=xlNone, SkipBlanks _
:=False, Transpose:=False
Next decInd1
' Operation:=xlNone prevents calculations while pasting (less CPU intensive)
' Don't skip blanks, don't transpose
' Calculation of background and efflux for individual plates
For decInd1 = 1 To decPlateNo / 2
decStep2 = (decInd1 - 1) * decStep * 2
decBgrRow = decStartrow + 8 + decStep2
decBgrValP = Cells(decBgrRow, 2).Value 'Background plate value
For decInd2 = 0 To 7 'From column Ind2 to column 7 do multiplication
decEntryRow = decStartrow + decInd2 + decStep2
decEntryRow2 = decStartrow + decInd2 + decStep2 + 11
decMediaVal = Cells(decEntryRow, 13).Value
decMonoVal = Cells(decEntryRow2, 13).Value
Cells(decEntryRow, 15).Value = decMEeff * 100 * decVolcorr * (decMediaVal - decBgrValP) / (decM40eff * decMonoVal + decVolcorr * decMEeff * (decMediaVal - decBgrValP))
Next decInd2
Next decInd1
MsgBox "end"
' calculation of average background for all media plates
decBgrSum = 0
For decInd1 = 1 To decPlateNo / 2
decStep2 = (decInd1 - 1) * decStep * 2
For decInd2 = 0 To 7
decRowIn = decStartrow + decStep2 + decInd2
decBgrSum = decBgrSum + Cells(decRowIn, 2).Value
Next decInd2
Next decInd1
decBgrVal = decBgrSum / (4 * decPlateNo) 'The plates are split up into 4 (control (media) plates are 2 of them).
decBgrVal = Cells(2, 17).Value
' Rearanging data and transferring to Results sheet
decMxRNo = 8 * decColNo
ReDim vResMatrix(1 To decMxRNo, 1 To decPlateNo)
Sheets("Data").Select
For decInd1 = 1 To decPlateNo
decMcol = decInd1
For decInd2 = 1 To 8
decRowIn = (decInd1 - 1) * decStep + decStartrow + decInd2 - 1
For decInd3 = 1 To decColNo
decColIn = decStartcol + decInd3 - 1
decMRow = (decInd3 - 1) * 8 + decInd2
vResMatrix(decMRow, decMcol) = Cells(decRowIn, decColIn).Value
Next decInd3
Next decInd2
Next decInd1
Sheets("Results").Select
For decInd4 = 1 To decPlateNo
For decInd5 = 1 To decMxRNo
Cells(decInd5, decInd4).Value = vResMatrix(decInd5, decInd4) 'Put the values of the matrix in this range?
Next decInd5
Next decInd4
Sheets("Results QC").Select
' Select QC (quality control) calculation
Range("C81:C82").Select
Selection.Copy
For decInd = 1 To decPlateNo / 2 - 1
decColIn = 2 + 2 * decInd + 1
Cells(81, decColIn).Select
ActiveSheet.Paste 'Paste values of the active sheet (C81:C82 range)
Next decInd
For decInd4 = 1 To decPlateNo
decInd6 = decInd4 + 2
For decInd5 = 1 To decMxRNo 'Put these cell values in the matrix
Cells(decInd5, decInd6).Value = vResMatrix(decInd5, decInd4)
Next decInd5
Next decInd4
For decInd4 = 1 To decPlateNo
decInd6 = decInd4 + 2
decMeanComp = 0.6 * Cells(81, decInd6).Value
For decInd5 = 1 To decMxRNo
If Cells(decInd5, decInd6).Value < decMeanComp Then
Cells(decInd5, decInd6).Interior.Color = RGB(255, 0, 0)
' If the cell value is less than the average highlight them red as outliers. (More likely: from pipettes that didn't release)
ElseIf Cells(decInd5, decInd6).Value > decMeanComp Then
Cells(decInd5, decInd6).Interior.Color = RGB(7, 253, 56)
' If the cell value is greater than the average highlight them green as outliers. (Unlikely unless )
End If
Next decInd5
Next decInd4
MsgBox "4"
ErrorHandler:
MsgBox "Error Code" & Err.Number & vbNewLine & Err.Description, vbCritical, "Error Code" & Err.Number
End Sub
' Another function to continue arranging the data. Start by declaring all data types.
Sub Arrange_data()
On Error GoTo ErrorHandler
Dim strPath, strFileN, strDirN, strCPath, strRangeNOut, strRangeNIn, strTLCorn, strBRCorn As String
Dim decColIn4: decColIn4 = CDec(decColIn4)
Dim decInd5: decInd5 = CDec(decInd5)
Dim decInd6: decInd6 = CDec(decInd6)
Dim decPlateNo: decPlateNo = CDec(decPlateNo)
Dim decStartrow: decStartrow = CDec(decStartrow)
Dim decStartcol: decStartcol = CDec(decStartcol)
Sheets("Parameters").Select
decPlateNo = Cells(1, 2).Value
decStartrow = Cells(2, 2).Values
decStartcol = Cells(3, 2).Value
decColNo = Cells(4, 2).Value
decStep = Cells(5, 2).Value
decMEeff = 2.03
decM40eff = 4.37 'microscint 40=kind of solution the macrophages go in
decVolcorr = 2.4
decMxRNo = 8 * decColNo
ReDim vResMatrix(1 To decMxRNo, 1 To decPlateNo)
' Select QC (quality control) data
Sheets("Results QC").Select
For decInd1 = 1 To decPlateNo
decInd3 = decInd1 + 2
For decInd2 = 1 To iMxRNo
vResMatrix(decInd2, decInd1) = Cells(decInd2, decInd3).Value
Next decInd2
Next decInd1
' Transfer data for two methods of efflux calculations.
' Create template of columns.
Sheets("Processed indiv").Select
Range("C2:E87").Select
Selection.Copy
For decInd = 1 To decPlateNo / 2 - 1
decColIn = 3 + 3 * decInd
Cells(2, decColIn).Select
ActiveSheet.Paste
Next decInd
Application.CutCopyMode = False
' Don't cut and copy: leave the values in the Excel sheet.
' For disgorging values stored in matrix and calculate efflux.
For decInd1 = 1 To decPlateNo / 2
decColIn1 = 3 + 3 * (decInd1 - 1)
decColIn2 = decColIn1 + 1
decColIn3 = decColIn1 + 2
decBgrRow = (decInd1 - 1) * decStep * 2 + decStartrow + 8
decInd4 = 2 * decInd1
decInd3 = decInd4 - 1
Cells(1, decStartcol + 3 * (decInd1 - 1)).Value = "Plate " + CStr(decInd1)
' Get background value for the plate.
Sheets("Data").Select
decBgrValP = Cells(decBgrRow, 2)
Sheets("Processed indiv").Select
' Digorging values and calculating efflux.
For decInd2 = 1 To iMxRNo
decMediaVal = vResMatrix(decInd2, decInd3)
decMonoVal = vResMatrix(decInd2, decInd4)
Cells(2 + decInd2, decColIn1).Value = decMediaVal
Cells(2 + decInd2, decColIn2).Value = decMonoVal
Cells(2 + decInd2, decColIn3).Value = decMEeff * 100 * decVolcorr * (decMediaVal - decBgrValP) / (decM40eff * decMonoVal + decVolcorr * decMEeff * (decMediaVal - decBgrValP))
Next decInd2
Next decInd1
' Remove no data cells.
For decInd1 = 1 To decPlateNo / 2
decColIn1 = 3 + 3 * (decInd1 - 1)
For decInd2 = 3 To decMxRNo + 2
If Cells(decInd2, decColIn1).Value = "" Then
Cells(decInd2, decColIn1 + 1).Value = ""
Cells(decInd2, decColIn1 + 2).Value = ""
End If
Next decInd2
Next decInd1
' calculate data based on plate average.
' Create template for columns.
Sheets("Processed by plate").Select
Range("C2:E87").Select
Selection.Copy
For decInd = 1 To decPlateNo / 2 - 1
decColIn = 3 + 3 * decInd
Cells(2, decColIn).Select
ActiveSheet.Paste
Next decInd
Application.CutCopyMode = False
' Prep for disgorging values stored in matrix and calculate efflux.
For decInd1 = 1 To decPlateNo / 2
decColIn1 = 3 + 3 * (decInd1 - 1)
decColIn2 = decColIn1 + 1
decColIn3 = decColIn1 + 2
decBgrRow = (decInd1 - 1) * decStep * 2 + decStartrow + 8
decInd4 = 2 * decInd1
decInd3 = decInd4 - 1
Cells(1, decStartcol + 3 * (decInd1 - 1)).Value = "Plate " + CStr(decInd1)
' Get background value for the plate.
Sheets("Data").Select
decBgrValP = Cells(decBgrRow, 2)
Sheets("Processed by plate").Select
' Digorging values and calculating efflux.
' When does this for loop end?
For decInd2 = 1 To decMxRNo
Cells(2 + decInd2, decColIn1).Value = vResMatrix(decInd2, decInd3)
Cells(2 + decInd2, decColIn2).Value = vResMatrix(decInd2, decInd4)
Next decInd2
' Get average value for monolayer. (Cells are in 1-cell deep layer.) ?
decMonoVal = Cells(83, decColIn2).Value
For decInd2 = 1 To decMxRNo
decMediaVal = vResMatrix(decInd2, decInd3)
Cells(2 + decInd2, decColIn3).Value = decMEeff * 100 * decVolcorr * (decMediaVal - decBgrValP) / (decM40eff * decMonoVal + decVolcorr * decMEeff * (decMediaVal - decBgrValP))
Next decInd2
Next decInd1
' Remove no data cells.
For decInd1 = 1 To decPlateNo / 2
decColIn1 = 3 + 3 * (decInd1 - 1)
For decInd2 = 3 To decMxRNo + 2
If Cells(decInd2, decColIn1).Value = "" Then
Cells(decInd2, decColIn1 + 1).Value = ""
Cells(decInd2, decColIn1 + 2).Value = ""
End If
Next decInd2
Next decInd1
' Replace cell count data with calculated efflux in the matrix.
Sheets("Processed indiv").Select
For decInd1 = 1 To decPlateNo / 2
decColIn1 = 5 + 3 * (decInd1 - 1)
decInd4 = 2 * decInd1
For decInd2 = 1 To decMxRNo
vResMatrix(decInd2, decInd4) = Cells(2 + decInd2, decColIn1).Value
Next decInd2
Next decInd1
'Move data to duplicate comparison.
Sheets("Duplicate comparison").Select
Range("C2:N87").Select
Selection.Copy
For decInd = 1 To decPlateNo / 4 - 1
decColIn = 3 + 12 * decInd
Cells(2, decColIn).Select
ActiveSheet.Paste
Next decInd
Application.CutCopyMode = False
For decInd1 = 1 To decPlateNo / 4
decColIn1 = 3 + 12 * (decInd1 - 1)
decColIn2 = decColIn1 + 2
decColIn3 = decColIn1 + 3
decColIn4 = decColIn1 + 5
decInd3 = decInd1 * 4 - 3
decInd4 = decInd3 + 1
decInd5 = decInd3 + 2
decInd6 = decInd3 + 3
Cells(1, decStartcol + 12 * (decInd1 - 1)).Value = "Plate " + CStr(2 * decInd1 - 1)
Cells(1, decStartcol + 3 + 12 * (decInd1 - 1)).Value = "Plate " + CStr(2 * decInd1)
For iInd2 = 1 To iMxRNo
Cells(2 + iInd2, iColIn1).Value = vResMatrix(decInd2, decInd3)
Cells(2 + iInd2, iColIn2).Value = vResMatrix(decInd2, decInd4)
Cells(2 + iInd2, iColIn3).Value = vResMatrix(decInd2, decInd5)
Cells(2 + iInd2, iColIn4).Value = vResMatrix(decInd2, decInd6)
Next decInd2
Next decInd1
' Remove no data cells.
For decInd1 = 1 To decPlateNo / 4
decColIn1 = 3 + 12 * (decInd1 - 1)
decColIn2 = decColIn1 + 3
For decInd2 = 3 To decMxRNo + 2
If Cells(decInd2, decColIn1).Value = "" Then
Cells(decInd2, decColIn1 + 1).Value = ""
For decInd = 1 To 6
Cells(decInd2, decColIn1 + 5 + decInd).Value = ""
Next decInd
End If
If Cells(decInd2, decColIn2).Value = "" Then
Cells(decInd2, decColIn2 + 1).Value = ""
For decInd = 1 To 6
Cells(decInd2, decColIn2 + 2 + decInd).Value = ""
Next iInd
End If
Next decInd2
Next decInd1
' Prepare summary statistics.
decTL = decPlateNo * decMxRNo / 2
ReDim vResMatrix(1 To 4, 1 To iTL)
Sheets("Processed indiv").Select
decRowIn = 3 + decMxRNo
decRowIn2 = decRowIn + 1
For decInd1 = 1 To 3 * decPlateNo / 2
For decInd2 = 1 To 3
decRowIn3 = 3 * (decInd1 - 1) + iInd2
decColIn = 2 + decRowIn3
vResMatrix(1, decRowIn3) = Cells(decRowIn, decColIn).Value
vResMatrix(2, decRowIn3) = Cells(decRowIn2, decColIn).Value
Next decInd2
Next decInd1
Sheets("Processed by plate").Select
decRowIn = 3 + iMxRNo
decRowIn2 = decRowIn + 1
For decInd1 = 1 To 3 * decPlateNo / 2
For decInd2 = 1 To 3
decRowIn3 = 3 * (decInd1 - 1) + decInd2
decColIn = 2 + decRowIn3
vResMatrix(3, iRowIn3) = Cells(decRowIn, decColIn).Value
vResMatrix(4, decRowIn3) = Cells(decRowIn2, decColIn).Value
Next decInd2
Next decInd1
' Put summary statistics in distribution comp.
Sheets("Distribution comp").Select
For decInd = 1 To 3 * decPlateNo / 2
Cells(2 + iInd, 2).Value = vResMatrix(1, iInd)
Cells(2 + iInd, 3).Value = vResMatrix(2, iInd)
Cells(2 + iInd, 5).Value = vResMatrix(3, iInd)
Cells(2 + iInd, 6).Value = vResMatrix(4, iInd)
Next decInd
' Prepare plate by plate results.
Sheets("Duplicate comparison").Select
For decInd = 1 To iPlateNo / 4
decMatrixStep = (iInd - 1) * iMxRNo
decColIn = 9 + 12 * (iInd - 1)
decColIn2 = iColIn + 2
decColIn3 = iColIn + 1
decColIn4 = iColIn + 3
For decInd2 = 1 To decMxRNo
decMRow = iMatrixStep + decInd2
' Difference between duplicates converted into range.
vResMatrix(1, iMRow) = Cells(2 + decInd2, decColIn).Value
vResMatrix(2, iMRow) = Cells(2 + decInd2, decColIn2).Value / 2
vResMatrix(3, iMRow) = Cells(2 + decInd2, decColIn3).Value
vResMatrix(4, iMRow) = Cells(2 + decInd2, decColIn4).Value / 2
Next decInd2
Next decInd
' Transfer data to Summary.
Sheets("Summary").Select
' Prepare sheet.
Range("B3:G82").Select
Selection.Copy
For decInd = 1 To decPlateNo / 4 - 1
decRowIn = 3 + decMxRNo * iInd
decRangeNIn = "B" + CStr(decRowIn)
Range(decRangeNIn).Select
ActiveSheet.Paste
For decInd2 = 1 To decMxRNo
Cells(decInd2 + decRowIn - 1, 1).Value = "Plate " + CStr(decInd + 1)
Next decInd2
Next decInd
Application.CutCopyMode = False
' Don't cut and copy
' Distribute values.
For decInd = 1 To decTL
iRowIn = iInd + 2
Cells(decRowIn, 4).Value = vResMatrix(1, decInd)
Cells(decRowIn, 5).Value = vResMatrix(2, decInd)
Cells(decRowIn, 6).Value = vResMatrix(3, decInd)
Cells(decRowIn, 7).Value = vResMatrix(4, decInd)
Next decInd
' Transfer data to Matrix summary.
Sheets("Matrix summary").Select
' Prepare page for data.
Range("A1:M11").Select
Selection.Copy
For decInd = 1 To decPlateNo / 4 - 1
decRowIn = 1 + decStep * decInd
decRangeNIn = "A" + CStr(decRowIn)
Range(decRangeNIn).Select
ActiveSheet.Paste
Next decInd
Application.CutCopyMode = False
' Distribute data.
For decInd1 = 0 To iPlateNo / 4 - 1
decPlateStep = decStep * decInd1
decMatrixStep = iColNo * 8 * decInd1
For decInd2 = 0 To iColNo - 1
decColIn = decStartcol + decInd2
decColStep = 8 * iInd2
For iInd3 = 0 To 7
iRowIn = iStartrow + iPlateStep + iInd3
iMxElem = iMatrixStep + iColStep + iInd3 + 1
Cells(decRowIn, decColIn).Value = vResMatrix(3, iMxElem)
Next decInd3
Next decInd2
Next decInd1
' collect statistical parameters on efflux for unknown samples.
decRowNo = decPlateNo / 4
ReDim decEffluxMatrix(1 To iRowNo, 1 To 6)
decStartRowIn = 10
decStartColIn = 2
For decInd = 0 To iRowNo - 1
decRowIn = iStartRowIn + iStep * iInd
EffluxMatrix(iInd + 1, 1) = Cells(iRowIn, iStartColIn).Value
EffluxMatrix(iInd + 1, 2) = Cells(iRowIn + 1, iStartColIn).Value
Next decInd
'collect statistical parameters on efflux for control samples.
Sheets("Data").Select
decStartRowIn = 10
decStartColIn = 15
For iInd = 0 To iRowNo - 1
iRowIn = iStartRowIn + iStep * iInd * 4
EffluxMatrix(iInd + 1, 3) = Cells(iRowIn, iStartColIn).Value
EffluxMatrix(iInd + 1, 4) = Cells(iRowIn + 1, iStartColIn).Value
EffluxMatrix(iInd + 1, 5) = Cells(iRowIn + 22, iStartColIn).Value
EffluxMatrix(iInd + 1, 6) = Cells(iRowIn + 23, iStartColIn).Value
Next decInd
' Ouput of statistical parameters on efflux
Sheets("Matrix summary").Select
decStartRowOut = 4
decStartColOut = 15
For decInd1 = 1 To decRowNo
decRowOut = decStartRowOut + decInd1 - 1
For decInd2 = 1 To 6
decColOut = decStartColOut + decInd2 - 1
Cells(decRowOut, decColOut).Value = EffluxMatrix(decInd1, decInd2)
Next iInd2
Next decInd1
'Output into Matrix min-max
Sheets("Matrix min-max").Select
For decInd1 = 0 To decPlateNo / 4 - 1
decPlateStep = decStep * decInd1
decMatrixStep = decColNo * 8 * decInd1
For decInd2 = 0 To decColNo - 1
decColIn = decStartcol + iInd2
decColStep = 8 * decInd2
For decInd3 = 0 To 7
decRowIn = decStartrow + decPlateStep + decInd3
decMxElem = decMatrixStep + decColStep + decInd3 + 1
Cells(decRowIn, decColIn).Value = vResMatrix(3, decMxElem)
Next decInd3
Next decInd2
Next decInd1
ErrorHandler:
MsgBox "Error detected" & vbNewLine & "Error" & Err.Number & ": " & Err.Description, vbCritical, "Error Handler: Error " & Err.Number
MsgBox "If you want to force the program to run, go to the line below and insert a ' mark to comment the line out." & vbNewLine & "On Error GoTo ErrorHandler", vbCritical, "Error Handler: Error " & Err.Number
End Sub
You are attempting to use the variable vCPath before you have initialized it.

Using function in VBA excel

I have been working on this code for a while. As you can see after the code line " With ws(2)" there is an if condition. Now, I have multiple to create multiple such If conditions such as for 0.6, 0.7, 0.8 etc. (and each such condition should use a different table of data) {I am posting the excel file link for the tables as well so that you can get an idea} Can I do this using a function or any method which wont require me to write this code again and again for each new condition ?
https://docs.google.com/file/d/0B1DVNSutDHR0QWd2UUJsVDZ1Tm8/edit
Private Sub CommandButton1_Click()
Dim x(1 To 9000) As Double, y(1 To 9000) As Double, x1 As Double, y1 As Double, x2 As Double, y2 As Double, I1(1 To 9000) As Double, I2(1 To 9000) As Double, R1(1 To 9000) As Double, R2(1 To 9000) As Double, a As Double, b As Double, c As Double, d As Double, Result(1 To 9000) As Double
Dim i As Integer, j As Integer, k As Integer, p As Integer, q As Integer, r As Integer, s As Integer, t As Integer
Dim ws As Sheets
Set ws = ActiveWorkbook.Sheets(Array("Sheet1", "PLP-1", "PLP-2"))
For t = 0 To 120 Step 20
For k = 1 To 9000
With ws(1)
I1(k) = .Cells(k + 2, 13).Value
I2(k) = .Cells(k + 2, 14).Value
End With
With ws(2)
Select Case .Cells(6 + t, 1).Value
Case 0.5:
r = 0
s = 0
Case 0.6:
r = 20
s = 1
Case 0.7:
r = 40
s = 2
Case 0.8:
r = 60
s = 2
Case 0.9:
r = 80
s = 3
Case 1:
r = 100
s = 4
Case 1.1:
r = 120
s = 5
End Select
For i = 7 To 22
If (.Cells(i + r, 1).Value <= I1(k)) And (I1(k) <= .Cells(i + r + 1, 1).Value) And Not (IsEmpty(I1(k))) Then
p = i + r
x(k) = I1(k)
x1 = .Cells(i + r, 1).Value
x2 = .Cells(i + r + 1, 1).Value
End If
Next i
For j = 2 To 8
If (.Cells(6 + r, j).Value <= I2(k)) And (I2(k) <= .Cells(6 + r, j + 1).Value) And Not (IsEmpty(I2(k))) Then
q = j + r
y(k) = I2(k)
y1 = .Cells(6 + r, j).Value
y2 = .Cells(6 + r, j + 1).Value
End If
Next j
If p <> 0 And q <> 0 Then
a = .Cells(p, q).Value
b = .Cells(p, q + 1).Value
c = .Cells(p + 1, q).Value
d = .Cells(p + 1, q + 1).Value
End If
If I1(k) = Empty Then
R1(k) = 0
Else
R1(k) = (((y2 - y(k)) / (y2 - y1)) * a) + (((y(k) - y1) / (y2 - y1)) * b)
End If
If I2(k) = Empty Then
R2(k) = 0
Else
R2(k) = (((y2 - y(k)) / (y2 - y1)) * c) + (((y(k) - y1) / (y2 - y1)) * d)
End If
Result(k) = (((x2 - x(k)) / (x2 - x1)) * R1(k)) + (((x(k) - x1) / (x2 - x1)) * R2(k))
End With
With ws(1)
.Cells(k + 2, 15 + s).Value = Result(k)
End With
Next k
Next t
End Sub
Try using a Select Case statement as below:
Dim iStart As Long, iEnd As long, jStart As Long, jEnd As Long
'...
With ws(2)
Select Case .Cells(6, 1).Value
Case 0.5:
iStart = 7: iEnd = 22
jStart = 2: jEnd = 7
Case 0.6:
'Same as above but substitute new values for iStart etc.
End Select
For i = iStart To iEnd
'DO STUFF WITH i
Next i
For j = jStart To jEnd
'DO STUFF WITH j
Next j
End With
EDIT: Updated to reflect needs clarified in comments
A more in-depth explanation and usage guide for Select Case can be found here
With regard to your looping, if I understand your code, you need to loop through each "table", but your I and J refer to absolute addresses. What you want is to have I and J be relative to the desired table.
I just used values of 2 to 7, but if the tables are different sizes, you could certainly determine that with code; or even read them into a variant array and do your testing on the array (would often be faster).
So something like the following (pseudo code)
Option Explicit
'N is the Value that defines the proper table
Function DoYourThingOnProperRange(N As Double)
Dim C As Range
Dim I As Long, J As Long
With Sheet1.Columns(1)
Set C = .Find(what:=N, after:=Sheet1.Cells(Rows.Count, "A"), LookIn:=xlValues, _
lookat:=xlWhole, searchorder:=xlByRows, searchdirection:=xlNext)
If Not C Is Nothing Then
Set C = C.CurrentRegion 'C is now set to the proper table
'DoYourThing
'Here's just a dummy routine
For I = 2 To 7
For J = 2 To 7
Debug.Print C(I, J).Address
Next J
Next I
Else
'some kind or error routine for non-existent table
End If
End With
End Function