rename
[unres4.git] / source / unres / random.F90
diff --git a/source/unres/random.F90 b/source/unres/random.F90
new file mode 100644 (file)
index 0000000..fa14312
--- /dev/null
@@ -0,0 +1,577 @@
+      module random
+!-----------------------------------------------------------------------------
+      use io_units
+      use prng ! prng.f90 or prng_32.f90
+      use math
+      implicit none
+!      public :: rndv
+!
+!-----------------------------------------------------------------------------
+      contains
+!-----------------------------------------------------------------------------
+! gen_rand_conf.F
+!-----------------------------------------------------------------------------
+      real(kind=8) function ran_number(x1,x2)
+! Calculate a random real number from the range (x1,x2).
+#ifdef MPI
+      use MPI_data     ! include 'COMMON.SETUP'
+      include "mpif.h"
+#endif
+
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      real(kind=8) :: x1,x2,fctor
+!el local variables
+      integer :: ix(1) !el ix --->  ix(1)
+      data fctor /2147483647.0D0/
+#ifdef MPI
+      ran_number=x1+(x2-x1)*prng_next(me)
+#else
+      call vrnd(ix(1),1)
+      ran_number=x1+(x2-x1)*ix(1)/fctor
+#endif
+      return
+      end function ran_number
+!-----------------------------------------------------------------------------
+      integer function iran_num(n1,n2)
+! Calculate a random integer number from the range (n1,n2).
+#ifdef MPI
+      use MPI_data     ! include 'COMMON.SETUP'
+      include "mpif.h"
+#endif
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+      integer :: n1,n2,ix(1)   !el ix --->  ix(1)
+      real(kind=4) :: fctor=2147483647.0
+#ifdef MPI
+      ix(1)=n1+(n2-n1+1)*prng_next(me)
+      if (ix(1).lt.n1) ix(1)=n1
+      if (ix(1).gt.n2) ix(1)=n2
+      iran_num=ix(1)
+#else
+      call vrnd(ix(1),1)
+      ix(1)=n1+(n2-n1+1)*(ix(1)/fctor)
+      if (ix(1).gt.n2) ix(1)=n2
+      iran_num=ix(1)
+#endif
+      return
+      end function iran_num
+!-----------------------------------------------------------------------------
+      real(kind=8) function binorm(x1,x2,sigma1,sigma2,ak)
+!      implicit real*8 (a-h,o-z)
+!el local variables
+      real(kind=8) :: x1,x2,sigma1,sigma2,ak,alowb,aupb,seg,alen
+!     print '(a)','Enter BINORM.'
+      alowb=dmin1(x1-3.0D0*sigma1,x2-3.0D0*sigma2)
+      aupb=dmax1(x1+3.0D0*sigma1,x2+3.0D0*sigma2)
+      seg=sigma1/(sigma1+ak*sigma2)
+      alen=ran_number(0.0D0,1.0D0)
+      if (alen.lt.seg) then
+        binorm=anorm_distr(x1,sigma1,alowb,aupb)
+      else
+        binorm=anorm_distr(x2,sigma2,alowb,aupb)
+      endif
+!     print '(a)','Exiting BINORM.'
+      return
+      end function binorm
+!-----------------------------------------------------------------------------
+      real(kind=8) function anorm_distr(x,sigma,alowb,aupb)
+!        implicit real*8 (a-h,o-z)
+!  to make a normally distributed deviate with zero mean and unit variance
+!
+        integer :: iset
+        real(kind=8) :: fac,gset,rsq,v1,v2,ran1
+        real(kind=8) :: x,sigma,alowb,aupb,gaussdev
+        save iset,gset
+        data iset/0/
+!elwrite(iout,*) "anorm distr start",x,sigma,alowb,aupb
+        if(iset.eq.0) then
+    1           v1=2.0d0*ran_number(0.0d0,1.0d0)-1.0d0
+                v2=2.0d0*ran_number(0.0d0,1.0d0)-1.0d0
+                rsq=v1**2+v2**2
+                if(rsq.ge.1.d0.or.rsq.eq.0.0d0) goto 1
+                fac=sqrt(-2.0d0*log(rsq)/rsq)
+                gset=v1*fac
+                gaussdev=v2*fac
+                iset=1
+        else
+                gaussdev=gset
+                iset=0
+        endif
+        anorm_distr=x+gaussdev*sigma
+!elwrite(iout,*) "anorm distr end",x,sigma,alowb,aupb,anorm_distr
+      return
+      end function anorm_distr
+!-----------------------------------------------------------------------------
+      subroutine mult_norm(lda,n,a,x,fail)
+!
+! Generate the vector X whose elements obey the multiple-normal distribution
+! from exp(-0.5*X'AX). LDA is the leading dimension of the moment matrix A,
+! n is the dimension of the problem. FAIL is set at .TRUE., if the smallest
+! eigenvalue of the matrix A is close to 0.
+!
+!      implicit double precision (a-h,o-z)
+      integer :: lda,n,i,j
+      real(kind=8),dimension(lda,n) :: a
+      real(kind=8),dimension(n) :: x
+      real(kind=8),dimension(100) :: eig,work
+      real(kind=8),dimension(3,3) :: vec
+      real(kind=8) :: eig_limit=1.0D-8
+      logical :: fail
+      real(kind=8) :: sigma,alim,xi
+      fail=.false.
+!     print '(a)','Enter MULT_NORM.'
+!
+! Find the smallest eigenvalue of the matrix A.
+!
+!     do i=1,n
+!       print '(8f10.5)',(a(i,j),j=1,n)
+!     enddo
+#ifdef NAG
+      call f02faf('V','U',2,a,lda,eig,work,100,ifail)
+#else
+      call djacob(2,lda,10000,1.0d-10,a,vec,eig)
+#endif
+!     print '(8f10.5)',(eig(i),i=1,n)
+!     print '(a)'
+!     do i=1,n
+!       print '(8f10.5)',(a(i,j),j=1,n)
+!     enddo
+      if (eig(1).lt.eig_limit) then
+        print *,'From Mult_Norm: Eigenvalues of A are too small.'
+        fail=.true.
+      return
+      endif
+! 
+! Generate points following the normal distributions along the principal
+! axes of the moment matrix. Store in WORK.
+!
+      do i=1,n
+        sigma=1.0D0/dsqrt(eig(i))
+        alim=-3.0D0*sigma
+        work(i)=anorm_distr(0.0D0,sigma,-alim,alim)
+      enddo
+!
+! Transform the vector of normal variables back to the original basis.
+!
+      do i=1,n
+        xi=0.0D0
+        do j=1,n
+          xi=xi+a(i,j)*work(j)
+        enddo
+        x(i)=xi
+      enddo
+      return
+      end subroutine mult_norm
+!-----------------------------------------------------------------------------
+      subroutine mult_norm1(lda,n,a,z,box,x,fail)
+!
+! Generate the vector X whose elements obey the multi-gaussian multi-dimensional
+! distribution from sum_{i=1}^m W(i)exp[-0.5*X'(i)A(i)X(i)]. LDA is the 
+! leading dimension of the moment matrix A, n is the dimension of the 
+! distribution, nlob is the number of lobes. FAIL is set at .TRUE., if the 
+! smallest eigenvalue of the matrix A is close to 0.
+!
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+#ifdef MP
+      use MPI_data     !include 'COMMON.SETUP' 
+#endif
+#ifdef MPI
+      include 'mpif.h'
+#endif
+      integer :: lda,n,i,j,istep
+      real(kind=8),dimension(lda,n) :: a
+      real(kind=8),dimension(n) :: z,x
+      real(kind=8),dimension(n,n) :: box
+      real(kind=8) :: etmp,ww,xi,dec
+!      include 'COMMON.IOUNITS'
+      logical :: fail
+! 
+! Generate points following the normal distributions along the principal
+! axes of the moment matrix. Store in WORK.
+!
+!d    print *,'CG Processor',me,' entered MultNorm1.'
+!d    print '(2(1pe14.4),3x,1pe14.4)',((a(i,j),j=1,2),z(i),i=1,2)
+!d    do i=1,n
+!d      print *,i,box(1,i),box(2,i)
+!d    enddo
+      istep = 0
+   10 istep = istep + 1
+      if (istep.gt.10000) then
+!        write (iout,'(a,i4,2a)') 'CG Processor: ',me,': too many steps',
+!     & ' in MultNorm1.'
+!        write (*,'(a,i4,2a)') 'CG Processor: ',me,': too many steps',
+!     & ' in MultNorm1.'
+!        write (iout,*) 'box',box
+!        write (iout,*) 'a',a
+!        write (iout,*) 'z',z
+        fail=.true.
+        return
+      endif
+      do i=1,n
+       x(i)=ran_number(box(1,i),box(2,i))
+      enddo
+      ww=0.0D0
+      do i=1,n
+        xi=pinorm(x(i)-z(i))
+        ww=ww+0.5D0*a(i,i)*xi*xi
+        do j=i+1,n
+          ww=ww+a(i,j)*xi*pinorm(x(j)-z(j))
+        enddo
+      enddo
+      dec=ran_number(0.0D0,1.0D0)
+!      print *,(x(i),i=1,n),ww,dexp(-ww),dec
+!rc   if (dec.gt.dexp(-ww)) goto 10
+      if(-ww.lt.100) then
+       etmp=dexp(-ww)
+      else
+       return  
+      endif
+      if (dec.gt.etmp) goto 10
+!d    print *,'CG Processor',me,' exitting MultNorm1.'
+      return
+      end subroutine mult_norm1
+!-----------------------------------------------------------------------------
+! ran.f
+!-----------------------------------------------------------------------------
+      function ran0(idum)
+      integer :: idum
+      integer,parameter :: IA=16807,IM=2147483647,IQ=127773,IR=2836
+      integer,parameter :: MASK=123459876
+      real(kind=4) :: ran0
+      real(kind=4),parameter :: AM=1./IM
+      integer :: k
+      idum=ieor(idum,MASK)
+      k=idum/IQ
+      idum=IA*(idum-k*IQ)-IR*k
+      if (idum.lt.0) idum=idum+IM
+      ran0=AM*idum
+      idum=ieor(idum,MASK)
+      return
+      end function ran0
+!  (C) Copr. 1986-92 Numerical Recipes Software *11915
+!-----------------------------------------------------------------------------
+      function ran1(idum)
+      integer :: idum
+      integer,parameter :: IA=16807,IM=2147483647,IQ=127773,IR=2836
+      integer,parameter :: NTAB=32,NDIV=1+(IM-1)/NTAB
+      real(kind=4) :: ran1
+      real(kind=4),parameter :: AM=1./IM,EPS=1.2e-7,RNMX=1.-EPS
+      integer :: j,k,iy
+      integer,dimension(NTAB) :: iv
+      SAVE iv,iy
+      DATA iv /NTAB*0/, iy /0/
+      if (idum.le.0.or.iy.eq.0) then
+        idum=max(-idum,1)
+        do 11 j=NTAB+8,1,-1
+          k=idum/IQ
+          idum=IA*(idum-k*IQ)-IR*k
+          if (idum.lt.0) idum=idum+IM
+          if (j.le.NTAB) iv(j)=idum
+11      continue
+        iy=iv(1)
+      endif
+      k=idum/IQ
+      idum=IA*(idum-k*IQ)-IR*k
+      if (idum.lt.0) idum=idum+IM
+      j=1+iy/NDIV
+      iy=iv(j)
+      iv(j)=idum
+      ran1=min(AM*iy,RNMX)
+      return
+      end function ran1
+!  (C) Copr. 1986-92 Numerical Recipes Software *11915
+!-----------------------------------------------------------------------------
+      function ran2(idum)
+      integer :: idum
+      integer,parameter :: IM1=2147483563,IM2=2147483399,IMM1=IM1-1,&
+              IA1=40014,IA2=40692,IQ1=53668,IQ2=52774,IR1=12211,IR2=3791,&
+              NTAB=32,NDIV=1+IMM1/NTAB
+      real(kind=4) :: ran2
+      real(kind=4),parameter :: AM=1./IM1,EPS=1.2e-7,RNMX=1.-EPS
+      integer :: idum2,j,k,iy
+      integer,dimension(NTAB) :: iv
+      SAVE iv,iy,idum2
+      DATA idum2/123456789/, iv/NTAB*0/, iy/0/
+      if (idum.le.0) then
+        idum=max(-idum,1)
+        idum2=idum
+        do 11 j=NTAB+8,1,-1
+          k=idum/IQ1
+          idum=IA1*(idum-k*IQ1)-k*IR1
+          if (idum.lt.0) idum=idum+IM1
+          if (j.le.NTAB) iv(j)=idum
+11      continue
+        iy=iv(1)
+      endif
+      k=idum/IQ1
+      idum=IA1*(idum-k*IQ1)-k*IR1
+      if (idum.lt.0) idum=idum+IM1
+      k=idum2/IQ2
+      idum2=IA2*(idum2-k*IQ2)-k*IR2
+      if (idum2.lt.0) idum2=idum2+IM2
+      j=1+iy/NDIV
+      iy=iv(j)-idum2
+      iv(j)=idum
+      if(iy.lt.1)iy=iy+IMM1
+      ran2=min(AM*iy,RNMX)
+      return
+      end function ran2
+!  (C) Copr. 1986-92 Numerical Recipes Software *11915
+!-----------------------------------------------------------------------------
+      function ran3(idum)
+      integer :: idum
+      integer,parameter :: MBIG=1000000000,MSEED=161803398,MZ=0
+!     REAL MBIG,MSEED,MZ
+      real(kind=4) :: ran3
+      real(kind=4),parameter :: FAC=1./MBIG
+!     PARAMETER (MBIG=4000000.,MSEED=1618033.,MZ=0.,FAC=1./MBIG)
+      integer :: i,iff,ii,inext,inextp,k
+      integer :: mj,mk
+      integer,dimension(55) :: ma
+!     REAL mj,mk,ma(55)
+      SAVE iff,inext,inextp,ma
+      DATA iff /0/
+      if(idum.lt.0.or.iff.eq.0)then
+        iff=1
+        mj=MSEED-iabs(idum)
+        mj=mod(mj,MBIG)
+        ma(55)=mj
+        mk=1
+        do 11 i=1,54
+          ii=mod(21*i,55)
+          ma(ii)=mk
+          mk=mj-mk
+          if(mk.lt.MZ)mk=mk+MBIG
+          mj=ma(ii)
+11      continue
+        do 13 k=1,4
+          do 12 i=1,55
+            ma(i)=ma(i)-ma(1+mod(i+30,55))
+            if(ma(i).lt.MZ)ma(i)=ma(i)+MBIG
+12        continue
+13      continue
+        inext=0
+        inextp=31
+        idum=1
+      endif
+      inext=inext+1
+      if(inext.eq.56)inext=1
+      inextp=inextp+1
+      if(inextp.eq.56)inextp=1
+      mj=ma(inext)-ma(inextp)
+      if(mj.lt.MZ)mj=mj+MBIG
+      ma(inext)=mj
+      ran3=mj*FAC
+      return
+      end function ran3
+!  (C) Copr. 1986-92 Numerical Recipes Software *11915
+!-----------------------------------------------------------------------------
+! randgens.f
+!-----------------------------------------------------------------------------
+! $Date: 1994/10/04 16:19:52 $
+! $Revision: 2.1 $
+!
+!
+!  See help for RANDOMV on the PSFSHARE disk to understand these
+!  subroutines.  This is the VS Fortran version of this code.
+!
+!
+      subroutine VRND(VEC,N)
+
+      use comm_vrandd
+!el      integer,dimension(250) :: A
+      integer :: LOOP,N !el,I,I147
+      integer,dimension(N) :: VEC
+!el      COMMON /VRANDD/ A, I, I147
+      DO 23000 LOOP=1,N
+      I=I+1
+      IF(.NOT.(I.GE.251))GOTO 23002
+      I=1
+23002 CONTINUE
+      I147=I147+1
+      IF(.NOT.(I147.GE.251))GOTO 23004
+      I147=1
+23004 CONTINUE
+      A(I)=IEOR(A(I147),A(I))
+      VEC(LOOP)=A(I)
+23000 CONTINUE
+      return
+      end subroutine VRND
+!-----------------------------------------------------------------------------
+      real(kind=8) function RNDV(IDUM)
+
+      real(kind=8) :: RM1,RM2,R(99)
+      INTEGER :: IA1,IC1,M1, IA2,IC2,M2, IA3,IC3,M3, IDUM
+      INTEGER :: IX1,IX2,IX3,J
+      SAVE
+      DATA IA1,IC1,M1/1279,351762,1664557/
+      DATA IA2,IC2,M2/2011,221592,1048583/
+      DATA IA3,IC3,M3/15551,6150,29101/
+      IF(.NOT.(IDUM.LT.0))GOTO 23006
+      IX1 = MOD(-IDUM,M1)
+      IX1 = MOD(IA1*IX1+IC1,M1)
+      IX2 = MOD(IX1,M2)
+      IX1 = MOD(IA1*IX1+IC1,M1)
+      IX3 = MOD(IX1,M3)
+      RM1 = 1./DBLE(M1)
+      RM2 = 1./DBLE(M2)
+      DO 23008 J = 1,99
+      IX1 = MOD(IA1*IX1+IC1,M1)
+      IX2 = MOD(IA2*IX2+IC2,M2)
+      R(J) = (DBLE(IX1)+DBLE(IX2)*RM2)*RM1
+23008 CONTINUE
+23006 CONTINUE
+      IX1 = MOD(IA1*IX1+IC1,M1)
+      IX2 = MOD(IA2*IX2+IC2,M2)
+      IX3 = MOD(IA3*IX3+IC3,M3)
+      J = 1+(99*IX3)/M3
+      RNDV = R(J)
+      R(J) = (DBLE(IX1)+DBLE(IX2)*RM2)*RM1
+      IDUM = IX1
+      return
+      end function RNDV
+!-----------------------------------------------------------------------------
+      subroutine VRNDST(SEED)
+
+      use comm_vrandd
+!el      INTEGER :: A(250)
+      INTEGER :: LOOP,IDUM !el,I,I147
+      INTEGER :: SEED
+!el      real(kind=8) :: RNDV
+!el      COMMON /VRANDD/ A, I, I147
+      I=0
+      I147=103
+      IDUM=SEED
+      DO 23010 LOOP=1,250
+      A(LOOP)=INT(RNDV(IDUM)*2147483647)
+23010 CONTINUE
+      return
+      end subroutine VRNDST
+!-----------------------------------------------------------------------------
+      subroutine VRNDIN(IODEV)
+      use comm_vrandd
+      INTEGER :: IODEV !el, A(250),I, I147
+!el      COMMON/VRANDD/ A, I, I147
+      READ(IODEV) A, I, I147
+      return
+      end subroutine VRNDIN
+!-----------------------------------------------------------------------------
+      subroutine VRNDOU(IODEV)
+!       This corresponds to VRNDOUT in the APFTN64 version
+      use comm_vrandd
+      INTEGER :: IODEV !el, A(250),I, I147
+!el      COMMON/VRANDD/ A, I, I147
+      WRITE(IODEV) A, I, I147
+      return
+      end subroutine VRNDOU
+!-----------------------------------------------------------------------------
+      real(kind=8) function RNUNF(N)
+      INTEGER :: IRAN1(2000),N
+      real(kind=8) :: FCTOR
+      DATA FCTOR /2147483647.0D0/
+!     We get only one random number, here!    DR  9/1/92
+      CALL VRND(IRAN1,1)
+      RNUNF= DBLE( IRAN1(1) ) / FCTOR
+!******************************
+!     write(6,*) 'rnunf  in rnunf = ',rnunf
+      return
+      end function RNUNF
+!-----------------------------------------------------------------------------
+! readrtns_CSA.F
+!-----------------------------------------------------------------------------
+      subroutine random_init(seed)
+!
+! Initialize random number generator
+!
+!      implicit real*8 (a-h,o-z)
+!      include 'DIMENSIONS'
+#ifdef MPI
+      use MPI_data
+      include 'mpif.h'
+      logical :: OKRandom !, prng_restart
+      real(kind=8) :: r1
+      integer :: iseed_array(4)
+      integer(kind=8) :: iseed
+#else
+      integer :: iseed
+#endif
+      real(kind=8) :: seed
+      integer :: ierr,error_msg
+!      include 'COMMON.IOUNITS'
+!      include 'COMMON.TIME1'
+!      include 'COMMON.THREAD'
+!      include 'COMMON.SBRIDGE'
+!      include 'COMMON.CONTROL'
+!      include 'COMMON.MCM'
+!      include 'COMMON.MAP'
+!      include 'COMMON.HEADER'
+!      include 'COMMON.CSA'
+!      include 'COMMON.CHAIN'
+!      include 'COMMON.MUCA'
+!      include 'COMMON.MD'
+!      include 'COMMON.FFIELD'
+!      include 'COMMON.SETUP'
+      iseed=-dint(dabs(seed))
+      if (iseed.eq.0) then
+        write (iout,'(/80(1h*)/20x,a/80(1h*))') &
+          'Random seed undefined. The program will stop.'
+        write (*,'(/80(1h*)/20x,a/80(1h*))') &
+          'Random seed undefined. The program will stop.'
+#ifdef MPI
+        call mpi_finalize(mpi_comm_world,ierr)
+#endif
+        stop 'Bad random seed.'
+      endif
+#ifdef MPI
+      if (fg_rank.eq.0) then
+      seed=seed*(me+1)+1
+#ifdef AMD64
+      if(me.eq.king) &
+        write (iout,*) 'MPI: node= ', me, ' iseed= ',iseed
+      OKRandom = prng_restart(me,iseed)
+#else
+      do i=1,4
+       tmp=65536.0d0**(4-i)
+       iseed_array(i) = dint(seed/tmp)
+       seed=seed-iseed_array(i)*tmp
+      enddo
+      if(me.eq.king) &
+       write (iout,*) 'MPI: node= ', me, ' iseed(4)= ',&
+                       (iseed_array(i),i=1,4)
+      write (*,*) 'MPI: node= ',me, ' iseed(4)= ',&
+                       (iseed_array(i),i=1,4)
+      OKRandom = prng_restart(me,iseed_array)
+#endif
+      if (OKRandom) then
+!        r1 = prng_next(me)
+         r1=ran_number(0.0D0,1.0D0)
+        if(me.eq.king) &
+         write (iout,*) 'ran_num',r1
+        if (r1.lt.0.0d0) OKRandom=.false.
+      endif
+      if (.not.OKRandom) then
+        write (iout,*) 'PRNG IS NOT WORKING!!!'
+        print *,'PRNG IS NOT WORKING!!!'
+        if (me.eq.0) then 
+         call flush(iout)
+         call mpi_abort(mpi_comm_world,error_msg,ierr)
+         stop
+        else
+         write (iout,*) 'too many processors for parallel prng'
+         write (*,*) 'too many processors for parallel prng'
+         call flush(iout)
+         stop
+        endif
+      endif
+      endif
+#else
+      call vrndst(iseed)
+      write (iout,*) 'ran_num',ran_number(0.0d0,1.0d0)
+#endif
+      return
+      end subroutine random_init
+!-----------------------------------------------------------------------------
+!-----------------------------------------------------------------------------
+      end module random