!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!
!     This is an example call of MIDACO 6.0
!     -------------------------------------
!
!     MIDACO solves Multi-Objective Mixed-Integer Non-Linear Problems:
!
!
!      Minimize     F_1(X),... F_O(X)  where X(1,...N-NI)   is CONTINUOUS
!                                      and   X(N-NI+1,...N) is DISCRETE
!
!      subject to   G_j(X)  =  0   (j=1,...ME)      equality constraints
!                   G_j(X) >=  0   (j=ME+1,...M)  inequality constraints
!
!      and bounds   XL <= X <= XU
!
!
!     The problem statement of this example is given below. You can use 
!     this example as template to run your own problem. To do so: Replace 
!     the objective functions 'F' (and in case the constraints 'G') given 
!     here with your own problem and follow the below instruction steps.
!
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCC   MAIN PROGRAM   CCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      PROGRAM MAIN
      IMPLICIT NONE
      INCLUDE 'mpif.h'          
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!     Dimensions of the optimization problem        
      INTEGER O, N, NI, M, ME
!     Lower and upper bounds ('XL' & 'XU') and optimization variable 'X'
      DOUBLE PRECISION XL(1000), XU(1000), X(1000)
!     Objectives 'F(X)' and constraints 'G(X)' 
      DOUBLE PRECISION F(10), G(1000)            
!     MIDACO information and stop flags
      INTEGER IFLAG, ISTOP
!     MIDACO parameter
      DOUBLE PRECISION PARAM(13)
!     MIDACO integer 'IW' and real'RW' workspace and pareto front 'PF'
      INTEGER LIW, LRW, LPF 
      PARAMETER (LIW = 5000, LRW = 20000, LPF = 20000)       
      INTEGER IW(LIW)
      DOUBLE PRECISION RW(LRW),PF(LPF)
!     Parameter for stopping criteria, printing and license
      INTEGER MAXTIME, MAXEVAL, PRINTEVAL, SAVE2FILE, I
      CHARACTER*60 KEY
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!     Arrays for parallelization (Increase allocation, if necessary)
      INTEGER C,P,IERR,THREAD,NTHREADS,STATUS(MPI_STATUS_SIZE)
      DOUBLE PRECISION XXX(10000), FFF(10000), GGG(10000) 
      DOUBLE PRECISION dx(100000),df(100000),dg(100000) 
      DOUBLE PRECISION ex(100000),ef(100000),eg(100000)       
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      CALL MPI_INIT( IERR )
      CALL MPI_COMM_RANK( MPI_COMM_WORLD, THREAD, IERR )
      CALL MPI_COMM_SIZE( MPI_COMM_WORLD, NTHREADS, IERR )
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC      
      KEY='MIDACO_LIMITED_VERSION___[CREATIVE_COMMONS_BY-NC-ND_LICENSE]'
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CC Step 1: Problem definition     CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!
!     Step 1.A : Problem dimensions
!     CCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      O  = 1  ! Number of objectives
      N  = 4  ! Number of variables (in total)
      NI = 2  ! Number of integer variables (0 <= NI <= N)
      M  = 3  ! Number of constraints (in total)
      ME = 1  ! Number of equality constraints (0 <= ME <= M)
!
!     Step 1.B : Lower and upper bounds: 'XL' and 'XU'
!     CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      DO I = 1,N
         XL(I) = 1.0D0
         XU(I) = 4.0D0
      ENDDO
!         
!     Step 1.C : Starting point 'X'
!     CCCCCCCCCCCCCCCCCCCCCCCCCCCCC     
      DO I = 1,N          
          X(I) = XL(I) ! Here for example: starting point = lower bounds
      ENDDO
      
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CC Step 2: Choose stopping criteria and printing options    CCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!
!     Step 2.A : Stopping criteria
!     CCCCCCCCCCCCCCCCCCCCCCCCCCCC
      MAXEVAL = 10000    ! Maximum evaluation budget (e.g. 1000000)
      MAXTIME = 60*60*24 ! Maximum time limit (e.g. 60*60*24 = 1 Day)
!
!     Step 2.B : Printing options
!     CCCCCCCCCCCCCCCCCCCCCCCCCCC
      PRINTEVAL = 1000 ! Print-Frequency for current best solution (e.g. 1000)
      SAVE2FILE = 1    ! Save SCREEN and SOLUTION to TXT-files [0=NO/1=YES]
      
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CC Step 3: Choose MIDACO parameters (FOR ADVANCED USERS)    CCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

      PARAM( 1) = 0.0D0  ! ACCURACY
      PARAM( 2) = 0.0D0  ! SEED
      PARAM( 3) = 0.0D0  ! FSTOP
      PARAM( 4) = 0.0D0  ! ALGOSTOP
      PARAM( 5) = 0.0D0  ! EVALSTOP
      PARAM( 6) = 0.0D0  ! FOCUS
      PARAM( 7) = 0.0D0  ! ANTS
      PARAM( 8) = 0.0D0  ! KERNEL
      PARAM( 9) = 0.0D0  ! ORACLE
      PARAM(10) = 0.0D0  ! PARETOMAX
      PARAM(11) = 0.0D0  ! EPSILON  
      PARAM(12) = 0.0D0  ! BALANCE
      PARAM(13) = 0.0D0  ! CHARACTER 

!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CC Step 4: Choose Parallelization Factor   CCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

      P = NTHREADS ! NTHREADS argument given automatically via command:
                   ! "mpirun -np NTHREADS ./run"   

