C @(#)chaos.for	19.1 (ESO-DMD) 02/25/03 13:24:47
C===========================================================================
C Copyright (C) 1995 European Southern Observatory (ESO)
C
C This program is free software; you can redistribute it and/or 
C modify it under the terms of the GNU General Public License as 
C published by the Free Software Foundation; either version 2 of 
C the License, or (at your option) any later version.
C
C This program is distributed in the hope that it will be useful,
C but WITHOUT ANY WARRANTY; without even the implied warranty of
C MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
C GNU General Public License for more details.
C
C You should have received a copy of the GNU General Public 
C License along with this program; if not, write to the Free 
C Software Foundation, Inc., 675 Massachusetts Ave, Cambridge, 
C MA 02139, USA.
C
C Correspondence concerning ESO-MIDAS should be addressed as follows:
C	Internet e-mail: midas@eso.org
C	Postal address: European Southern Observatory
C			Data Management Division 
C			Karl-Schwarzschild-Strasse 2
C			D 85748 Garching bei Muenchen 
C			GERMANY
C===========================================================================
C
      PROGRAM CHAOS
C
C++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.IDENTIFICATION
C  program CHAOS			version 1.00	901031
C  K. Banse				ESO - Garching
C
C.KEYWORDS
C  dynamic systems, bulk data frame
C
C.PURPOSE
C  create a MIDAS image
C
C.ALGORITHM
C  use MIDAS interfaces
C
C.INPUT/OUTPUT
C  the following keywords are used:
C
C IN_A/C/1/60                  	name of new image file
C DEFAULT/C/1/1         	= Y, all image info given in command line
C                  		= N, use frame given in key P2 for that
C P3/C/1/60                  	info frame, if DEFAULT = N
C INPUTI/I/1/7                 	NAXIS + NPIX
C INPUTR/R/1/12                	START + STEP
C P4/C/1/20                  	type of data function
C                  		= LORENZ, ELFLY, JULIA, SYMM
C P5/C/1/60                  	coefficients for data function
C
C.VERSIONS
C  1.00		from version 1.20 of crfram.for
C
C--------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER      NAXIS,CUNLEN
      INTEGER*8    PNTR
      INTEGER      IAV,IDUM,N,NCOEF,NO,STAT
      INTEGER      INO,IBUF(7),NPIX(6)
      INTEGER      NLO,RNO,UNIT(1),MADRID(1)
      INTEGER      NPIX1,NPIX2
C
      REAL         CUTS(4),COEFS(10),FMIN,FMAX,RDUM
C
      DOUBLE PRECISION START(6),STEP(6),DBUF(12)
      DOUBLE PRECISION DCOEFS(3),DDUM
C
      CHARACTER    CUNIT*112,IDENT*72,NAME*60,INFRAM*60
      CHARACTER    CBUF*60,DEFAUL*1
      CHARACTER    FUNCY*4
C
      INCLUDE 'MID_INCLUDE:ST_DEF.INC'
C
      COMMON   /VMR/ MADRID
C
      DATA      CUNIT /'none given '/, CBUF /' '/
      DATA      NPIX      /6*1/,       START /6*0.D0/, STEP /6*1.D0/
      DATA      NAME      /' '/,       INFRAM /' '/
C
      INCLUDE 'MID_INCLUDE:ST_DAT.INC'
C
C  get into MIDAS
      CALL STSPRO('CHAOS')
C
C  get name and type of new frame and DEFAULT flag
      CALL STKRDC('IN_A',1,1,60,IAV,NAME,UNIT,NLO,STAT)
      CALL STKRDC('DEFAULT',1,1,1,IAV,DEFAUL,UNIT,NLO,STAT)
      CALL UPCAS(DEFAUL,DEFAUL)
C
C  image info from command line or reference frame
      IF (DEFAUL.NE.'Y') THEN
         CALL STKRDC('P3',1,1,60,IAV,INFRAM,UNIT,NLO,STAT)  !get ref. frame
C
C  read all relevant descriptors
         CALL STFOPN(INFRAM,D_OLD_FORMAT,0,F_IMA_TYPE,RNO,STAT)
         CALL STDRDI(RNO,'NAXIS',1,1,IAV,NAXIS,UNIT,NLO,STAT)
         CALL STDRDI(RNO,'NPIX',1,NAXIS,IAV,NPIX,UNIT,NLO,STAT)
         CALL STDRDD(RNO,'START',1,NAXIS,IAV,START,UNIT,NLO,STAT)
         CALL STDRDD(RNO,'STEP',1,NAXIS,IAV,STEP,UNIT,NLO,STAT)
         CALL STDRDC(RNO,'IDENT',1,1,72,IAV,IDENT,UNIT,NLO,STAT)
         CALL STDRDC(RNO,'CUNIT',1,1,112,IAV,CUNIT,UNIT,NLO,STAT)
      ELSE
C
C     get NAXIS, NPIX, START + STEP (max 6 dimensions)
         CALL STKRDI('INPUTI',1,7,IAV,IBUF,UNIT,NLO,STAT)
         CALL STKRDD('INPUTD',1,12,IAV,DBUF,UNIT,NLO,STAT)
C
C     set descriptor values
         NAXIS = IBUF(1)
         IF ((NAXIS.LT.1).OR.(NAXIS.GT.6))
     +      CALL STETER(1,'invalid NAXIS ...')      !invalid NAXIS ...
C
         DO 800 N=1,NAXIS
            NPIX(N) = IBUF(N+1)
            START(N) = DBUF(N)
            STEP(N) = DBUF(N+NAXIS)
800      CONTINUE
      ENDIF
C
C  finally look for coefficients + function type
      CALL STKRDC('P4',1,1,4,IAV,FUNCY,UNIT,NLO,STAT)
      CALL UPCAS(FUNCY,FUNCY)
      CALL STKRDC('P5',1,1,60,IAV,CBUF,UNIT,NLO,STAT)
C
      IDENT = 'artificial image '
      CUNLEN = (NAXIS+1)*16
C
C  create new frame
      CALL STIPUT(NAME,D_R4_FORMAT,F_O_MODE,F_IMA_TYPE,
     +            NAXIS,NPIX,START,STEP,IDENT,
     +            CUNIT(1:CUNLEN),PNTR,INO,STAT)
      NO = NPIX(1) * NPIX(2)
      CALL NL(MADRID(PNTR),NO)                   !set everything to 0.0
C
C  branch according to function type
C 
C
      NPIX1  =  NPIX(1)
      NPIX2  =  NPIX(2)
C  Lorenz attractors
      IF (FUNCY(1:2).EQ.'LO') THEN
         CALL GENCNV(CBUF,2,7,IDUM,COEFS,DDUM,NCOEF) !x,y,z + h,a,b + no_iter
         IF (NCOEF.LT.6) 
     +      CALL STETER(1,'we need 6 coefficients...')
         IF (NCOEF.LT.7) COEFS(7) = 4000.
         CALL LOR(MADRID(PNTR),NPIX1,NPIX2,COEFS,FMIN,FMAX,
     +                                              START,STEP)   
C 
C  chaotic dynamic system  - Electronic Fly)
      ELSE IF (FUNCY(1:3).EQ.'ELF') THEN
         CALL GENCNV(CBUF,2,6,IDUM,COEFS,DDUM,NCOEF)    !a,b,c,d,e + no_iter
         IF (NCOEF.LT.5) 
     +      CALL STETER(1,'we need 5 coefficients...')
         IF (NCOEF.LT.6) COEFS(6) = 1000000.
         CALL ELFLY(MADRID(PNTR),NPIX1,NPIX2,COEFS,FMIN,FMAX,
     +                                               START,STEP)  
