'' 
'' COPYRIGHT (C) 1987, CACI, INC. - FEDERAL, LA JOLLA
''
''
'' Model: bank      Investigating service time of customers depending on
''                  the number of tellers and other factors.
''
''-----------------------------------------------------------------------

main  
      define FORM.PTR as a pointer variable

'' INITIALIZE INTEGRATOR 

      OPEN 1 FOR INPUT, NAME IS "coarse.dat"
      USE 1 FOR INPUT  '' file "fine.dat" contains init for fine integration

      READ MAX.STEP.V
       READ AS /
      READ MIN.STEP.V
       READ AS /
      READ ABS.ERR.V
       READ AS /
      READ REL.ERR.V
       READ AS /

      CLOSE 1

      USE 5 FOR INPUT

''  
'' INITIALIZE VARIABLES
''  
      LET RHO   =  0.0023769
      LET G     =  32.2 

      LET Y1    =  4.0  '' Ejection rail height
   
   ''let V.AIR = 250    // Knots
   ''let V.EJECT = 40   // ft/sec
   ''let ALTITUDE = 45  // ft

      show FORM.PTR with "eject.frm"
	  if ACCEPT.F(FORM.PTR, 0) eq "OK"
	      let V.AIR = DDVAL.A(DFIELD.F("AIR", FORM.PTR))   ''250   Knots
          let V.EJECT = DDVAL.A(DFIELD.F("EJECT", FORM.PTR)) ''40  ft/sec
          let ALTITUDE = DDVAL.A(DFIELD.F("ALTITUDE", FORM.PTR))  ''45 ft
      else
	      stop
	  endif

	  

      let V.AIR = V.AIR * 1.68777777  '' change to ft/sec for internal use

'' INITIALIZE STATE VARIABLES AND DERIVATIVES 

      CREATE AN AIRCRAFT
      LET DRTN.A(AIRCRAFT) = 'V.AIRCRAFT'    '' Switch on graphic display
      SHOW AIRCRAFT WITH "plane"
      LET Y(AIRCRAFT) = ALTITUDE
      LET D.X(AIRCRAFT) = V.AIR

      '' Display these dials under VXFORM.V = 0 ; NDC's

      DISPLAY SECS WITH "dials"
      DISPLAY SECS10 WITH "dials10"
      DISPLAY XAS WITH "dialxas"
      DISPLAY YAS WITH "dialyas"

      LET XMIN = -50
      LET XMAX = 350

      LET VXFORM.V = 1
      CALL SETWORLD.R(XMIN, XMAX, ALTITUDE-100, ALTITUDE+200)

      CREATE A GROUND
      LET DRTN.A(GROUND) = 'V.GROUND'
      LET LOCATION.A(GROUND) = LOCATION.F(0, 0)

      ACTIVATE AN OUTPUT NOW
      ACTIVATE AN EXPLOSION IN (MAX.STEP.V * 5) UNITS
      SHOW EXPLOSION WITH "xplode"

      ACTIVATE THE AIRCRAFT NOW

      LET HEADING.V = 'HEADER'   
      LET LINES.V = 55

      START SIMULATION

      print 4 lines thus

      END OF SIMULATION



end   '' MAIN

''-----------------------------------------------------------

PROCESS AIRCRAFT

    WORK CONTINUOUSLY EVALUATING 'FLIGHT' TESTING 'EMERGENCY'

    CREATE A PILOT

    LET THETAE = 15.0 / RADIAN.C               '' Ejection angle from vertical
    LET VX = V.AIR - V.EJECT * SIN.F (THETAE)
    LET VY = V.EJECT * COS.F (THETAE)
    LET ORIENTATION.A(PILOT) = THETAE

    LET CD    =  1.
    LET AREA  =  10.  
    LET DRAG(PILOT) = 0.5 * RHO * CD * AREA    '' Initially...
    LET MASS(PILOT) = 7.0                      '' Pilot + Seat

    LET X(PILOT) = LOCATION.X(AIRCRAFT)
    LET Y(PILOT) = LOCATION.Y(AIRCRAFT)
    LET VEL(PILOT) = SQRT.F (VX*VX + VY*VY)
    LET THETA(PILOT) =  ARCTAN.F (VY, VX)

    LET D.X(PILOT) =  VEL(PILOT) * COS.F (THETA(PILOT))
    LET D.Y(PILOT) =  VEL(PILOT) * SIN.F (THETA(PILOT))

    ACTIVATE PILOT NOW

    LET PTCHRATE(AIRCRAFT) = - 0.1  '' should really depend on airspeed..?

    WORK CONTINUOUSLY EVALUATING 'FLIGHT' TESTING 'FLTTIME'

    IF TIME.V LT 5.0
        LET PTCHRATE(AIRCRAFT) = - PTCHRATE(AIRCRAFT) * 4
        WORK CONTINUOUSLY EVALUATING 'FLIGHT' TESTING 'FLTTIME'
    ENDIF

    CREATE AN EXPLOSION
    SHOW EXPLOSION WITH "xplode"
    ACTIVATE EXPLOSION NOW

    IF THETA(AIRCRAFT) GT 0            '' Mid-air explosion
        LET STATUS(AIRCRAFT) = STATUS(AIRCRAFT) + 2
        WAIT MAX.STEP.V * 10 UNITS
        LET X(AIRCRAFT) = 0
        LET Y(AIRCRAFT) = 0
        LET LOCATION.A(AIRCRAFT) = 0   '' Disappear...
        LET DRTN.A(AIRCRAFT) = 0
    ELSE
        LET STATUS(AIRCRAFT) = 8       '' On the ground........
    ENDIF

    SUSPEND

    END

''-----------------------------------------------------------

FUNCTION DEPLOY(PILOT)
    DEFINE PILOT AS POINTER VARIABLE

    LET HEIGHT = Y(PILOT)

    IF D.Y(PILOT) LT -5.0         '' dropping at least 5 ft/sec
     AND HEIGHT LT 10000
     AND (D.X(PILOT) LT 150.0     '' wait to lose forward speed..
          OR HEIGHT LT 100)       '' unless very close to ground !
        RETURN WITH 1
    ENDIF

    RETURN WITH 0

    END

''-----------------------------------------------------------

FUNCTION DESCENT(PILOT)
    DEFINE PILOT AS POINTER VARIABLE

    IF Y(PILOT) LE 2.0 LT L.Y(PILOT)
        RETURN WITH 1
    ENDIF

    RETURN WITH 0

    END

''-----------------------------------------------------------

ROUTINE EJECT(PILOT)
    DEFINE PILOT AS POINTER VARIABLE

    LET D.X(PILOT) = VEL(PILOT) * COS.F (THETA(PILOT))
    LET D.Y(PILOT) = VEL(PILOT) * SIN.F (THETA(PILOT)) 

    RETURN
    END   

''-----------------------------------------------------------

FUNCTION EMERGENCY(AIRCRAFT)
    DEFINE AIRCRAFT AS POINTER VARIABLE

    IF STATUS(AIRCRAFT) NE 0
        RETURN WITH 1
    ENDIF

    RETURN WITH 0

    END    

''-----------------------------------------------------------

PROCESS EXPLOSION

    LET STATUS(AIRCRAFT) = STATUS(AIRCRAFT) + 1
    DISPLAY AIRCRAFT

    WAIT MAX.STEP.V * 2 UNITS

    LET STATUS(AIRCRAFT) = STATUS(AIRCRAFT) - 1
    DISPLAY AIRCRAFT

    END    

''-----------------------------------------------------------