!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCC     Start MPI Thread Splitting     CCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 
      IF (THREAD .EQ. 0) THEN
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCC     MPI Master MIDACO     CCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 
!     Copy starting point X in parallel array XXX
      DO C = 1,P
        DO I = 1,N          
            XXX((C-1)*N+I) = X(I) 
        ENDDO
      ENDDO
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!         
!     Call MIDACO by Reverse Communication
!      
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!     Print MIDACO headline with basic information
      CALL MIDACO_PRINT(1,PRINTEVAL,SAVE2FILE,IFLAG,ISTOP,F,G,X,XL, &
               XU,O,N,NI,M,ME,RW,PF,MAXEVAL,MAXTIME,PARAM,P,0,KEY)             
      DO WHILE(ISTOP.EQ.0) !~~~Start~of~reverse~communication~loop         

!       Store variables X in dummy dx and send to MPI slave
        DO C = 2, P
          DO I = 1,N        
             dx(I) = XXX((C-1)*N+I)
          ENDDO
          CALL MPI_SEND(dx,N,MPI_DOUBLE_PRECISION,C-1,1, &
                        MPI_COMM_WORLD,ierr)   
        ENDDO        
!       Perform one evaluation on Master    
        CALL PROBLEM_FUNCTION( FFF, GGG , XXX ) 
!       Collect results F & G
        DO C = 2, P
          CALL MPI_RECV(df,O,MPI_DOUBLE_PRECISION,C-1,2, &
                        MPI_COMM_WORLD,status,ierr)  
          CALL MPI_RECV(dg,M,MPI_DOUBLE_PRECISION,C-1,3, &
                        MPI_COMM_WORLD,status,ierr)  
!         Get F and G out of dummys df and dg
          DO I = 1,O
             FFF((C-1)*O+I) = df(I)
          ENDDO
          DO I = 1,M 
             GGG((C-1)*M+I) = dg(I)
          ENDDO          
        ENDDO  

!       Call MIDACO
        CALL MIDACO(P,O,N,NI,M,ME,XXX,FFF,GGG,XL,XU,IFLAG, &
                    ISTOP,PARAM,RW,LRW,IW,LIW,PF,LPF,KEY)            
!       Call MIDACO printing routine
        CALL MIDACO_PRINT(2,PRINTEVAL,SAVE2FILE,IFLAG,ISTOP,FFF,GGG,XXX, &
           XL,XU,O,N,NI,M,ME,RW,PF,MAXEVAL,MAXTIME,PARAM,P,0,KEY)     
        
        DO C = 2, P
           CALL MPI_SEND(ISTOP,1,MPI_INTEGER,C-1,4,MPI_COMM_WORLD,ierr)   
        ENDDO          
      ENDDO !~~~~~~~~~~~~~~~~~~~~End~of~reverse~communication~loop  

!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCC   MPI Evaluation Slave   CCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      ELSEIF (THREAD .GT. 0) THEN

        ISTOP = 0

        DO WHILE(ISTOP.LE.0)
            CALL MPI_RECV(EX,N,MPI_DOUBLE_PRECISION,0,1, &
                          MPI_COMM_WORLD,STATUS,IERR) 

            CALL PROBLEM_FUNCTION( EF, EG , EX )

            CALL MPI_SEND(EF,O,MPI_DOUBLE_PRECISION,0,2, &
                          MPI_COMM_WORLD,IERR)
            CALL MPI_SEND(EG,M,MPI_DOUBLE_PRECISION,0,3, &
                          MPI_COMM_WORLD,IERR)  
            CALL MPI_RECV(ISTOP,1,MPI_INTEGER,0,4, &
                          MPI_COMM_WORLD,STATUS,IERR)   
        ENDDO

      ENDIF
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 
      IF(ISTOP.GE.1) CALL MPI_FINALIZE(IERR)
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC 
      ! PRINT*," Solution F(1) = ", FFF(1)
      ! PRINT*," Solution G(1) = ", GGG(1)
      ! PRINT*," Solution X(1) = ", XXX(1)  
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC       
      END
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCC END OF MAIN CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC




!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCC   OPTIMIZATION PROBLEM   CCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      SUBROUTINE PROBLEM_FUNCTION(F,G,X)
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      IMPLICIT NONE
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      DOUBLE PRECISION F(*),G(*),X(*)
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      DOUBLE PRECISION DUMMY
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

!     Objective functions F(X)
      F(1) = (X(1)-1.0D0)**2 &
           + (X(2)-2.0D0)**2 &
           + (X(3)-3.0D0)**2 &
           + (X(4)-4.0D0)**2 &
           + 1.23456789D0

!     Equality constraints G(X) = 0 MUST COME FIRST in G(1:ME) 
      G(1) = X(1) - 1.0D0
!     Inequality constraints G(X) >= 0 MUST COME SECOND in G(ME+1:M)
      G(2) = X(2) - 1.333333333D0
      G(3) = X(3) - 2.666666666D0

!     CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!     Dummy calculation to simulate cpu-time intensive F(X) calculation
!     CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
      DUMMY = 0.01D0
      DO WHILE ( DUMMY .GT. 1.0D-8 )
         DUMMY = DUMMY - (1.0D-8*X(1))
      ENDDO
      F(1) = F(1) + DUMMY

      END
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCC END OF FILE CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
!CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC

