!  This file is an example of the Corana et al. simulated annealing algorithm
!  for multimodal and robust optimization as implemented and modified by
!  Goffe, Ferrier and Rogers.  Counting the above line
!  ABSTRACT as 1, the routine itself (SA), with its supplementary
!  routines, is on lines 232-990. A multimodal example from Judge et al.
!  (FCN) is on lines 150-231. The rest of this file (lines 1-149) is a
!  driver routine with values appropriate for the Judge example.  Thus, this
!  example is ready to run.

!  To understand the algorithm, the documentation for SA on lines 236-
!  484 should be read along with the parts of the paper that describe
!  simulated annealing. Then the following lines will then aid the user
!  in becomming proficient with this implementation of simulated annealing.

!  Learning to use SA:
!      Use the sample function from Judge with the following suggestions
!  to get a feel for how SA works. When you have done this, you should be
!  ready to use it on most any function with a fair amount of expertise.
!    1. Run the program as is to make sure it runs okay. Take a look at
!       the intermediate output and see how it optimizes as temperature
!       (T) falls.  Notice how the optimal point is reached and how
!       falling T reduces VM.
!    2. Look through the documentation to SA so the following makes a
!       bit of sense. In line with the paper, it should not be that hard
!       to figure out. The core of the algorithm is described on pp. 68-70
!       and on pp. 94-95. Also see Corana et al. pp. 264-9.
!    3. To see how it selects points and makes decisions about uphill and
!       downhill moves, set IPRINT = 3 (very detailed intermediate output)
!       and MAXEVL = 100 (only 100 function evaluations to limit output).
!    4. To see the importance of different temperatures, try starting
!       with a very low one (say T = 10E-5).  You will see (i) it never
!       escapes from the local optima (in annealing terminology, it
!       quenches) & (ii) the step length (VM) will be quite small.  This
!       is a key part of the algorithm: as temperature (T) falls, step
!       length does too. In a minor point here, note how VM is quickly
!       reset from its initial value. Thus, the input VM is not very
!       important.  This is all the more reason to examine VM once the
!       algorithm is underway.
!    5. To see the effect of different parameters and their effect on
!       the speed of the algorithm, try RT = .95 & RT = .1.  Notice the
!       vastly different speed for optimization. Also try NT = 20.  Note
!       that this sample function is quite easy to optimize, so it will
!       tolerate big changes in these parameters.  RT and NT are the
!       parameters one should adjust to modify the runtime of the
!       algorithm and its robustness.
!    6. Try constraining the algorithm with either LB or UB.


MODULE simulated_anneal

! ABSTRACT:
!   Simulated annealing is a global optimization method that distinguishes
!   between different local optima.  Starting from an initial point, the
!   algorithm takes a step and the function is evaluated. When minimizing a
!   function, any downhill step is accepted and the process repeats from this
!   new point. An uphill step may be accepted. Thus, it can escape from local
!   optima. This uphill decision is made by the Metropolis criteria. As the
!   optimization process proceeds, the length of the steps decline and the
!   algorithm closes in on the global optimum. Since the algorithm makes very
!   few assumptions regarding the function to be optimized, it is quite
!   robust with respect to non-quadratic surfaces. The degree of robustness
!   can be adjusted by the user. In fact, simulated annealing can be used as
!   a local optimizer for difficult functions.

!   This implementation of simulated annealing was used in "Global Optimizatio
!   of Statistical Functions with Simulated Annealing," Goffe, Ferrier and
!   Rogers, Journal of Econometrics, vol. 60, no. 1/2, Jan./Feb. 1994, pp.
!   65-100. Briefly, we found it competitive, if not superior, to multiple
!   restarts of conventional optimization routines for difficult optimization
!   problems.

!   For more information on this routine, contact its author:
!   Bill Goffe, bgoffe@whale.st.usm.edu

! This version in Fortran 90 has been prepared by Alan Miller.
! It is compatible with Lahey ELF90 compiler.
! N.B. The 3 last arguments have been removed from subroutine sa.   these
!      were work arrays and are now internal to the routine.
! e-mail:  amiller @ bigpond.net.au
! URL   :  http://users.bigpond.net.au/amiller

! Latest revision of Fortran 90 version - 3 August 1997

USE sep
USE fftw
USE tcai1_mod

IMPLICIT NONE

INTEGER, PARAMETER,private          :: dp = SELECTED_REAL_KIND(14, 60)
real(dp),public,save                :: pi
integer,public,save                 :: nw,nx,nz,nreal,ntot,pwval
integer,public,save                 :: dados,nwind,nodes,ngap
logical,public,save                 :: encz, gold


! The following variables were in COMMON /raset1/
REAL, SAVE    :: u(97), cc, cd, cm
INTEGER, SAVE :: i97, j97

CONTAINS
!==================================================================
SUBROUTINE sa(n, x, max, rt, eps, ns, nt, neps, maxevl, lb, ub, c, iprint,  &
              iseed1, iseed2, t, vm, xopt, fopt, nacc, nfcnev, nobds, ier)

!  Version: 3.2
!  Date: 1/22/94.
!  Differences compared to Version 2.0:
!     1. If a trial is out of bounds, a point is randomly selected
!        from LB(i) to UB(i). Unlike in version 2.0, this trial is
!        evaluated and is counted in acceptances and rejections.
!        All corresponding documentation was changed as well.
!  Differences compared to Version 3.0:
!     1. If VM(i) > (UB(i) - LB(i)), VM is set to UB(i) - LB(i).
!        The idea is that if T is high relative to LB & UB, most
!        points will be accepted, causing VM to rise. But, in this
!        situation, VM has little meaning; particularly if VM is
!        larger than the acceptable region. Setting VM to this size
!        still allows all parts of the allowable region to be selected.
!  Differences compared to Version 3.1:
!     1. Test made to see if the initial temperature is positive.
!     2. WRITE statements prettied up.
!     3. References to paper updated.

!  Synopsis:
!  This routine implements the continuous simulated annealing global
!  optimization algorithm described in Corana et al. article "Minimizing
!  Multimodal Functions of Continuous Variables with the Simulated Annealing
!  Algorithm" in the September 1987 (vol. 13, no. 3, pp. 262-280) issue of
!  the ACM Transactions on Mathematical Software.

!  A very quick (perhaps too quick) overview of SA:
!     SA tries to find the global optimum of an N dimensional function.
!  It moves both up and downhill and as the optimization process
!  proceeds, it focuses on the most promising area.
!     To start, it randomly chooses a trial point within the step length
!  VM (a vector of length N) of the user selected starting point. The
!  function is evaluated at this trial point and its value is compared
!  to its value at the initial point.
!     In a maximization problem, all uphill moves are accepted and the
!  algorithm continues from that trial point. Downhill moves may be
!  accepted; the decision is made by the Metropolis criteria. It uses T
!  (temperature) and the size of the downhill move in a probabilistic
!  manner. The smaller T and the size of the downhill move are, the more
!  likely that move will be accepted. If the trial is accepted, the
!  algorithm moves on from that point. If it is rejected, another point
!  is chosen instead for a trial evaluation.
!     Each element of VM periodically adjusted so that half of all
!  function evaluations in that direction are accepted.
!     A fall in T is imposed upon the system with the RT variable by
!  T(i+1) = RT*T(i) where i is the ith iteration. Thus, as T declines,
!  downhill moves are less likely to be accepted and the percentage of
!  rejections rise. Given the scheme for the selection for VM, VM falls.
!  Thus, as T declines, VM falls and SA focuses upon the most promising
!  area for optimization.

!  The importance of the parameter T:
!     The parameter T is crucial in using SA successfully. It influences
!  VM, the step length over which the algorithm searches for optima. For
!  a small intial T, the step length may be too small; thus not enough
!  of the function might be evaluated to find the global optima. The user
!  should carefully examine VM in the intermediate output (set IPRINT =
!  1) to make sure that VM is appropriate. The relationship between the
!  initial temperature and the resulting step length is function
!  dependent.
!     To determine the starting temperature that is consistent with
!  optimizing a function, it is worthwhile to run a trial run first. Set
!  RT = 1.5 and T = 1.0. With RT > 1.0, the temperature increases and VM
!  rises as well. Then select the T that produces a large enough VM.

!  For modifications to the algorithm and many details on its use,
!  (particularly for econometric applications) see Goffe, Ferrier
!  and Rogers, "Global Optimization of Statistical Functions with
!  Simulated Annealing," Journal of Econometrics, vol. 60, no. 1/2,
!  Jan./Feb. 1994, pp. 65-100.
!  For more information, contact
!              Bill Goffe
!              Department of Economics and International Business
!              University of Southern Mississippi
!              Hattiesburg, MS  39506-5072
!              (601) 266-4484 (office)
!              (601) 266-4920 (fax)
!              bgoffe@whale.st.usm.edu (Internet)

!  As far as possible, the parameters here have the same name as in
!  the description of the algorithm on pp. 266-8 of Corana et al.

!  In this description, SP is single precision, DP is double precision,
!  INT is integer, L is logical and (N) denotes an array of length n.
!  Thus, DP(N) denotes a double precision array of length n.

!  Input Parameters:
!    Note: The suggested values generally come from Corana et al. To
!          drastically reduce runtime, see Goffe et al., pp. 90-1 for
!          suggestions on choosing the appropriate RT and NT.
!    N - Number of variables in the function to be optimized. (INT)
!    X - The starting values for the variables of the function to be
!        optimized. (DP(N))
!    MAX - Denotes whether the function should be maximized or minimized.
!          A true value denotes maximization while a false value denotes
!          minimization.  Intermediate output (see IPRINT) takes this into
!          account. (L)
!    RT - The temperature reduction factor.  The value suggested by
!         Corana et al. is .85. See Goffe et al. for more advice. (DP)
!    EPS - Error tolerance for termination. If the final function
!          values from the last neps temperatures differ from the
!          corresponding value at the current temperature by less than
!          EPS and the final function value at the current temperature
!          differs from the current optimal function value by less than
!          EPS, execution terminates and IER = 0 is returned. (EP)
!    NS - Number of cycles.  After NS*N function evaluations, each element of
!         VM is adjusted so that approximately half of all function evaluations
!         are accepted.  The suggested value is 20. (INT)
!    NT - Number of iterations before temperature reduction. After
!         NT*NS*N function evaluations, temperature (T) is changed
!         by the factor RT.  Value suggested by Corana et al. is
!         MAX(100, 5*N).  See Goffe et al. for further advice. (INT)
!    NEPS - Number of final function values used to decide upon termi-
!           nation.  See EPS.  Suggested value is 4. (INT)
!    MAXEVL - The maximum number of function evaluations.  If it is
!             exceeded, IER = 1. (INT)
!    LB - The lower bound for the allowable solution variables. (DP(N))
!    UB - The upper bound for the allowable solution variables. (DP(N))
!         If the algorithm chooses X(I) .LT. LB(I) or X(I) .GT. UB(I),
!         I = 1, N, a point is from inside is randomly selected. This
!         This focuses the algorithm on the region inside UB and LB.
!         Unless the user wishes to concentrate the search to a particular
!         region, UB and LB should be set to very large positive
!         and negative values, respectively.  Note that the starting
!         vector X should be inside this region.  Also note that LB and
!         UB are fixed in position, while VM is centered on the last
!         accepted trial set of variables that optimizes the function.
!    C - Vector that controls the step length adjustment.  The suggested
!        value for all elements is 2.0. (DP(N))
!    IPRINT - controls printing inside SA. (INT)
!             Values: 0 - Nothing printed.
!                     1 - Function value for the starting value and
!                         summary results before each temperature
!                         reduction. This includes the optimal
!                         function value found so far, the total
!                         number of moves (broken up into uphill,
!                         downhill, accepted and rejected), the
!                         number of out of bounds trials, the
!                         number of new optima found at this
!                         temperature, the current optimal X and
!                         the step length VM. Note that there are
!                         N*NS*NT function evalutations before each
!                         temperature reduction. Finally, notice is
!                         is also given upon achieveing the termination
!                         criteria.
!                     2 - Each new step length (VM), the current optimal
!                         X (XOPT) and the current trial X (X). This
!                         gives the user some idea about how far X
!                         strays from XOPT as well as how VM is adapting
!                         to the function.
!                     3 - Each function evaluation, its acceptance or
!                         rejection and new optima. For many problems,
!                         this option will likely require a small tree
!                         if hard copy is used. This option is best
!                         used to learn about the algorithm. A small
!                         value for MAXEVL is thus recommended when
!                         using IPRINT = 3.
!             Suggested value: 1
!             Note: For a given value of IPRINT, the lower valued
!                   options (other than 0) are utilized.
!    ISEED1 - The first seed for the random number generator RANMAR.
!             0 <= ISEED1 <= 31328. (INT)
!    ISEED2 - The second seed for the random number generator RANMAR.
!             0 <= ISEED2 <= 30081. Different values for ISEED1
!             and ISEED2 will lead to an entirely different sequence
!             of trial points and decisions on downhill moves (when
!             maximizing).  See Goffe et al. on how this can be used
!             to test the results of SA. (INT)

!  Input/Output Parameters:
!    T - On input, the initial temperature. See Goffe et al. for advice.
!        On output, the final temperature. (DP)
!    VM - The step length vector. On input it should encompass the region of
!         interest given the starting value X.  For point X(I), the next
!         trial point is selected is from X(I) - VM(I)  to  X(I) + VM(I).
!         Since VM is adjusted so that about half of all points are accepted,
!         the input value is not very important (i.e. is the value is off,
!         SA adjusts VM to the correct value). (DP(N))

!  Output Parameters:
!    XOPT - The variables that optimize the function. (DP(N))
!    FOPT - The optimal value of the function. (DP)
!    NACC - The number of accepted function evaluations. (INT)
!    NFCNEV - The total number of function evaluations. In a minor
!             point, note that the first evaluation is not used in the
!             core of the algorithm; it simply initializes the
!             algorithm. (INT).
!    NOBDS - The total number of trial function evaluations that
!            would have been out of bounds of LB and UB. Note that
!            a trial point is randomly selected between LB and UB. (INT)
!    IER - The error return number. (INT)
!          Values: 0 - Normal return; termination criteria achieved.
!                  1 - Number of function evaluations (NFCNEV) is
!                      greater than the maximum number (MAXEVL).
!                  2 - The starting value (X) is not inside the
!                      bounds (LB and UB).
!                  3 - The initial temperature is not positive.
!                  99 - Should not be seen; only used internally.