ROUTINE FLIGHT(AIRCRAFT)
    DEFINE AIRCRAFT AS POINTER VARIABLE

    LET D.THETA(AIRCRAFT) = PTCHRATE(AIRCRAFT)
    LET D.X(AIRCRAFT) = V.AIR * COS.F(THETA(AIRCRAFT))
    LET D.Y(AIRCRAFT) = V.AIR * SIN.F(THETA(AIRCRAFT))

    END

''-----------------------------------------------------------

FUNCTION FLTTIME(AIRCRAFT)
    DEFINE AIRCRAFT AS POINTER VARIABLE

    IF Y(AIRCRAFT) LE 0
        RETURN WITH 1
    ENDIF

    IF THETA(AIRCRAFT) LE -PI.C/8
     AND PTCHRATE(AIRCRAFT) LT 0
        RETURN WITH 1
    ENDIF

    IF THETA(AIRCRAFT) GE PI.C/8
        RETURN WITH 1
    ENDIF

    RETURN WITH 0

    END

''-----------------------------------------------------------

routine  HEADER   
  print  7 lines thus   
             

                             Pilot  Ejection  Model
 
                              
    Time       X          Y        Speed      Theta      D.X     D.Y     D.V


  return
end   '' HEADER

''-----------------------------------------------------------

FUNCTION HITGROUND(SEAT)
    DEFINE SEAT AS POINTER VARIABLE
    IF Y(SEAT) LE 0 LT L.Y(SEAT)
        RETURN WITH 1
    ENDIF
    RETURN WITH 0
    END

''-----------------------------------------------------------

ROUTINE LINEOUT
   
      PRINT 1 LINE WITH 
      TIME.V, X(pilot), Y(pilot), VEL(pilot), THETA(pilot),
       D.X(pilot), D.Y(pilot), D.VEL(pilot)
      THUS  
     *.***    ***.**    ***.**     ***.**     **.**    ***.**  ***.**  ***.**
      RETURN
      END   

''-----------------------------------------------------------

PROCESS OUTPUT

    WHILE 1 EQ 1
    DO
        let xsize = XMAX - xmin
        if PILOT NE 0 AND X(PILOT) gt 0.8 * XMAX
         or X(aircraft) ge XMAX
         or Y(aircraft) le -0.25 * xsize

            IF PILOT NE 0
                let xmin = min.f( X(PILOT), X(aircraft) ) - 40
                if abs.f(X(aircraft) - X(PILOT)) gt 0.75 * xsize
                 or abs.f(Y(aircraft) - Y(PILOT)) gt 0.5 * xsize
                 or Y(aircraft) le ALTITUDE - 0.25 * xsize
                    let xsize = xsize * 2
                endif
            ELSE
                LET XMIN = X(AIRCRAFT)
            ENDIF
            let XMAX = xmin + xsize
            call setworld.r(XMIN, XMAX, 
                            ALTITUDE - 0.25 * xsize, ALTITUDE + 0.50 * xsize)
            display ground

        endif

        IF STATUS(AIRCRAFT) LT 8
            DISPLAY AIRCRAFT AT ( X(AIRCRAFT), Y(AIRCRAFT) )
        ENDIF
        IF SEAT NE 0
          AND STATUS(SEAT) LT 2
            let orientation.a(seat) = orientation.a(seat) + pi.c/8
            DISPLAY SEAT AT ( X(SEAT), Y(SEAT) )
        ENDIF
        IF PILOT NE 0
         AND STATUS(PILOT) LT 3
            DISPLAY PILOT AT ( X(PILOT), Y(PILOT) )
            LET XAS = D.X(PILOT)
            LET YAS = D.Y(PILOT)
        ENDIF

        LET SECS = TIME.V
        LET SECS10 = TIME.V * 10

        WAIT MAX.STEP.V UNITS
    LOOP
    END

''-----------------------------------------------------------

