Trial and error process to find a variable that its function value is known
Hello friends
I have a code uses a module (IAPWS) and uses its function (enthalpySatVapTW).
this code must calculate the the temprature "T_dis", when "h_dis = enthalpySatVapTW @ T_dis" is known. I've witten the code but i dont know why it doesnt work properly! if someone can help me,i would be grateful of him.
thanks.
In the first box a number between "2600 - 2700" must be intered.
the file is edited an d corrected.
Last edited by hossein8862; Jun 17th, 2013 at 03:35 AM.
Re: Trial and error process to find a variable that its function value is known
There are two issues I can see
Code:
Private Sub OK_Click()
Call Tdiscalcs
h_dis = Val(Text1.Text)
Text2.Text = T_dis
Text3.Text = enthalpySatVapTW(T_dis + 273.15)
End Sub
you're calling the Subroutine before assigning a value to h_dis
Code:
Private Sub OK_Click()
h_dis = Val(Text1.Text)
Call Tdiscalcs
Text2.Text = T_dis
Text3.Text = enthalpySatVapTW(T_dis + 273.15)
End Sub
would be better !
In your Calculations Module, the method used to define the Public variables is not doing what you expect. Only T_dis will be defined as Single all the others will default to Variant
You should be using something like
Code:
Public T1 As Single, T2 As Single, T3 As Single, h1 As Single, h2 As Single
Public h3 As Single, h_dis As Single, T_dis As Single
Having 'fixed' those, the program seems to get into an endless loop so I suspect there's something wrong with the calculations (h3 never seems to change value)
Last edited by Doogle; Jun 17th, 2013 at 04:06 AM.
Reason: Typo
Re: Trial and error process to find a variable that its function value is known
Using '2605' in the first TextBox I used a 'Debug.Print Abs(h3 - h_dis)' statement in Subroutine Tdiscalcs in the 'Do While Abs(h3 - h_dis) > 1' loop and it is constantly showing as 67.53052, so it's not converging.
Re: Trial and error process to find a variable that its function value is known
Originally Posted by Doogle
Using '2605' in the first TextBox I used a 'Debug.Print Abs(h3 - h_dis)' statement in Subroutine Tdiscalcs in the 'Do While Abs(h3 - h_dis) > 1' loop and it is constantly showing as 67.53052, so it's not converging.
So is there any way to find a function's (enthalpySatVapTW) variable (T) when the value of function is known and the value of variable is unknown and must be found like this?
Re: Trial and error process to find a variable that its function value is known
Originally Posted by hossein8862
so what can i do to make program converge now?
what other ways do u suggest?
I'm afraid I don't understand the Science so I'm not going to be much help there. I think you're going to have to look at the sequence of calculations.
On second thoughts, perhaps you should be looking at this
Code:
Do While Abs(h3 - h_dis) > 1
T2 = T3
T3 = (T1 + T2) / 2
h3 = enthalpySatVapTW(T3 + 273.15)
Loop
when T1 = T2 (and it does eventually), T3 will remain constant (20) so enthalpySatVapTW will always return the same value. Perhaps the loop should be based on T2 - T1 = 0 ?? (or Abs(T2 - T1) > 0.000001)
Since T1 starts off as 20 and T2 as 220, T2 will equal T1 after about 28 iterations.
Last edited by Doogle; Jun 17th, 2013 at 05:16 AM.
Re: Trial and error process to find a variable that its function value is known
Again, talking off the top of my head and with total ignorance, the fact the h3 and h_dis don't converge is because the T1 -> T2 Range is too small or is of the wrong magnitude, perhaps widening the range may help.
I tested with T1 = 20 and T2 = 320 and h3 and h_dis do converge, when h_dis is 2605, after 2 iterations. Whether that's scientifically 'allowed' you'll have to decide. (T1 = 20, T2 = 95, T3 = 57.5 at the point of convergence)
EDIT: I suppose you could put 57.5 into the 'known' Function and see if you get 2605 out
Last edited by Doogle; Jun 17th, 2013 at 06:02 AM.
Re: Trial and error process to find a variable that its function value is known
OK, there are a lot of problems with this code. The first of which is that calling this trial and error is a little misleading. Trial and error is for middle school math... what you are attempting to do is much more sophisticated, and has a much more sophisticated name: binary search.
Now that we have a name for what you are doing, let's compare your code to standard binary search pseudocode (taken directly from Wikipedia):
Binary Search Pseudocode:
Code:
int binary_search(int A[], int key, int imin, int imax)
{
// continue searching while [imin,imax] is not empty
while (imax >= imin)
{
/* calculate the midpoint for roughly equal partition */
int imid = midpoint(imin, imax);
// determine which subarray to search
if (A[imid] < key)
// change min index to search upper subarray
imin = imid + 1;
else if (A[imid] > key)
// change max index to search lower subarray
imax = imid - 1;
else
// key found at index imid
return imid;
}
// key not found
return KEY_NOT_FOUND;
}
Your code:
Code:
Public T1, T2, T3, h1, h2, h3, h_dis, T_dis As Single
Public Sub Tdiscalcs()
' h is incremental between 0 < T < 220 Celcius
T1 = 20 'Celcius
T2 = 220
T3 = (T1 + T2) / 2
h3 = enthalpySatVapTW(T3 + 273.15)
h1 = enthalpySatVapTW(T1 + 273.15) 'kJ/kg
h2 = enthalpySatVapTW(T2 + 273.15)
If (h_dis < h1) Or (h_dis > h2) Then
Call MsgBox("Out of range outlet Enthalpy", vbOKCancel + vbExclamation, "Range Error !")
End If
If (h_dis > h1) And (h_dis < h3) Then
Do While Abs(h3 - h_dis) > 1
T2 = T3
T3 = (T1 + T2) / 2
h3 = enthalpySatVapTW(T3 + 273.15)
Loop
ElseIf (h_dis > h3) And (h_dis < h2) Then
Do While Abs(h3 - h_dis) > 1
T1 = T3
T3 = (T1 + T2) / 2
h3 = enthalpySatVapTW(T3 + 273.15)
Loop
End If
T_dis = T3
End Sub
So there are numerous problems with your code. Let's start with some VB6/programming basics first:
- Always declare Option Explicit at the start of a module. It's just good practice
- use Doubles instead of Singles, which gets you better precision, especially since this is a scientific application
- This is a single subroutine. Get rid of all the global variables! Instead of "Public T1, T2, T3, h1, h2, h3, h_dis, T_dis As Single" outside of Tdiscalcs(), use "Dim T1, T2, T3, h1, h2, h3, h_dis, T_dis As Single" inside of Tdiscalcs()
- But not so fast... when you declare variables in line like "Dim T1, T2, T3, h1, h2, h3, h_dis, T_dis As Single", T_dis is a Single, but all the other ones are Variants, which is clearly not your intention, so instead declare them like this (and remember to use Double, not Single): "Dim T1 As Double, T2 As Double,... h_dis As Double, T_dis As Double". Better yet, declare each variable on its own line.
- This routine accepts a single value as input and calculates a single value as output. Why is this a Subroutine? This should be a Function, just like enthalpySatVapTW() is a Function: Public Function TDiscalcs(h_dis As Double) As Double
- It would be helpful to use more descriptive names. For example, instead of T1, T2, and T3, use something like dblLowTemp, dblHighTemp and dblMidTemp
- Constant values, such as the difference between absolute zero in Kelvin and Celsius (273.15), should be stored as a constant: Private Const KELVIN_CONVERSION As Double = 273.15
Now let's compare the algorithms:
- You have just one problem, but it's pretty major: In the pseudocode, there is a single loop, with an If-Else statement inside. In your code, there is a single If-Else statement with loops inside each branch. That's your problem. You need to change those loops into a single outer loop and have your If-Else inside it. That's it!
- Also, a little helpful tip. I find it easier, in scientific applications like this in VB6, to use square powers instead of absolute values. Squaring a number gets rid of negative values, and in VB6, lets you avoid Type conversion issues with the Abs() function, which uses Variants.
So now that you know where your mistake is, it's your job to fix it. Good luck!
Re: Trial and error process to find a variable that its function value is known
I probably shouldn't but I'm going to rise to the bait.....
Originally Posted by Lenggries
In the pseudocode, there is a single loop, with an If-Else statement inside. In your code, there is a single If-Else statement with loops inside each branch. That's your problem. You need to change those loops into a single outer loop and have your If-Else inside it. That's it!
Just out of interest, how does quoting some generalised 'C' code and re-naming the problem as 'binary search', help ?
OP's problem is with convergence. Have you actually read all the Posts in this thread?
Originally Posted by Lenggries
So now that you know where your mistake is, it's your job to fix it.
The 'issues' have already been well defined - Using Option Explicit, defining variables as Double rather than Single, using a Constant rather than an assigned variable, and using descriptive variable names may be good ideas but none of those will actually help the problem of non-convergence.
I think OP is asking for help to resolve the problem, rather than inviting criticism
Last edited by Doogle; Jun 17th, 2013 at 01:30 PM.