!  Work arrays that must be dimensioned in the calling routine:
!       RWK1 (DP(NEPS))  (FSTAR in SA)
!       RWK2 (DP(N))     (XP    "  " )
!       IWK  (INT(N))    (NACP  "  " )
!  N.B. In the Fortran 90 version, these are automatic arrays.

!  Required Functions (included):
!    EXPREP - Replaces the function EXP to avoid under- and overflows.
!             It may have to be modified for non IBM-type main-
!             frames. (DP)
!    RMARIN - Initializes the random number generator RANMAR.
!    RANMAR - The actual random number generator. Note that
!             RMARIN must run first (SA does this). It produces uniform
!             random numbers on [0,1]. These routines are from
!             Usenet comp.lang.fortran. For a reference, see
!             "Toward a Universal Random Number Generator"
!             by George Marsaglia and Arif Zaman, Florida State
!             University Report: FSU-SCRI-87-50 (1987).
!             It was later modified by F. James and published in
!             "A Review of Pseudo-random Number Generators." For
!             further information, contact stuart@ads.com. These
!             routines are designed to be portable on any machine
!             with a 24-bit or more mantissa. I have found it produces
!             identical results on a IBM 3081 and a Cray Y-MP.

!  Required Subroutines (included):
!    PRTVEC - Prints vectors.
!    PRT1 ... PRT10 - Prints intermediate output.
!    OBJFCN - Function to be optimized. The form is
!            SUBROUTINE OBJFCN(N, X, F)
!            IMPLICIT NONE
!            INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
!            INTEGER, INTENT(IN)    :: N
!            REAL (dp), INTENT(IN)  :: X(N)
!            REAL (dp), INTENT(OUT) :: F
!            ...
!            function code with F = F(X)
!            ...
!            RETURN
!            END
!  Note: This is the same form used in the multivariable
!        minimization algorithms in the IMSL edition 10 library.

!  Machine Specific Features:
!    1. EXPREP may have to be modified if used on non-IBM type main-
!       frames. Watch for under- and overflows in EXPREP.
!    2. Some FORMAT statements use G25.18; this may be excessive for
!       some machines.
!    3. RMARIN and RANMAR are designed to be protable; they should not
!       cause any problems.

!  Type all external variables.
REAL (dp), INTENT(IN)     :: lb(:), ub(:), c(:), eps, rt
REAL (dp), INTENT(IN OUT) :: x(:), t, vm(:)
REAL (dp), INTENT(OUT)    :: xopt(:), fopt
INTEGER, INTENT(IN)       :: n, ns, nt, neps, maxevl, iprint, iseed1, iseed2
INTEGER, INTENT(OUT)      :: nacc, nfcnev, nobds, ier
LOGICAL, INTENT(IN)       :: max

!  Type all internal variables.
REAL (dp) :: f, fp, p, pp, ratio, xp(n), fstar(neps)
INTEGER   :: nup, ndown, nrej, nnew, lnobds, h, i, j, m, nacp(n)
LOGICAL   :: quit

!INTERFACE
!  SUBROUTINE objfcn(n, theta, h)
!    IMPLICIT NONE
!    INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
!    INTEGER, INTENT(IN)    :: n
!    REAL (dp), INTENT(IN)  :: theta(:)
!    REAL (dp), INTENT(OUT) :: h
!  END SUBROUTINE objfcn
!END INTERFACE

!  Initialize the random number generator RANMAR.
CALL rmarin(iseed1, iseed2)

!  Set initial values.
nacc = 0
nobds = 0
nfcnev = 0
ier = 99

xopt = x
nacp = 0
fstar = 1.0D+20

!  If the initial temperature is not positive, notify the user and
!  return to the calling routine.
IF (t <= 0.0) THEN
  WRITE(*,'(/, "  THE INITIAL TEMPERATURE IS NOT POSITIVE. "/,  &
        &    "  reset the variable t. "/)')
  ier = 3
  RETURN
END IF

!  If the initial value is out of bounds, notify the user and return
!  to the calling routine.
DO i = 1, n
  IF ((x(i) > ub(i)) .OR. (x(i) < lb(i))) THEN
    CALL prt1()
    ier = 2
    RETURN
  END IF
END DO

!  Evaluate the function with input X and return value as F.
!Call objfcn2(n, x, f)
call objfcn5(n, x, f)

!  If the function is to be minimized, switch the sign of the function.
!  Note that all intermediate and final output switches the sign back
!  to eliminate any possible confusion for the user.
IF(.NOT. max) f = -f
nfcnev = nfcnev + 1
fopt = f
fstar(1) = f
IF(iprint >= 1) CALL prt2(max, n, x, f)

!  Start the main loop. Note that it terminates if (i) the algorithm
!  succesfully optimizes the function or (ii) there are too many
!  function evaluations (more than MAXEVL).
100 nup = 0
nrej = 0
nnew = 0
ndown = 0
lnobds = 0

DO m = 1, nt
  DO j = 1, ns
    DO h = 1, n
      
!  Generate XP, the trial value of X. Note use of VM to choose XP.
      DO i = 1, n
        IF (i == h) THEN
          xp(i) = x(i) + (ranmar()*2. - 1.) * vm(i)
        ELSE
          xp(i) = x(i)
        END IF
        
!  If XP is out of bounds, select a point in bounds for the trial.
        IF((xp(i) < lb(i)) .OR. (xp(i) > ub(i))) THEN
          xp(i) = lb(i) + (ub(i) - lb(i))*ranmar()
          lnobds = lnobds + 1
          nobds = nobds + 1
          IF(iprint >= 3) CALL prt3(max, n, xp, x, f)
        END IF
      END DO
      
!  Evaluate the function with the trial point XP and return as FP.
!      Call objfcn2(n, xp, fp)
      call objfcn5(n, xp, fp)
      IF(.NOT. max) fp = -fp
      nfcnev = nfcnev + 1
      IF(iprint >= 3) CALL prt4(max, n, xp, x, fp, f)
      
!  If too many function evaluations occur, terminate the algorithm.
      IF(nfcnev >= maxevl) THEN
        CALL prt5()
        IF (.NOT. max) fopt = -fopt
        ier = 1
        RETURN
      END IF
      
!  Accept the new point if the function value increases.
      IF(fp >= f) THEN
        IF(iprint >= 3) THEN
          WRITE(*,'("  POINT ACCEPTED")')
        END IF
        x(1:n) = xp(1:n)
        f = fp
        nacc = nacc + 1
        nacp(h) = nacp(h) + 1
        nup = nup + 1
        