C 
C  Mandelbrot set
      ELSE IF (FUNCY(1:1).EQ.'M') THEN
         CALL GENCNV(CBUF,4,3,IDUM,RDUM,DCOEFS,NCOEF)    !x,y + no_iter
         IF (NCOEF.LT.2) 
     +      CALL STETER(1,'we need 2 coefficients...')
         IF (NCOEF.LT.3) DCOEFS(3) = 100.
         CALL MANDEL(MADRID(PNTR),NPIX1,NPIX2,START,STEP,DCOEFS,
     +               FMIN,FMAX)
C 
C  Julia set
      ELSE IF (FUNCY(1:1).EQ.'J') THEN
         CALL GENCNV(CBUF,4,3,IDUM,RDUM,DCOEFS,NCOEF)    !x,y + no_iter
         IF (NCOEF.LT.2) 
     +      CALL STETER(1,'we need 2 coefficients...')
         IF (NCOEF.LT.3) DCOEFS(3) = 100.
         CALL JULIA(MADRID(PNTR),NPIX1,NPIX2,START,STEP,DCOEFS,
     +              FMIN,FMAX)
C 
C  Colour wheel
      ELSE IF (FUNCY(1:3).EQ.'COL') THEN
         CALL COLWH(MADRID(PNTR),NPIX1,NPIX2,FMIN,FMAX)