PROCESS PILOT

    DEFINE .SELF TO MEAN PROCESS.V

    LET DRTN.A(PILOT) = 'V.PILOT'     '' Enable graphics output
    SHOW .SELF WITH "pilot1"

    WORK CONTINUOUSLY EVALUATING 'EJECT', TESTING 'RAILTEST'

    WRITE AS "..Leaving Rails", /
    CALL  LINEOUT

    WORK CONTINUOUSLY EVALUATING 'TRAJECTORY', TESTING 'TAILTEST'

    IF STATUS(.SELF) LT 0            '' hit the tail....
        WRITE AS "Hit the Tail!", /
        CALL LINEOUT
        DISPLAY .SELF
        LET ORIENTATION.A(.SELF) = - PI.C
        LET THETA(AIRCRAFT) = THETA(AIRCRAFT) + PI.C/32  '' slight nose-up
    ELSE

        WRITE AS "Clear...!", /
        CALL LINEOUT

        WORK CONTINUOUSLY EVALUATING 'TRAJECTORY', TESTING 'DEPLOY'

        WRITE AS "Chute Open..", /
        CALL LINEOUT

        CALL SEPARATION

        LET STATUS(.SELF) = 1   '' chute open...
        ERASE .SELF
        SHOW .SELF WITH "pchute"

        LET DRAG(.SELF) = DRAG(.SELF) * 20     '' area increase
        LET MASS(.SELF) = MASS(.SELF) * 0.5    '' less seat mass
    ENDIF

    WORK CONTINUOUSLY EVALUATING 'TRAJECTORY' TESTING 'DESCENT'

    WRITE AS "On the Ground..", /
    CALL LINEOUT

    IF STATUS(.SELF) GT 0
        LET ORIENTATION.A(.SELF) = 0    '' upright
        ERASE .SELF
        IF ABS.F( X(.SELF) - LOCATION.X(AIRCRAFT) ) LT 30  '' too close !
            LET STATUS(.SELF) = 3
            DISPLAY .SELF WITH "pilot2"
        ELSE
            LET STATUS(.SELF) = 2
            DISPLAY .SELF WITH "pilot3"
        ENDIF
    ENDIF

    WAIT MAX.STEP.V * 5 UNITS

    IF STATUS(AIRCRAFT) LT 2  '' still flying..
        CANCEL AIRCRAFT
    ENDIF
    CANCEL OUTPUT

    write as "**************************", /
    write as "---> press any key to quit", /
    write as "**************************", /
    READ AS /		''**** causes problem with simdemo ???????

    STOP

    END

''-----------------------------------------------------------

FUNCTION RAILTEST(PILOT)
    DEFINE PILOT AS POINTER VARIABLE

    '' Is the pilot crossing the end of the seat rail ?

    IF L.Y(PILOT) LT L.Y(AIRCRAFT) + Y1     '' wasn't at end last integration st
     AND Y(PILOT) GE Y(AIRCRAFT) + Y1       '' ..but is now !
        RETURN WITH 1
    ENDIF
    RETURN WITH 0

    END

''-----------------------------------------------------------

PROCESS SEAT
    DEFINE .SELF TO MEAN PROCESS.V

    WORK CONTINUOUSLY EVALUATING 'TRAJECTORY' TESTING 'HITGROUND'

    LET STATUS(.SELF) = 2
    SUSPEND

    END

''-----------------------------------------------------------

ROUTINE SEPARATION
'' Seat separation as chute opens..

    CREATE A SEAT
    SHOW SEAT WITH "seat"

    LET X(SEAT) = X(PILOT)
    LET Y(SEAT) = Y(PILOT)
    LET VEL(SEAT) = VEL(PILOT)
    LET THETA(SEAT) = THETA(PILOT)

    LET DRAG(SEAT) = DRAG(PILOT)        '' same area, cd. etc.. ?
    LET MASS(SEAT) = MASS(PILOT) * 0.5  '' split up the mass

    ACTIVATE SEAT NOW

    END

''-----------------------------------------------------------

