# BASIC Hydrodynamics

I'm currently translating the code examples in BASIC Hydrodynamics by A.C. Thompson into True BASIC. Here is the code for the streamline plotting program they provide in Apple BASIC. Pretty easy to translate it to True BASIC.

``` ! SPLOT ! BASIC Hydrodynamics ! Jovan Trujillo 6/1/2017 ! ! Got rid of all of the sphaghetti code in this version of SPLOT. ! I need to figure out how to get things really working well now. ! Plot streamlines around various objects. ! I also need to remember that global variables can only be used ! within subroutines if the subroutine is within the main END statement. ! Outside of the END statement subroutines are external and all parameters ! need to be passed as arguments. ! ! Sample input has always been: 20,20,1,1,1,5,5,1```

DIM S(210,210),QS(10),XS(10)
INPUT PROMPT "NO. GRID COLS.? ":J2
INPUT PROMPT "NO. GRID ROWS? ":K2
INPUT PROMPT "STREAM VELOCITY? ":U1
INPUT PROMPT "NO. SOURCES? ":M1

FOR M = 1 TO M1
INPUT PROMPT "Q/2PI? ":QS(M)
INPUT PROMPT "X? ":XS(M)
NEXT M

LET SF = 160 / K2
IF SF > 360 / J2 THEN LET SF = 360 / J2

FOR J = 1 TO J2
PRINT "ROW ";J;" OF ";J2
FOR K = 2 TO K2
LET S(J,K) = U1 * (K - 1)
FOR M = 1 TO M1
LET T1 = (J - XS(M)) / (K - 1)
LET T1 = ATN(T1) + 1.5708
LET S(J,K) = S(J,K) + QS(M) * T1
NEXT M
NEXT K
NEXT J

LET NR = 1
DO WHILE NR = 1
CALL L1000
INPUT PROMPT "TO REPLOT ENTER 1: ":NR
! GOTO 350
LOOP
PRINT "Press any key to quit."

SUB L1000
REM PLOTS STREAMLINES
LOCAL DEBUG
LET DEBUG = 0

INPUT PROMPT "NO. STREAMLINES? ":NSL
INPUT PROMPT "INTERVAL BETWEEN LINES? ":DS

IF DEBUG = 1 THEN
PRINT "LOCAL VARIABLES ARE: "
PRINT "NSL: ";NSL
PRINT "DS: ";DS
PRINT "J2: ";J2
PRINT "K2: ";K2
PRINT "SF: ";SF
PRINT "S1: ";S1
GET KEY done
FOR J = 1 TO 20
FOR K = 1 TO 20
PRINT "S(";J;",";K;") = "; S(J,K)
NEXT K
NEXT J
GET KEY done
END IF
! ClearSreen does th following Apple BASIC commands:
! HOME - Clear the screen
! VTAB 24 - position pen to 0,0 in lower left corner
! HGR - prepare graphics mode
CALL ClearScreen
FOR I = 1 TO NSL
LET S1 = DS * I
LET K = 0
FOR J = 1 TO J2
LET DY = 0
DO
LET K = K + 1
IF K = K2 THEN
! GOTO 1110
LET Y1 = (K2 - K + DY) * SF
LET X1 = J * SF
IF J > 1 THEN
! GOTO 1160
PLOT X1,Y1;
!PLOT X1,Y1
!LET K = 0
ELSE
PLOT X1,Y1
! GOTO 1170
!LET K = 0
END IF
END IF
LOOP WHILE S(J,K) < S1
LET DY = (S(J,K) - S1) / (S(J,K) - S(J,K-1))
LET Y1 = (K2 - K + DY) * SF
LET X1 = J * SF
IF J > 1 THEN
! GOTO 1160
SET COLOR 4
PLOT LINES: X1,Y1;
!PLOT X1,Y1
LET K = 0
ELSE
SET COLOR "white"
PLOT X1,Y1
! GOT 1170
LET K = 0
END IF
NEXT J
NEXT I
GET KEY done
END SUB

SUB ClearScreen
LOCAL BLACK
LET BLACK = 1
CLEAR
SET WINDOW 0,320,0,240
SET COLOR BLACK
PLOT 0,0
END SUB

END ! Program

### Global Variables in External SUBS

Hi Jovan,

You posted:

! I also need to remember that global variables can only be used
! within subroutines if the subroutine is within the main END statement.
! Outside of the END statement subroutines are external and all parameters
! need to be passed as arguments.

This is not true of True Basic. Any variable can be used in any External SUB. This is done via the PUBLIC and DECLARE PUBLIC statements.

In the Calling program, you list the variables in question in a PUBLIC statement. Then, in the External SUB which is outside the END statement of the Calling program, the same variables are listed in a DECLARE PUBLIC statement.

This is illustrated as follows:

!! Calling program
···option nolet
···PUBLIC a(0,3) ! In lieu of "Dim a(0,3)". Suppose the variable is a numeric array, here a 3 column array with unspecified number of rows. This line makes this variable "global".
·····! Further suppose that the DATA for this array is kept in, generated by, read from a file, or whatever; inside an external SUB called "Get_Data", located below the END statement of the Calling Program. No args need be passed (although in some cases passing them might be desirable).
···CALL Get_Data ! This goes and gets the array data and assigns it to re-dimmed array "a(n,3)" where n is the number of rows of data in the SUB.
···set cursor 3,1
···MAT PRINT using " ####": a
···get key zz
··END ! of the Calling program

···SUB Get_Data
······option nolet
······DECLARE PUBLIC a()
······n=4 ! rows
······MAT REDIM a(n,3)
······DATA 11,12,13
······DATA 21,22,23
······DATA 31,32,33
······DATA 41,42,43
···END SUB

In fact, the External SUB can be located in a completely separate file, known as a LIBRARY file, the contents of which the calling program can access by means of the LIBRARY statement. The LIBRARY file need not even be opened by you.

The Calling Program invokes the LIBRARY by means of the LIBRARY statement, finds the SUB of interest therein and employs it, just as in the above example.
To implement this, in the Calling program, add the statement:

LIBRARY "PathToLibraryFile\LibraryFileName.txt". Put this line somewhere before the SUB is CALLed.

The Library file itself MUST have, as the very first non-remmed line, the word EXTERNAL. Suppose the SUB "Get_Data" is located, perhaps along with a bunch of other SUBS, in a Library file named "xyz LIB.txt" (The extention can be .txt, .tru or .trc, but I usually use .txt) After a large collection of Library files accumulates, it is convenient to have Windows preview the contents. Windows won't preview .tru or .trc files. I have many LIB's, some with over 1000 lines of code. I forget what's in them so the preview is quite useful.

So the above example would become:

!··Calling program
····option nolet
····LIBRARY "PathToLibraryFile\LibraryFileName.txt"
····PUBLIC a(0,3)
····CALL Get_Data ! Goes and gets the array data and assigns it to array "a(n,3)" where n is the number of rows of data in the SUB.
····MAT PRINT a
····get key zz
···END ! of the Calling program

!··LibraryFileName.txt
···EXTERNAL
····SUB Get_Data
······option nolet
······DECLARE PUBLIC a()
······n=5 ! rows
······MAT REDIM a(n,3)