!  If greater than any other point, record as new optimum.
        IF (fp > fopt) THEN
          IF(iprint >= 3) THEN
            WRITE(*,'("  NEW OPTIMUM")')
          END IF
          xopt(1:n) = xp(1:n)
          fopt = fp
          nnew = nnew + 1
        END IF
        
!  If the point is lower, use the Metropolis criteria to decide on
!  acceptance or rejection.
      ELSE
        p = exprep((fp - f)/t)
        pp = ranmar()
        IF (pp < p) THEN
          IF(iprint >= 3) CALL prt6(max)
          x(1:n) = xp(1:n)
          f = fp
          nacc = nacc + 1
          nacp(h) = nacp(h) + 1
          ndown = ndown + 1
        ELSE
          nrej = nrej + 1
          IF(iprint >= 3) CALL prt7(max)
        END IF
      END IF
      
    END DO
  END DO
  
!  Adjust VM so that approximately half of all evaluations are accepted.
  DO i = 1, n
    ratio = DBLE(nacp(i)) /DBLE(ns)
    IF (ratio > .6) THEN
      vm(i) = vm(i)*(1. + c(i)*(ratio - .6)/.4)
    ELSE IF (ratio < .4) THEN
      vm(i) = vm(i)/(1. + c(i)*((.4 - ratio)/.4))
    END IF
    IF (vm(i) > (ub(i)-lb(i))) THEN
      vm(i) = ub(i) - lb(i)
    END IF
  END DO
  
  IF(iprint >= 2) THEN
    CALL prt8(n, vm, xopt, x)
  END IF
  
  nacp(1:n) = 0
  
END DO

IF(iprint >= 1) THEN
  CALL prt9(max,n,t,xopt,vm,fopt,nup,ndown,nrej,lnobds,nnew)
END IF

!  Check termination criteria.
quit = .false.
fstar(1) = f
IF ((fopt - fstar(1)) <= eps) quit = .true.
DO i = 1, neps
  IF (ABS(f - fstar(i)) > eps) quit = .false.
END DO

!  Terminate SA if appropriate.
IF (quit) THEN
  x(1:n) = xopt(1:n)
  ier = 0
  IF (.NOT. max) fopt = -fopt
  IF(iprint >= 1) CALL prt10()
  RETURN
END IF

!  If termination criteria is not met, prepare for another loop.
t = rt*t
DO i = neps, 2, -1
  fstar(i) = fstar(i-1)
END DO
f = fopt
x(1:n) = xopt(1:n)

!  Loop again.
GO TO 100

END SUBROUTINE sa
!==================================================================
FUNCTION exprep(rdum) RESULT(fn_val)
!  This function replaces exp to avoid under- and overflows and is
!  designed for IBM 370 type machines. It may be necessary to modify
!  it for other machines. Note that the maximum and minimum values of
!  EXPREP are such that they has no effect on the algorithm.

REAL (dp), INTENT(IN) :: rdum
REAL (dp)             :: fn_val

!IF (rdum > 174._dp) THEN
IF (rdum > 88._dp) THEN
  fn_val = 3.69D+75
!ELSE IF (rdum < -180.+dp) THEN
ELSE IF (rdum < -87.+dp) THEN
  fn_val = 0.0_dp
ELSE
  fn_val = EXP(rdum)
END IF

RETURN
END FUNCTION exprep
!==================================================================
SUBROUTINE rmarin(ij, kl)
!  This subroutine and the next function generate random numbers. See
!  the comments for SA for more information. The only changes from the
!  orginal code is that (1) the test to make sure that RMARIN runs first
!  was taken out since SA assures that this is done (this test did not
!  compile under IBMs VS Fortran) and (2) typing ivec as integer was
!  taken out since ivec is not used. With these exceptions, all following
!  lines are original.

! This is the initialization routine for the random number generator
!     RANMAR()
! NOTE: The seed variables can have values between:    0 <= IJ <= 31328
!                                                      0 <= KL <= 30081

INTEGER, INTENT(IN) :: ij, kl

INTEGER :: i, j, k, l, ii, jj, m
REAL    :: s, t

IF( ij < 0  .OR.  ij > 31328  .OR. kl < 0  .OR.  kl > 30081 ) THEN
  WRITE(*, '(A)') ' The first random number seed must have a value ',  &
               'between 0 AND 31328'
  WRITE(*, '(A)') ' The second seed must have a value between 0 and 30081'
  STOP
END IF
i = MOD(ij/177, 177) + 2
j = MOD(ij    , 177) + 2
k = MOD(kl/169, 178) + 1
l = MOD(kl,     169)
DO ii = 1, 97
  s = 0.0
  t = 0.5
  DO jj = 1, 24
    m = MOD(MOD(i*j, 179)*k, 179)
    i = j
    j = k
    k = m
    l = MOD(53*l+1, 169)
    IF (MOD(l*m, 64) >= 32) THEN
      s = s + t
    END IF
    t = 0.5 * t
  END DO
  u(ii) = s
END DO
cc = 362436.0 / 16777216.0
cd = 7654321.0 / 16777216.0
cm = 16777213.0 /16777216.0
i97 = 97
j97 = 33
RETURN
END SUBROUTINE rmarin
!==================================================================
FUNCTION ranmar() RESULT(fn_val)
REAL :: fn_val

! Local variable
REAL :: uni

uni = u(i97) - u(j97)
IF( uni < 0.0 ) uni = uni + 1.0
u(i97) = uni
i97 = i97 - 1
IF(i97 == 0) i97 = 97
j97 = j97 - 1
IF(j97 == 0) j97 = 97
cc = cc - cd
IF( cc < 0.0 ) cc = cc + cm
uni = uni - cc
IF( uni < 0.0 ) uni = uni + 1.0
fn_val = uni

RETURN
END FUNCTION ranmar
!==================================================================
SUBROUTINE prt1()
!  This subroutine prints intermediate output, as does PRT2 through
!  PRT10. Note that if SA is minimizing the function, the sign of the
!  function value and the directions (up/down) are reversed in all
!  output to correspond with the actual function optimization. This
!  correction is because SA was written to maximize functions and
!  it minimizes by maximizing the negative a function.

WRITE(*, '(/, "  THE STARTING VALUE (X) IS OUTSIDE THE BOUNDS "/,  &
      &     "  (lb AND ub). execution terminated without any"/,  &
      &     "  optimization. respecify x, ub OR lb so that  "/,  &
      &     "  lb(i) < x(i) < ub(i), i = 1, n. "/)')

RETURN
END SUBROUTINE prt1
!==================================================================
SUBROUTINE prt2(max, n, x, f)

REAL (dp), INTENT(IN) ::  x(:), f
INTEGER, INTENT(IN)   ::  n
LOGICAL, INTENT(IN)   ::  max

WRITE(*, '("  ")')
!CALL prtvec(x,n,'INITIAL X')
IF (max) THEN
  WRITE(*, '("  INITIAL F: ",/, G25.18)') f
ELSE
  WRITE(*, '("  INITIAL F: ",/, G25.18)') -f
END IF

RETURN
END SUBROUTINE prt2
!==================================================================
SUBROUTINE prt3(max, n, xp, x, f)