C 
C  Symmetric chaos
      ELSE IF (FUNCY(1:3).EQ.'SYM') THEN
         CALL GENCNV(CBUF,2,7,IDUM,COEFS,DDUM,NCOEF)            !a,b,c,d
         CALL SYM(MADRID(PNTR),NPIX1,NPIX2,COEFS,FMIN,FMAX)
C 
      ELSE
         CALL STETER(9,'invalid function...')
      ENDIF
C
C  update cuts
      CUTS(1) = 0.
      CUTS(2) = 0.
      CUTS(3) = FMIN
      CUTS(4) = FMAX
      CALL STDWRR(INO,'LHCUTS',CUTS,1,4,UNIT,STAT)
C     
      IF (FUNCY(1:2).EQ.'LO') THEN
         CUNIT(1:) = 'Lorenz: '//CBUF
      ELSE IF (FUNCY(1:3).EQ.'ELF') THEN
         CUNIT(1:) = 'ElFly: '//CBUF
      ELSE IF (FUNCY(1:1).EQ.'M') THEN
         CUNIT(1:) = 'Mandelbrot set: '//CBUF
      ELSE IF (FUNCY(1:1).EQ.'J') THEN
         CUNIT(1:) = 'Julia set: '//CBUF
      ELSE IF (FUNCY(1:3).EQ.'COL') THEN
         CUNIT(1:) = 'Colour wheel '
      ELSE IF (FUNCY(1:3).EQ.'SYM') THEN
         CUNIT(1:) = 'Symmetric chaos: '//CBUF
      ENDIF
      CALL STDWRC(INO,'HISTORY',1,CUNIT,1,80,UNIT,STAT)
C
C  that's it folks...
      CALL STSEPI
      END

      SUBROUTINE LOR(A,NPIX1,NPIX2,RR,FMI,FMA,START,STEP)
C 
      IMPLICIT NONE
C 
      INTEGER   NPIX1,NPIX2
      INTEGER   ITLIM,N,NX,NY
      DOUBLE PRECISION  START(2), STEP(2)
C 
      REAL      A(NPIX1,NPIX2),RR(*),FMI,FMA
      REAL      X,Y,Z,XNEW,YNEW,ZNEW,H,AAAA,FRAC
      REAL      XXMIN,XXMAX,YYMIN,YYMAX
      REAL      XINC,YINC,XXX,YYY
C 
      XXMIN = START(1)
      XXMAX = START(1)+NPIX1*STEP(1)
      YYMIN = START(2)
      YYMAX = START(2)+NPIX2*STEP(2)
      XINC  = 1./STEP(1)
      YINC  = 1./STEP(2)
C 
      X = RR(1)
      Y = RR(2)
      Z = RR(3)
      H = RR(4)
      AAAA = RR(5)
      FRAC = RR(6)
      ITLIM = INT(RR(7)+0.5)
C 
      DO 1000 N=1,ITLIM
         XNEW = X + H*10.*(Y-X)
         YNEW = Y + H*((-X*Z)+AAAA*X-Y)
         ZNEW = Z + H*(X*Y-FRAC*Z)
         X = XNEW
         Y = YNEW
         Z = ZNEW
         IF ( (X.GE.XXMIN) .AND. (X.LE.XXMAX) .AND.
     +        (Y.GE.YYMIN) .AND. (Y.LE.YYMAX) ) THEN
            XXX = (X - XXMIN) * XINC
            YYY = (Y - YYMIN) * YINC
            NX = INT(XXX+0.5)
            NY = INT(YYY+0.5)
            A(NX,NY) = 1.0
         ENDIF
1000  CONTINUE
C 
      FMI = 0.
      FMA = 1.
C 
      RETURN
      END

      SUBROUTINE NL(A,NSIZE)
C 
      IMPLICIT NONE
C 
      INTEGER  NSIZE,N
C 
      REAL  A(NSIZE)
C 
      DO 500 N=1,NSIZE
         A(N) = 0.
500   CONTINUE
C 
      RETURN
      END

      SUBROUTINE ELFLY(A,NPIX1,NPIX2,RR,FMI,FMA,START,STEP)
C 
      IMPLICIT NONE
C 
      INTEGER   NPIX2,NPIX1
      INTEGER   ITLIM,N,NX,NY
      DOUBLE PRECISION START(2), STEP(2)
C 
      REAL      A(NPIX1,NPIX2),RR(*),FMI,FMA
      REAL      AA,BB,CC,DD,EE
      REAL      XXMIN,XXMAX,YYMIN,YYMAX
      REAL      XINC,YINC,X,Y,Z,X1,Y1,Z1,XXX,YYY
