!
!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
!
!         <<<<<---------------------------------------------->>>>>
!         <<<<<  4.  P R O G R A M    U N I T S              >>>>>
!         <<<<<      A N D    P R O C E D U R E S            >>>>>
!         <<<<<---------------------------------------------->>>>>
!
!&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

! It is usually preferable to conceive and write computer codes as
! consisting of different program UNITS
! These can be of three kinds
!
!  1. main program
!  2. external sub-program
!  3. module
!
! An external sub-program can be 
!
!    2.1 Function   (returns a single object and usually does not 
!                    modify its argument)
!    2.2 Subroutine (returns several objects and may well modify 
!                    its arguments)
!
!    FUNCTIONS AND SUBROUTINES ARE COLLECTIVELY REFERRED TO AS 
!    *** PROCEDURES ***
!
!
!***********************************************************************
! THE MAIN PROGRAM
!***********************************************************************
!
! Every complete program must have ONE AND ONLY ONE MAIN program. 
! Optionally, it may contain calls to sub-programs
!
! A main program has the following structure
!
!  [PROGRAM programme-name]
!         [specification-statements]
!         [executable-statements]
!  [CONTAINS 
!        internal-subprograms]
!  END [PROGRAM [programme-name]]
!
! 
! The PROGRAM statement is optional but highly recommended
! The only non-optional statement is END  (signal the end of the 
! code and when executed causes the code to halt
!
! ============================
! The SPECIFICATION STATEMENTS
!         
! Define the environment for the executable statements.
! These include the DECLARATIONS:
! we have seen five types 
!
! INTEGER              (intrinsic)
! REAL                   "     "
! COMPLEX                "     "
! LOGICAL                "     "
! CHARACTER              "     "
! TYPE (type-name)     (derived)
!
! We will see other specification statements later

! ============================
! The EXECUTABLE STATEMENTS
!         
! The executable statements specify the actions that are to be 
! performed.
!
! We have seen 
!
! GO TO 
! IF statement and construct
! DO constructs
! READ and PRINT statements
!
!
! ============================
! The CONTAINS statement
!
!
! The CONTAINS statement flags the presence of one or more 
! INTERNAL sub-programs         


!***********************************************************************
! THE EXTERNAL SUB-PROGRAMS
!***********************************************************************
!
! External sub-programs are called from a main program or elsewhere,
! usually do perform a WELL-DEFIMNED TASK 
! Optionally, they may contain calls to internal sub-programs
!
! An external sub-program has one of the two following structures
!
!  subroutine-statement
!         [specification-statements]
!         [executable-statements]
!  [CONTAINS 
!        internal-subprograms]
!  END [SUBROUTINE [subroutine-name]]
!
! 
!  function-statement
!         [specification-statements]
!         [executable-statements]
!  [CONTAINS 
!        internal-subprograms]
!  END [FUNCTION [function-name]]
!
! 
! The CONTAINS statement plays exactly the same role as in the MAIN
!
! The effect of executing an END statement here is to return control 
! to the HOST (the programi unit from where the sub-program has
! been called).
!
! The simples form of external sub-program defines a subroutine
! without arguments
!

  subroutine INIT
      ..... 
      .....
  end [subroutine INIT]    

! When a program consists of different stages, external sub-programs 
! are useful
!
! EXAMPLE:
!
  PROGRAM integrate
       CALL INIT_COND
       CALL INTEGR
       CALL COMPUTE_RESULTS
       CALL PRINT_RESULTS
  END PROGRAM integrate  

!
! However, there is something missing from this program. How does the 
! subroutine INTEGR know the initial conditions specified by 
! subroutine INIT_COND?
!
! There are two methods by which information may be passed 
!
! 1. Via data held in a MODULE, which is USED by different 
!    sub-programs
! 2. Via ARGUMENTS in the subroutine statement and call
!
!

!***********************************************************************
! MODULES
!***********************************************************************
!
! The third type of program unit, the MODULE, is useful for GLOBAL
! data and is important for the packaging of derived data types
!
! It has the form 
!
!  MODULE module-name
!       [specification-statements]
!  [CONTAINS
!        module-sub-programs]
!  END [MODULE [module-name]]
!
! In its simplest form, a module consists only of data specifications
! For example
!
  MODULE STATES
      REAL, DIMENSION(100) :: X, V
  END MODULE STATES

! Then this module is accessed through the statement
!
  USE STATES

! appearing at the beginning of the program integrate (see above)
! and sub-programs   INTEGR, COMPUTE_RESULTS and PRINT_RESULTS
!


!***********************************************************************
! ARGUMENTS OF PROCEDURES (FUNCTIONS AND SUBROUTINES)
!***********************************************************************
!
! Procedure arguments provide an alternative means for two program 
! units to access the same data
!
!
  PROGRAM integrate
       REAL, DIMENSION(100) :: X, V
       REAL, DIMENSION(100) :: X_0, V_0
       CALL INIT_COND(X_0,V_0)
       CALL INTEGR(X,V)
       CALL COMPUTE_RESULTS(X,V)
       CALL PRINT_RESULTS(X,V)
  END PROGRAM integrate  

  subroutine INIT_COND(X,V)
      REAL, DIMENSION(100) :: X, V
      ...
      X(1) = X0
      ...
  end subroutine INIT_COND    

! Each subroutine receives two vectors (position and velocities of
! the system particles) as DUMMY (MUETS) arguments.
!
! We can imagine for example that we are interested in evolving 
! only a portion of the system particles. In this case we can 
! limit for example INTEGR to a subset by doing the following
!
  CALL INTEGR(N_red,X(1:N_red),V(1:N_red))
!
! In this case the subroutine INTEGR might look like this
!
  SUBROUTINE INTEGR(N,X,V)
       INTEGER N
       REAL, DIMENSION(N) :: X,V
       DO I=1, N
          ....
       END DO
  END SUBROUTINE INTEGR
!
! Note that we have given different names to the arguments.  Each dummy 
! argument of a given procedure (function or subroutine) has to
! agree with the corresponding arguments in the calling statements
! in 
! 
! 1. type
! 2. type parameters
! 3. shape
!
! We'll se later on that for characters these requirements can be
! relaxed a little.
!
! The name of a dummy variable is only known and used within the 
! procedure. However, when the same name can be used for arguments 
! and dummy arguments it should be done.


!***********************************************************************
! The RETURN statement
!***********************************************************************

! Just as the STOP statement the RETURN statement provides a means
! of stopping the execution. When it is encountered in a sub-program
! the control is returned to the main or sub-program containing the 
! call. 

  RETURN

! Like the STOP statement, the RETURN statement can be labelled, may
! be part of an IF statement. 

! The RETURN statement must not appear among the execitable statements
! of a main program       


!***********************************************************************
! Argument INTENT 
!***********************************************************************       

! Dummy arguments in subroutines can be used to pass information IN
! or OUT of a subroutine or can be used for BOTH
!
! Example

  REAL, DIMENSION(1000) :: Y
  INTEGER NPOINTS
  REAL MOYENNE
  
  NPOINTS = 50
  CALL MEAN(Y(1:NPOINTS),MOYENNE,NPOINTS)
  .....
  END PROGRAM
!-----------------------------------------------------------------------
  SUBROUTINE MEAN(X,XM,N)
      INTEGER N                          ! N is used to pass info IN
      REAL, DIMENSION(N) :: X            ! The array X passes info OUT
      REAL XM                            ! The value of XM returns the
      XM = 0.0                           ! average of array X, thus
      DO I=1, N                          ! passes info OUT
         XM = XM + X(I)
      END DO
      XM = XM / N 
  END SUBROUTINE MEAN

! A dummy argument can be used to pass information IN AND OUT
! 
! Example

  SUBROUTINE MEAN(X,XM,N)
      INTEGER N                          ! N is used to pass info IN
      REAL, DIMENSION(N) :: X            ! The array X passes info OUT
      REAL XM                            ! The value of XM returns the
      XM = 0.0                           ! average of array X, thus
      DO I=1, N                          ! passes info OUT
         XM = XM + X(I)
      END DO
      XM = XM / N
      IF ( XM .GT. 1.0 ) N = N - 1       ! The value of N is modified       
  END SUBROUTINE MEAN                    ! if tyhe condition is verified
                                         ! hence N is used to pass 
                                         ! info OUT too

! When a dummy variable is modified inside the procedure it MUST be
! associated with a VARIABLE in the main or sub-program where it 
! is called from and not associated to an expression


  CALL MEAN(X,XM,N)    ! is legal
  
  CALL MEAN(X,XM,N*2)  ! is NOT legal if INTENT of N is INOUT or OUT 

                   
! Compilers DO NOT check this sort of consistency. FORTRAN 90 
! allows for the intent of a dummy variable to be specified 
! explicitly. 
!
! THIS IS STRONGLY RECOMMENDED AS IT CAN AVOID VERY NASTY ERRORS
! AT EXECUTION THAT WOULD BE EXTREMELY DIFFICULY TO DETECT
!

  INTENT(IN)
  INTENT(OUT)
  INTENT(INOUT)

! Example
 
  SUBROUTINE MEAN(X,XM,N)
      INTEGER, INTENT(INOUT) N              ! The compiler  allows the 
                                            ! dummy variable to be 
                                            ! modified inside the 
                                            ! procedure      
      REAL, INTENT(IN), DIMENSION(N) :: X   ! The compiler will NOT 
                                            ! allow the dummy variable 
                                            ! to be modified inside the 
                                            ! procedure      
      REAL XM                            
      XM = 0.0                           
      DO I=1, N                          
         XM = XM + X(I)
      END DO
      XM = XM / N
      IF ( XM .GT. 1.0 ) N = N - 1             
  END SUBROUTINE MEAN   
  

!***********************************************************************
! FUNCTIONS
!***********************************************************************       

! Functions are similar to subroutines in many respects, but they 
! are invoked WITHIN AN EXPRESSION and return a value that is used
! WITHIN the expression
!
! Example
!

  INTEGER IFLAG
  REAL, DIMENSION(2) :: A,B,C,D
  
  IF ( DIST(A,B) .LE. DIST(C,D) ) IFLAG = 0

! The function DIST computes the distance between point on a plane
!

  FUNCTION DIST(P1,P2)
     REAL DIST, DX, DY
     REAL, INTENT(IN), DIMENSION(2) :: P1,P2
     DX = P1(1) - P2(1)
     DY = P1(2) - P2(2)
     DIST = SQRT( DX*DX + DY*DY )
  END FUNCTION DIST                   

! Note the declaratiuon for the function result. The result behaves 
! just as DUMMY ARGUMENT WITH INTENT(OUT)
! The type of a function may also be defined like this:

  REAL FUNCTION DIST(P1,P2)            ! The result DIST is declared 
                                       ! like this as a REAL number
     REAL DX, DY
     REAL, INTENT(IN), DIMENSION(2) :: P1,P2
     DX = P1(1) - P2(1)
     DY = P1(2) - P2(2)
     DIST = SQRT( DX*DX + DY*DY )
  END FUNCTION DIST 


!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!
! EXPLICIT AND IMPLICT INTERFACES: THE CONCEPT OF " INTERFACE "
!                                                   ---------
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  

! A call to an INTERNAL subprogram MUST be from a statement within 
! the SAME program unit
!
! The compiler will know all about the internal subprogram, in 
! particular about its INTERFACE, i.e. 
!
! 1. Whether it defines a FUNCTION or a SUBROUTINE
! 2. The NAMES and PROPERTIES of the arguments
! 3. The properties of the result if ir defines a FUNCTION
!
! We say that the INTERFACE of an INTERNAL sub-program is EXPLICIT.
!
! This is not the case for calls to EXTERNAL PROCEDURES
! For these, the compiler may not have access to his code and
! hence the INTERFACE of an external procedure is IMPLICIT.
! This may lead to errors and problems.
!
! It is highly recommended to make the interface of external 
! sub-programs explicit through an INTERFACE BLOCK. This has 
! the following form

  INTERFACE 
      interface-body
  END INTERFACE

! Normally the interface-body is an EXACT copy of the external 
! sub-program's header, the specifications of its arguments and 
! function result and its END statement. However, 
!
! 1. The names of the arguments may be changed
! 2. Other specifications may be included (not INTERNAL procedures)

!=======================================================================
! Perhaps the most convenient way to use make interfaces of 
! external sub-programs explicit is to place all the corresponding 
! interface blocks in a MODULE unit and than USE the module
!=======================================================================

! Example: PROCEDURES as ARGUMENTS

! So far we have taken the actual (and dummy) arguments of a 
! procedure invocation to be VARIABLES and EXPRESSIONS. Another 
! possibility is for them to be PROCEDURES.
!

   REAL FUNCTION MINIMUM( A, B, FUNC )
   ! FUNCTION MINIMUM( A, B, FUNC )
   ! REAL MINIMUM
   !
   ! Returns the minimum of the function FUNC(X) for X in [A,B] 
   !
   REAL, INTENT(IN) :: A, B
   !---------------------------
   INTERFACE                      ! This plays a similar role to 
       REAL FUNCTION FUNC(X)      ! the declaration of A and B
          REAL X
       END FUNCTION FUNC
   END INTERFACE
   !---------------------------
   REAL F,X
   ....
   F = FUNC(X)
   ....
   MINIMUM = ...
   END FUNCTION MINIMUM

! Notice the way the PROCEDURE argument is declared by an INTERFACE
! block playing a similar role to that of the type declaration 
! statement for a data object.

! IT WOULD MAKE NO SENSE TO SPECIFY AN INTENT ATTRIBUTE 
! FOR A DUMMY PROCEDURE, AND THIS IS NOT PERMITTED

! The code that would use the above function would looke like

  PROGRAM MAIN
     REAL P_1,P_2,F
     !---------------------------
     INTERFACE                      ! This plays a similar role to 
       REAL FUNCTION FUNC(X)        ! the declaration of A and B
          REAL X
       END FUNCTION FUNC
     END INTERFACE
     !---------------------------
     ...
     F = MINIMUM( P_1, P_2, MY_FUNC )
  END PROGRAM
  !===========================
  ! External sub-programs
  !
  REAL FUNCTION MY_FUNC(X)
     ....
  END FUNCTION MY_FUNC

!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
! IMPORTANT:
! 
! The procedure that is passed as a DUMMY argument MUST be an 
! external procedure (the external function MY_FUNC above for 
! example). It is not allowed to use INTERNAL procedures as 
! dummy arguments
!+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
!
! KEYWORDS AND OPTIONAL ARGUMENTS
!
!%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

! When a subroutine has many arguments, it may be desirable to be 
! able to call it by specifying only a sub-set of its arguments  
!

  SUBROUTINE MIN_COND(N, F, X, UPPER, LOWER, START)

! Optional arguments may be declared OPTIONAL

  REAL, OPTIONAL :: UPPER, LOWER, START

! and call the procedure as

  CALL MIN_COND(N, F, X) 

! It may be very useful to use a KEYWORD ARGUMENT LIST. This is 
! a good choice also for what concerns the READABILITY of a code
! The list of arguments with their keywords must respect the
! positional order

  CALL   MIN_COND(N, F, X, START=X0 )

! The KEYWORDS are the DUMMY argument names
! ==========================================

! There is a command that allows to detect whether an optional 
! argument is present and possibly take action consequently
!
  PRESENT(START)  ! this is a logical variable, .TRUE. if the 
                  ! dummy argument START has been passed in to 
                  ! the subroutine in the current call 
                  ! and .FALSE. otherwise  