REAL (dp), INTENT(IN) ::  xp(:), x(:), f
INTEGER, INTENT(IN)   ::  n
LOGICAL, INTENT(IN)   ::  max

WRITE(*, '("  ")')
!CALL prtvec(x, n, 'CURRENT X')
IF (max) THEN
  WRITE(*, '("  CURRENT F: ", G25.18)') f
ELSE
  WRITE(*, '("  CURRENT F: ", G25.18)') -f
END IF
!CALL prtvec(xp, n, 'TRIAL X')
WRITE(*, '("  POINT REJECTED SINCE OUT OF BOUNDS")')

RETURN
END SUBROUTINE prt3
!==================================================================
SUBROUTINE prt4(max, n, xp, x, fp, f)

REAL (dp), INTENT(IN) ::  xp(:), x(:), fp, f
INTEGER, INTENT(IN)   ::  n
LOGICAL, INTENT(IN)   ::  max

WRITE(*,'("  ")')
!CALL prtvec(x,n,'CURRENT X')
IF (max) THEN
  WRITE(*,'("  CURRENT F: ",G25.18)') f
!  CALL prtvec(xp,n,'TRIAL X')
  WRITE(*,'("  RESULTING F: ",G25.18)') fp
ELSE
  WRITE(*,'("  CURRENT F: ",G25.18)') -f
!  CALL prtvec(xp,n,'TRIAL X')
  WRITE(*,'("  RESULTING F: ",G25.18)') -fp
END IF

RETURN
END SUBROUTINE prt4
!==================================================================
SUBROUTINE prt5()

WRITE(*, '(/, "  TOO MANY FUNCTION EVALUATIONS; CONSIDER "/,  &
      &     "  increasing maxevl OR eps, OR decreasing "/,  &
      &     "  nt OR rt. these results are likely TO be "/, "  poor.",/)')

RETURN
END SUBROUTINE prt5
!==================================================================
SUBROUTINE prt6(max)
LOGICAL, INTENT(IN) ::  max

IF (max) THEN
  WRITE(*,'("  THOUGH LOWER, POINT ACCEPTED")')
ELSE
  WRITE(*,'("  THOUGH HIGHER, POINT ACCEPTED")')
END IF

RETURN
END SUBROUTINE prt6
!==================================================================
SUBROUTINE prt7(max)
LOGICAL, INTENT(IN) :: max

IF (max) THEN
  WRITE(*,'("  LOWER POINT REJECTED")')
ELSE
  WRITE(*,'("  HIGHER POINT REJECTED")')
END IF

RETURN
END SUBROUTINE prt7
!==================================================================
SUBROUTINE prt8(n, vm, xopt, x)

REAL (dp), INTENT(IN) :: vm(:), xopt(:), x(:)
INTEGER, INTENT(IN)   :: n

WRITE(*,'(/, " intermediate results after step length adjustment", /)')
!CALL prtvec(vm, n, 'NEW STEP LENGTH (VM)')
!CALL prtvec(xopt, n, 'CURRENT OPTIMAL X')
!CALL prtvec(x, n, 'CURRENT X')
WRITE(*,'(" ")')

RETURN
END SUBROUTINE prt8
!==================================================================
SUBROUTINE prt9(max, n, t, xopt, vm, fopt, nup, ndown, nrej, lnobds, nnew)

REAL (dp), INTENT(IN) :: xopt(:), vm(:), t, fopt
INTEGER, INTENT(IN)   :: n, nup, ndown, nrej, lnobds, nnew
LOGICAL, INTENT(IN)   :: max

! Local variable
INTEGER :: totmov

totmov = nup + ndown + nrej

WRITE(*,'(/," intermediate results before next temperature reduction",/)')
WRITE(*,'("  CURRENT TEMPERATURE:            ",G12.5)') t
IF (max) THEN
  WRITE(*, '("  MAX FUNCTION VALUE SO FAR:  ",G25.18)') fopt
  WRITE(*, '("  TOTAL MOVES:                ",I8)') totmov
  WRITE(*, '("     UPHILL:                  ",I8)') nup
  WRITE(*, '("     ACCEPTED DOWNHILL:       ",I8)') ndown
  WRITE(*, '("     REJECTED DOWNHILL:       ",I8)') nrej
  WRITE(*, '("  OUT OF BOUNDS TRIALS:       ",I8)') lnobds
  WRITE(*, '("  NEW MAXIMA THIS TEMPERATURE:",I8)') nnew
ELSE
  WRITE(*, '("  MIN FUNCTION VALUE SO FAR:  ",G25.18)') -fopt
  WRITE(*, '("  TOTAL MOVES:                ",I8)') totmov
  WRITE(*, '("     DOWNHILL:                ",I8)')  nup
  WRITE(*, '("     ACCEPTED UPHILL:         ",I8)')  ndown
  WRITE(*, '("     REJECTED UPHILL:         ",I8)')  nrej
  WRITE(*, '("  TRIALS OUT OF BOUNDS:       ",I8)')  lnobds
  WRITE(*, '("  NEW MINIMA THIS TEMPERATURE:",I8)')  nnew
END IF
!CALL prtvec(xopt, n, 'CURRENT OPTIMAL X')
!CALL prtvec(vm, n, 'STEP LENGTH (VM)')
WRITE(*, '(" ")')

RETURN
END SUBROUTINE prt9
!==================================================================
SUBROUTINE prt10()

WRITE(*, '(/, "  SA ACHIEVED TERMINATION CRITERIA. IER = 0. ",/)')

RETURN
END SUBROUTINE prt10
!==================================================================
SUBROUTINE prtvec(vector, ncols, name)
!  This subroutine prints the double precision vector named VECTOR.
!  Elements 1 thru NCOLS will be printed. NAME is a character variable
!  that describes VECTOR. Note that if NAME is given in the call to
!  PRTVEC, it must be enclosed in quotes. If there are more than 10
!  elements in VECTOR, 10 elements will be printed on each line.

INTEGER, INTENT(IN)           :: ncols
REAL (dp), INTENT(IN)         :: vector(ncols)
CHARACTER (LEN=*), INTENT(IN) :: name

INTEGER :: i, lines, ll

WRITE(*,1001) NAME

IF (ncols > 10) THEN
  lines = INT(ncols/10.)
  
  DO i = 1, lines
    ll = 10*(i - 1)
    WRITE(*,1000) vector(1+ll:10+ll)
  END DO
  
  WRITE(*,1000) vector(11+ll:ncols)
ELSE
  WRITE(*,1000) vector(1:ncols)
END IF

1000 FORMAT( 10(g12.5, ' '))
1001 FORMAT(/, 25(' '), a)

RETURN
END SUBROUTINE prtvec
!==================================================================
SUBROUTINE objfcn(n, x, f)
!
IMPLICIT NONE
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
INTEGER, INTENT(IN)    :: n
REAL (dp), INTENT(IN)  :: x(:)
REAL (dp), INTENT(OUT) :: f
! Local variables
integer                :: i,j,mini,maxi,nh,nodes,inode
real (dp),allocatable  :: obf(:)
integer, external      :: omp_get_thread_num,omp_get_num_threads