C 
      AA = RR(1)
      BB = RR(2)
      CC = RR(3)
      DD = RR(4)
      EE = RR(5)
      ITLIM = INT(RR(6)+0.5)
C 
      XXMIN = START(1)
      XXMAX = START(1)+NPIX1*STEP(1)
      YYMIN = START(2)
      YYMAX = START(2)+NPIX2*STEP(2)
      XINC  = 1./STEP(1)
      YINC  = 1./STEP(2)
      X = 0.                            !start wit (0.,0.,0.)
      Y = 0.
      Z = 0.
C 
      DO 1000 N=1,ITLIM
         X1 = SIN(AA*Y) - Z*COS(BB*X)
         Y1 = Z*SIN(CC*X) - COS(DD*Y)
         Z1 = EE*SIN(X)
         X = X1
         Y = Y1
         Z = Z1
         IF ( (X.GE.XXMIN) .AND. (X.LE.XXMAX) .AND.
     +        (Y.GE.YYMIN) .AND. (Y.LE.YYMAX) ) THEN
            XXX = (X - XXMIN) * XINC
            YYY = (Y - YYMIN) * YINC
            NX = INT(XXX+0.5)
            NY = INT(YYY+0.5)
            A(NX,NY) = A(NX,NY) + 1.0
C            IF (A(NX,NY).GT.FMA) FMA = A(NX,NY)
         ENDIF
1000  CONTINUE
C 
      FMI = 0.
      FMA = 10.
C 
      RETURN
      END

      SUBROUTINE MANDEL(OUT,NPIX1,NPIX2,START,STEP,DCOF,FMI,FMA)
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.ALGORITHM
C  Mandelbrot set in the tranformation    z <- z*z + c
C  with z and c complex numbers
C  input is used as initial value for z, current (x,y) coord -> c
C 
C-------------------------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER NPIX1,NPIX2,IX,IY
      INTEGER K,KUP
C
      REAL OUT(NPIX1,NPIX2)  
      REAL FMI,FMA
C
      DOUBLE PRECISION START(2)  
      DOUBLE PRECISION STEP(2)  
      DOUBLE PRECISION DCOF(3)
      DOUBLE PRECISION UPPER  
C  
      DOUBLE PRECISION DK,X1,Y1,X2,Y2,X,Y,DX,DY,R
C
      FMI = 0.
      FMA = 0.
      KUP = 256
      DX = STEP(1)
      DY = STEP(2)
      UPPER = DCOF(3)
C 
C  loop over all lines
      Y = START(2)
      DO 400 IY=1,NPIX2
         X = START(1)
C 
C  loop over all pixels of a line
         DO 300 IX=1,NPIX1
            X1 = DCOF(1)                      !Re(c) -> Re(z)
            Y1 = DCOF(2)                      !Im(c) -> Im(z)
C 
C  iterate over max 256 pixel levels
            DO 100 K=1,KUP
               X2 = (X1*X1) - (Y1*Y1) + X          !Re(z~) = Re(z*z) + Re(c)
               Y2 = 2.*(X1*Y1) + Y                 !Im(z~) = Im(z*z) + Im(c)
               R = X2*X2 + Y2*Y2                   !Abs(z~)
               IF (R.GT.UPPER) THEN
                  DK = K - 1
                  OUT(IX,IY) = DK
                  IF (DK.GT.FMA) FMA = DK
                  GO TO 200
               ENDIF
               X1 = X2
               Y1 = Y2
100         CONTINUE                !if we come out here, leave pixel at 0.0
C 
200         X = X + DX
300      CONTINUE
C 
         Y = Y + DY
400      CONTINUE
C 
      RETURN
      END


      SUBROUTINE SYM(OUT,NPIX1,NPIX2,COF,FMI,FMA)
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.ALGORITHM
C
C-------------------------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER NPIX1,NPIX2,IX,IY
      INTEGER N,LIMIT
C
      REAL OUT(NPIX1,NPIX2)
      REAL FMI,FMA
      REAL COF(7)
C 
      DOUBLE PRECISION A,B,C,D,RFY,RFX,Z
      DOUBLE PRECISION X,Y,XX,YY,XXX,YYY,XN,YN
C
      X = COF(1)
      Y = COF(2)
      A = COF(3)
      B = COF(4)
      C = COF(5)
      D = COF(6)
      LIMIT = COF(7)
      RFX = NPIX1 - 1.
      RFY = NPIX2 - 1.