FUNCTION TAILTEST(PILOT)
    DEFINE PILOT AS POINTER VARIABLE

    LET NOSEDOWN = -THETA(AIRCRAFT)

    LET HORIZ = X(AIRCRAFT) - X(PILOT)
    LET FINX = 25 * COS.F(NOSEDOWN)

    LET STATUS(PILOT) = 0    '' reset..

    IF HORIZ GT FINX         ''  ok, clear behind tail of aircraft
     OR HORIZ LT 0            '' ..ahead of aircraft - it has crashed !
        RETURN WITH 1
    ENDIF

    LET VERT = Y(PILOT) - Y(AIRCRAFT)
    LET FINY = 25 * SIN.F(NOSEDOWN) + 12 * COS.F(NOSEDOWN)

    IF VERT GT FINY          '' good and high..
     AND D.Y(PILOT) GT 10    ''.. and travelling upward
        RETURN WITH 1        '' certain to clear
    ENDIF

    IF VERT LE FINY          '' low, and not far enough behind to clear
     AND (HORIZ GT FINX * 0.75
          OR D.Y(PILOT) LT D.Y(AIRCRAFT))
        LET STATUS(PILOT) = -1
        RETURN WITH 1
    ENDIF

    RETURN WITH 0

    END

''-----------------------------------------------------------

ROUTINE TRAJECTORY(OBJ)
      DEFINE OBJ AS POINTER VARIABLE

      DEFINE SPEED, ANGLE, COSTHETA, SINTHETA  AS DOUBLE VARIABLES

      '' Use some local variables for efficiency..

      LET SPEED = VEL(OBJ)
      LET ANGLE = THETA(OBJ)
      LET COSTHETA = COS.F(ANGLE)
      LET SINTHETA = SIN.F(ANGLE)
      LET DRAGFORCE = DRAG(OBJ) * SPEED * SPEED

      '' Evaluate the derivates for position and velocity

      LET D.X(OBJ) = SPEED * COSTHETA
      LET D.Y(OBJ) = SPEED * SINTHETA 
      LET D.VEL(OBJ) = - DRAGFORCE/MASS(OBJ) - G * SINTHETA   
      LET D.THETA(OBJ) = - G * COSTHETA / SPEED

      RETURN
      END

''-----------------------------------------------------------

display routine aircraft(aircraft)
    define aircraft as pointer variable

    if status(aircraft) lt 2
        Let DCOLOR.A(ICON.A(AIRCRAFT)) = 30
    else
        Let DCOLOR.A(ICON.A(AIRCRAFT)) = 180
    endif
    let orientation.a(aircraft) = THETA(aircraft)
    display icon.a(aircraft)

    if mod.f(status(aircraft), 2) ne 0   ''  explosion in effect
        DISPLAY ICON.A(EXPLOSION)
    endif

end   '' AIRCRAFT

''-----------------------------------------------------------

DISPLAY ROUTINE GROUND(GROUND)
    DEFINE GROUND AS POINTER VARIABLE
    DEFINE ARR AS 2-DIM REAL ARRAY
    RESERVE ARR(*) AS 2 BY 2
    LET ARR(1,1) = XMIN
    LET ARR(1,2) = XMAX
    CALL LINECOLOR.R(30)
    CALL LINEWIDTH.R(360)
    CALL POLYLINE.R(2, ARR(*))
    CALL LINEWIDTH.R(60) '' return to small value
    RELEASE ARR(*)
    END

''-----------------------------------------------------------

display routine pilot(pilot)
    define pilot as pointer variable

    if STATUS(pilot) lt 0
        call fillcolor.r(180)
    else
        if STATUS(pilot) eq 1
            let orientation.a(pilot) = THETA(PILOT) + PI.C/2
            call fillcolor.r(255)
        else
            call fillcolor.r(30)
        endif
    endif

    display icon.a(pilot)

    END