!$OMP PARALLEL
nodes = omp_get_num_threads()
!$OMP END PARALLEL

allocate(obf(nodes))
obf=0.0_dp
f = 0.0_dp
nh=11
!$OMP PARALLEL DO PRIVATE (inode,&
                               j,&
                            mini,&
                            maxi,&
                               i) schedule(dynamic,1)  num_threads(nodes) 
                               
do j = 1, nx*nz
   inode = omp_get_thread_num()+1
   obf(inode) = obf(inode) + (sum(x((j-1)*nw+1:j*nw) * x((j-1)*nw+1:j*nw)) - nw*.333)*&
                             (sum(x((j-1)*nw+1:j*nw) * x((j-1)*nw+1:j*nw)) - nw*.333)
!   mini=(max(1,int(j/nz)+1-nh)-1)*nz+1
!write(*, '(2i6)') j,inode
   mini=(max(1,int(j/nz)+1)-1)*nz+1
   maxi=(min(nx,int(j/nz)+1+nh)-1)*nz
   do i = mini,maxi
      if (i.ne.j) then
        obf(inode) = obf(inode) + sum(x((i-1)*nw+1:i*nw) * x((j-1)*nw+1:j*nw))*&
                                  sum(x((i-1)*nw+1:i*nw) * x((j-1)*nw+1:j*nw))
      end if
   end do
end do
!$OMP END PARALLEL DO

f=sum(obf)

write(*, '("  The obj.fcn: f = ",g25.8)') f
RETURN
END SUBROUTINE objfcn
!==================================================================
SUBROUTINE objfcn1(n, x, f)
!
IMPLICIT NONE
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)

INTEGER, INTENT(IN)    :: n
REAL (dp), INTENT(IN)  :: x(:)
REAL (dp), INTENT(OUT) :: f

! Local variables
!REAL (dp),allocatable :: data(:)
integer                :: i,j,mini,maxi,nh
complex                :: tfld(nw),temp1(nw),temp2(nw),temp3(nw),temp4(nw)
real                   :: spike(nw)

!allocate(data(2*nwind+1))
!call gendataw(data)

f = 0.0_dp
tfld=0.0;temp1=0.0;temp2=0.0;temp3=0.0
do j = 1, nx*nz
   write(0,*) j," from ",nx*nz
   spike=0.
   tfld=cmplx(x((j-1)*nw+1:j*nw),0.)
   call owfftexe(tfld)
   temp1=tfld/sqrt(1.*nw)
   temp3=temp1*conjg(temp1);
   tfld=temp3
   call owifftexe(tfld)
   temp3=tfld/sqrt(1.*nw)
   temp3=abs(temp3)/maxval(abs(temp3))
   where (real(temp3) .eq. 1.)
      spike=1.
   end where
   f = f + dble(sum((temp3-spike)**2))
   do i = 1, nx*nz
      if (i.ne.j) then
         tfld=cmplx(x((i-1)*nw+1:i*nw),0.)
         call owfftexe(tfld)
         temp2=tfld/sqrt(1.*nw)
         temp3=temp1*conjg(temp2)
         tfld=temp3
         call owifftexe(tfld)
         temp3=tfld/sqrt(1.*nw)
         temp3=abs(temp3)/maxval(abs(temp3))
         f = f + dble(sum((temp3**2)))
      end if
   end do
end do
write(*, '("  The obj.fcn: f = ",g25.8)') f
!deallocate(data)
call owfftwdestroy()
RETURN
END SUBROUTINE objfcn1
!==================================================================
SUBROUTINE objfcn2(n, x, f)
!
IMPLICIT NONE
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
INTEGER, INTENT(IN)    :: n
REAL (dp), INTENT(IN)  :: x(:)
REAL (dp), INTENT(OUT) :: f
! Local variables
integer                :: i,j,mini,maxi,nh,nodes,inode,stat
real (dp),allocatable  :: obf(:)
real (dp),allocatable  :: bb(:,:)
real (dp),allocatable  :: xx(:,:),spike(:,:)
integer, external      :: omp_get_thread_num,omp_get_num_threads

!$OMP PARALLEL
nodes = omp_get_num_threads()
!$OMP END PARALLEL

allocate(obf(nodes),bb(nw,nodes),xx(2*nw-1,nodes),spike(2*nw-1,nodes))
obf=0.0_dp
f = 0.0_dp
nh=11
!$OMP PARALLEL DO PRIVATE (inode,&
                               j,&
                            mini,&
                            maxi,&
                               i) schedule(dynamic,1)  num_threads(nodes) 
                               
do j = 1, nx*nz
   inode = omp_get_thread_num()+1
   bb(:,inode)=x((j-1)*nw+1:j*nw)
   call tcai1_lop2 ( xx(:,inode), x((j-1)*nw+1:j*nw),bb(:,inode))
   xx(:,inode)=xx(:,inode)/maxval(abs(xx(:,inode)))
   spike(:,inode)=0.0
   where (xx(:,inode) .eq. 1.)
      spike(:,inode)=1.
   end where
   obf(inode) = obf(inode) + sum((xx(:,inode) - spike(:,inode))**2)
!   mini=(max(1,int(j/nz)+1-nh)-1)*nz+1
!write(*, '(2i6)') j,inode
   mini=(max(1,int(j/nz)+1)-1)*nz+1
   maxi=(min(nx,int(j/nz)+1+nh)-1)*nz
   do i = mini,maxi
      if (i.ne.j) then
         call tcai1_lop2 ( xx(:,inode), x((i-1)*nw+1:i*nw),bb(:,inode))
         xx(:,inode)=xx(:,inode)/maxval(abs(xx(:,inode)))
         obf(inode) = obf(inode) + sum(xx(:,inode)**2)
      end if
   end do
end do
!$OMP END PARALLEL DO

f=sum(obf)

write(*, '("  The obj.fcn: f = ",g25.8)') f
RETURN
END SUBROUTINE objfcn2
!==================================================================
SUBROUTINE objfcn4(n, x, f)
!
IMPLICIT NONE
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
INTEGER, INTENT(IN)    :: n
REAL (dp), INTENT(IN)  :: x(:)
REAL (dp), INTENT(OUT) :: f
! Local variables
integer                :: i,j,nodes,inode,nt
real (dp),allocatable  :: obf(:)
real (dp),allocatable  :: bb(:,:)
real (dp),allocatable  :: xx(:,:),spike(:,:)
integer		   :: mm(1)
integer, external      :: omp_get_thread_num,omp_get_num_threads

!$OMP PARALLEL
nodes = omp_get_num_threads()
!$OMP END PARALLEL
if (gold) then 
   nt=2*nw-1
else
   nt=nw
end if

allocate(obf(nodes),bb(nt,nodes),xx(2*nt-1,nodes),spike(2*nt-1,nodes))! ,mm(nodes))
obf=0.0_dp
f = 0.0_dp

!$OMP PARALLEL DO PRIVATE (inode,&
                              mm,&
                               j,&
                               i) schedule(dynamic,1) firstprivate(nt) num_threads(nodes) 
                               