C
      DO 500, N=1,LIMIT
         XX = X * X
         XXX = XX * X
         YY = Y * Y
         YYY = YY * Y
         Z = B * (XX + YY)
         XN = A*X + B*X*(XX + YY) + C*(XXX-3.0*X*YY) + D*(XX-YY)
         YN = A*Y + B*Y*(XX + YY) + C*(3.0*XX*Y-YYY) - 2.0*D*X*Y
         X = XN
         Y = YN
         IX = (X*RFX) + 1
         IF (IX.LT.1) THEN
            IX = 1
         ELSE IF (IX.GT.NPIX1) THEN
            IX = NPIX1
         ENDIF
         IY = (Y*RFY) + 1
         IF (IY.LT.1) THEN
            IY = 1
         ELSE IF (IY.GT.NPIX2) THEN
            IY = NPIX2
         ENDIF
         OUT(IX,IY) = OUT(IX,IY) + 1.
500   CONTINUE
C 
      FMI = OUT(1,1)
      FMA = FMI
      DO 800, IY=1,NPIX2
         DO 700, IX=1,NPIX1
            IF (OUT(IX,IY).LT.FMI) THEN
               FMI = OUT(IX,IY)
            ELSE IF (OUT(IX,IY).GT.FMA) THEN
               FMA = OUT(IX,IY)
            ENDIF
700      CONTINUE
800   CONTINUE
C 
      RETURN
      END


      SUBROUTINE JULIA(OUT,NPIX1,NPIX2,START,STEP,DCOF,FMI,FMA)
C+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
C
C.ALGORITHM
C  Julia set in the tranformation    z <- z*z + c
C  with z and c complex numbers
C  input -> c, current (x,y) coord are used as initial value for z
C 
C-------------------------------------------------------------------
C
      IMPLICIT NONE
C
      INTEGER NPIX1,NPIX2,IX,IY
      INTEGER K,KUP
C
      REAL OUT(NPIX1,NPIX2)  
      REAL FMI,FMA
C
      DOUBLE PRECISION START(2)  
      DOUBLE PRECISION STEP(2)  
      DOUBLE PRECISION DCOF(3)
      DOUBLE PRECISION UPPER  
C  
      DOUBLE PRECISION DK,X1,Y1,X2,Y2,X,Y,DX,DY,R
C
      FMI = 0.
      FMA = 0.
      KUP = 256
      DX = STEP(1)
      DY = STEP(2)
      UPPER = DCOF(3)
C 
C  loop over all lines
      Y = START(2)
      DO 400 IY=1,NPIX2
         X = START(1)
C 
C  loop over all pixels of a line
         DO 300 IX=1,NPIX1
            X1 = X                      !xcoord -> Re(z)
            Y1 = Y                      !ycoord -> Im(z)
C 
C  iterate over max 256 pixel levels
            DO 100 K=1,KUP
               X2 = (X1*X1) - (Y1*Y1) + DCOF(1)       !Re(z~) = Re(z*z) + Re(c)
               Y2 = 2.*(X1*Y1) + DCOF(2)              !Im(z~) = Im(z*z) + Im(c)
               R = X2*X2 + Y2*Y2                   !Abs(z~)
               IF (R.GT.UPPER) THEN
                  DK = K - 1
                  OUT(IX,IY) = DK
                  IF (DK.GT.FMA) FMA = DK
                  GO TO 200
               ENDIF
               X1 = X2
               Y1 = Y2
100         CONTINUE                !if we come out here, leave pixel at 0.0
C 
200         X = X + DX
300      CONTINUE
C 
         Y = Y + DY
400      CONTINUE
C 
      RETURN
      END

      SUBROUTINE COLWH(A,NPIX1,NPIX2,FMIN,FMAX)
C 
      IMPLICIT NONE
C 
      INTEGER   NPIX1,NPIX2
      INTEGER   NX,NY,KX,KY
      INTEGER   MAXRAD,KOFF
C 
      REAL      PHI,R,X,Y
      REAL      A(1),FMIN,FMAX
C 
      FMIN = -3.2
      FMAX = 3.142
      KX = NPIX1/2
      KY = NPIX2/2
      MAXRAD = NINT(KX * 0.80)
      MAXRAD = MAXRAD * MAXRAD               !take square of radius
      KOFF = 0
C 
      DO 5000 NY=1,NPIX2
         Y = NY - KY
C 
         DO 4000 NX=1,NPIX1
            X = NX - KX
            R = X*X + Y*Y
            IF (R .GT. MAXRAD) THEN
               PHI = FMIN
            ELSE
               PHI = ATAN2(X,Y)
            ENDIF
            A(KOFF+NX) = PHI
4000     CONTINUE
         KOFF = KOFF + NPIX1
5000  CONTINUE
C 
      RETURN
      END