do j = 1, nx*nz
   inode = omp_get_thread_num()+1
   bb(:,inode)=x((j-1)*(nt)+1:j*(nt))
   call tcai1_lop2 ( xx(:,inode), x((j-1)*(nt)+1:j*(nt)),x((j-1)*(nt)+1:j*(nt)))!bb(:,inode))
!   mm(inode)=maxval(abs(xx(:,inode)))
   mm=maxloc(abs(xx(:,inode)))
write(0,*) inode,mm
!   xx(:,inode)=xx(:,inode)/mm(inode)
   spike(:,inode)=0.0
   spike(mm,inode)=xx(mm,inode)
!   where (xx(:,inode) .eq. 1.)
!      spike(:,inode)=1.
!   end where
!   where ((abs(xx(:,inode))).eq.mm(inode))
!      spike(:,inode)=xx(:,inode)
!   end where
   obf(inode) = obf(inode) + sum((xx(:,inode) - spike(:,inode))**2)
   do i = 1, nx*nz
      if (i.ne.j) then
         call tcai1_lop2 ( xx(:,inode), x((i-1)*(nt)+1:i*(nt)),bb(:,inode))
!         xx(:,inode)=xx(:,inode)/mm(inode)
         obf(inode) = obf(inode) + sum(xx(:,inode)**2)
      end if
   end do
end do
!$OMP END PARALLEL DO

f=sum(obf)
deallocate(obf,bb,xx,spike)!,mm)
write(*, '("  The obj.fcn: f = ",g25.8)') f
RETURN
END SUBROUTINE objfcn4
!==================================================================
SUBROUTINE objfcn5(n, x, f)
!
IMPLICIT NONE
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
INTEGER, INTENT(IN)    :: n
REAL (dp), INTENT(IN)  :: x(:)
REAL (dp), INTENT(OUT) :: f
! Local variables
integer                :: i,j,nodes,inode,nt
real (dp),allocatable  :: obf(:),mm(:)!,spike(:,:)
integer		   :: nn(1)
complex,allocatable    :: tfld(:,:),temp0(:,:),temp1(:,:),temp2(:,:),spike(:,:)
integer, external      :: omp_get_thread_num,omp_get_num_threads

!$OMP PARALLEL
nodes = omp_get_num_threads()
!$OMP END PARALLEL
! Setting FFTW plans

obf=0.0_dp
f = 0.0_dp

if (gold) then
   nt=2*nw-1
else
   nt=nw
end if

allocate(obf(nodes),tfld(nt,nodes),temp0(nt,nodes),temp1(nt,nodes),temp2(nt,nodes),spike(nt,nodes),mm(nodes))
call owfftwpl(tfld,nodes)

!$OMP PARALLEL DO PRIVATE (inode,&
                              nn,&
                               j,&
                               i) schedule(dynamic,1)  firstprivate(nt) num_threads(nodes) 
                               
do j = 1, nx*nz
   inode = omp_get_thread_num()+1
   temp1(:,inode)=0.0;temp0(:,inode)=0.0;tfld(:,inode)=0.0;spike(:,inode)=0.0
   tfld(:,inode)=cmplx(x((j-1)*(nt)+1:j*(nt)),0.)
   call owfftexepl(tfld(:,inode),inode)
   temp0(:,inode)=tfld(:,inode)/sqrt(1.*(nt))
   temp1(:,inode)=temp0(:,inode)*conjg(temp0(:,inode));
   tfld(:,inode)=temp1(:,inode)
   call owifftexepl(tfld(:,inode),inode)
   temp1(:,inode)=tfld(:,inode)/sqrt(1.*(nt))
   nn=maxloc(abs(temp1(:,inode)))
   mm(inode)=dble(maxval(abs(temp1(:,inode))))
   temp1(:,inode)=temp1(:,inode)/mm(inode)
   temp1(nn,inode)=0.
   obf(inode) = obf(inode) + dble(sum(abs(temp1(:,inode))))!**2)
   do i = 1, nx*nz
      if (i.ne.j) then
         temp1(:,inode)=0.0;tfld(:,inode)=0.0
         tfld(:,inode)=cmplx(x((i-1)*(nt)+1:i*(nt)),0.)
         call owfftexepl(tfld(:,inode),inode)
         temp1(:,inode)=tfld(:,inode)/sqrt(1.*(nt))
         temp1(:,inode)=temp1(:,inode)*conjg(temp0(:,inode));
         tfld(:,inode)=temp1(:,inode)
         call owifftexepl(tfld(:,inode),inode)
         temp1(:,inode)=tfld(:,inode)/sqrt(1.*(nt))/mm(inode)
         obf(inode) = obf(inode) + dble(sum(abs(temp1(:,inode))))!**2)
      end if
   end do
end do
!$OMP END PARALLEL DO
f=sum(obf)
write(0,*) f
deallocate(obf,tfld,temp0,temp1,temp2,spike)
call owfftwdestroypl()
write(*, '("  The obj.fcn: f = ",g25.8)') f
RETURN
END SUBROUTINE objfcn5
!==================================================================
SUBROUTINE parameters()
integer	:: nnw
 call from_param("nw",nw,20)
 call from_param("nx",nx,50)
 call from_param("nz",nz,1)
 call from_param("ngap",ngap,1)
 call from_param("nreal",nreal,1)
 call from_param("nwind",nwind,7)
 call from_param("dados",dados,1)
 call from_param("nodes",nodes,1)
 call from_param("gold",gold,.false.)
 call from_param("encz",encz,.false.)
 if (gold) then
    pwval=2
    nnw=nw
    do while (nnw.ne.2)
       nnw=nnw/2
       pwval=pwval+1
    end do
 end if

 if (gold) then
    ntot=(2*nw-1)*nz*nx*nreal
 else
    ntot=nz*nx*nreal
 end if
 pi=4.*datan(1._dp)

RETURN
END SUBROUTINE parameters
!==================================================================
subroutine io(m,L)
integer		:: L
real		:: m(:)

if (L==0) then
  if (gold.and.exist_file("x0")) then
     call to_history("n1",2*nw-1,"x0");call to_history("d1",1.,"x0");call to_history("o1",1.,"x0");
     call to_history("n2",nz,"x0");call to_history("d2",1.,"x0");call to_history("o2",1.,"x0");
     call to_history("n3",nx,"x0");call to_history("d3",1.,"x0");call to_history("o3",1.,"x0");
     call to_history("n4",nreal,"x0");call to_history("d4",1.,"x0");call to_history("o4",1.,"x0");
     call to_history("label1","freq","x0");call to_history("label2","z","x0");
     call to_history("label3","x","x0");call to_history("label4","realization","x0");
     call srite("x0",m,4*(2*nw-1)*nx*nz*nreal)
  else
     call to_history("n1",nw,"x0");call to_history("d1",1.,"x0");call to_history("o1",1.,"x0");
     call to_history("n2",nz,"x0");call to_history("d2",1.,"x0");call to_history("o2",1.,"x0");
     call to_history("n3",nx,"x0");call to_history("d3",1.,"x0");call to_history("o3",1.,"x0");
     call to_history("n4",nreal,"x0");call to_history("d4",1.,"x0");call to_history("o4",1.,"x0");
     call to_history("label1","freq","x0");call to_history("label2","z","x0");
     call to_history("label3","x","x0");call to_history("label4","realization","x0");
     call srite("x0",m,4*nw*nx*nz*nreal)
  end if
else
  if (gold.and.exist_file("xf")) then
     call to_history("n1",2*nw-1,"xf");call to_history("d1",1.,"xf");call to_history("o1",1.,"xf");
     call to_history("n2",nz,"xf");call to_history("d2",1.,"xf");call to_history("o2",1.,"xf");
     call to_history("n3",nx,"xf");call to_history("d3",1.,"xf");call to_history("o3",1.,"xf");
     call to_history("n4",nreal,"xf");call to_history("d4",1.,"xf");call to_history("o4",1.,"xf");
     call to_history("label1","freq","xf");call to_history("label2","z","xf");
     call to_history("label3","x","xf");call to_history("label4","realization","xf");
     call srite("xf",m,4*(2*nw-1)*nx*nz*nreal)
  else if (not(gold)) then
     call to_history("n1",nw);call to_history("d1",1.);call to_history("o1",1.);
     call to_history("n2",nz);call to_history("d2",1.);call to_history("o2",1.);
     call to_history("n3",nx);call to_history("d3",1.);call to_history("o3",1.);
     call to_history("n4",nreal);call to_history("d4",1.);call to_history("o4",1.);
     call to_history("label1","freq");call to_history("label2","z");
     call to_history("label3","x");call to_history("label4","realization");
     call srite("out",m,4*nw*nx*nz*nreal)
  end if
end if
end subroutine
!==================================================================
subroutine outcorr(x,L)
INTEGER, PARAMETER     :: dp = SELECTED_REAL_KIND(14, 60)
real (dp)		   :: x(:)
complex,allocatable	   :: tfld(:),fun1(:)
real,allocatable	   :: correl(:,:)
integer		   :: ixs,L

   if (gold) then
      if (allocated(tfld)) deallocate(tfld);allocate(tfld(2*nw-1))
      call owfftw(tfld)
      allocate(fun1(2*nw-1))
      allocate(correl(nz*nx,2*nw-1))
      tfld=cmplx(x(1:2*nw-1),0.)
      call sfftw_execute(planF)
      fun1=conjg(tfld/sqrt(1.*(2*nw-1)))
      do ixs=1,nx*nz
         tfld=cmplx(x((ixs-1)*(2*nw-1)+1:ixs*(2*nw-1)),0.)
         call sfftw_execute(planF)
         tfld=tfld/sqrt(1.*(2*nw-1))*fun1
         call sfftw_execute(planI)
         correl(ixs,:)=tfld
         correl(ixs,:)=cshift(correl(ixs,:),int((2*nw-1)/2))
      end do
      correl=correl/maxval(correl(1,:))*2*(2*nw-1)
      if (L==0) then
         call to_history("n1",nx*nz,"corrx0");call to_history("d1",1.,"corrx0");call to_history("o1",1.,"corrx0")
         call to_history("n2",2*nw-1,"corrx0");call to_history("d2",2.,"corrx0");call to_history("o2",-float(2*nw-1),"corrx0")
         call to_history("n3",1,"corrx0");call to_history("d3",1.,"corrx0");call to_history("o3",1.,"corrx0")  
         call to_history("n4",1,"corrx0");call to_history("d4",1.,"corrx0");call to_history("o4",0.,"corrx0")
         call to_history("n5",1,"corrx0");call to_history("d5",1.,"corrx0");call to_history("o5",0.,"corrx0")  
         call to_history("esize",4,"corrx0")
         call srite("corrx0",correl,4*(2*nw-1)*nz*nx)
      else
         call to_history("n1",nx*nz,"corrxf");call to_history("d1",1.,"corrxf");call to_history("o1",1.,"corrxf")
         call to_history("n2",2*nw-1,"corrxf");call to_history("d2",2.,"corrxf");call to_history("o2",-float(2*nw-1),"corrxf")
         call to_history("n3",1,"corrxf");call to_history("d3",1.,"corrxf");call to_history("o3",1.,"corrxf")  
         call to_history("n4",1,"corrxf");call to_history("d4",1.,"corrxf");call to_history("o4",0.,"corrxf")
         call to_history("n5",1,"corrxf");call to_history("d5",1.,"corrxf");call to_history("o5",0.,"corrxf")  
         call to_history("esize",4,"corrxf")
         call srite("corrxf",correl,4*(2*nw-1)*nz*nx)
      end if
      call owfftwdestroy()
      deallocate(tfld,fun1,correl)
   else
      if (allocated(tfld)) deallocate(tfld);allocate(tfld(nw))
      call owfftw(tfld)
      allocate(fun1(nw))
      allocate(correl(nz*nx,nw))
      tfld=cmplx(x(1:nw),0.)
      call sfftw_execute(planF)
      fun1=conjg(tfld/sqrt(1.*(nw)))
      do ixs=1,nx*nz
         tfld=cmplx(x((ixs-1)*nw+1:ixs*nw),0.)
         call sfftw_execute(planF)
         tfld=tfld/sqrt(1.*(nw))*fun1
         call sfftw_execute(planI)
         correl(ixs,:)=tfld
         correl(ixs,:)=cshift(correl(ixs,:),int(nw/2))
      end do
      correl=correl/maxval(correl(1,:))*2*nw
      if (L==0) then
         call to_history("n1",nx*nz,"corrx0");call to_history("d1",1.,"corrx0");call to_history("o1",1.,"corrx0")
         call to_history("n2",nw,"corrx0");call to_history("d2",2.,"corrx0");call to_history("o2",-float(nw),"corrx0")
         call to_history("n3",1,"corrx0");call to_history("d3",1.,"corrx0");call to_history("o3",1.,"corrx0")  
         call to_history("n4",1,"corrx0");call to_history("d4",1.,"corrx0");call to_history("o4",0.,"corrx0")
         call to_history("n5",1,"corrx0");call to_history("d5",1.,"corrx0");call to_history("o5",0.,"corrx0")  
         call to_history("esize",4,"corrx0")
         call srite("corrx0",correl,4*nw*nz*nx)
      else
         call to_history("n1",nx*nz,"corrxf");call to_history("d1",1.,"corrxf");call to_history("o1",1.,"corrxf")
         call to_history("n2",nw,"corrxf");call to_history("d2",2.,"corrxf");call to_history("o2",-float(nw),"corrxf")
         call to_history("n3",1,"corrxf");call to_history("d3",1.,"corrxf");call to_history("o3",1.,"corrxf")  
         call to_history("n4",1,"corrxf");call to_history("d4",1.,"corrxf");call to_history("o4",0.,"corrxf")
         call to_history("n5",1,"corrxf");call to_history("d5",1.,"corrxf");call to_history("o5",0.,"corrxf")  
         call to_history("esize",4,"corrxf")
         call srite("corrxf",correl,4*nw*nz*nx)
      end if
      call owfftwdestroy()
      deallocate(tfld,fun1,correl)
   end if

end subroutine
!==================================================================
END MODULE simulated_anneal
