AGA V1
Asexual Genetic Algorithm Version 1.0
modules.f90
Go to the documentation of this file.
00001 !=======================================================================
00002 !> @file modules.f90
00003 !> @brief Global functions and subroutines module
00004 !> @authors Ary Rodriguez-Gonzalez & Alejandro Esquivel
00005 !> @date 23/Jun/2011
00006 !
00007 ! Copyright (c) 2011 Ary Rodriguez-Gonzalez & Alejandro Esquivel
00008 !
00009 ! This file is part of AGA-V1.
00010 !
00011 ! AGA-V1 is free software; you can redistribute it and/or modify
00012 ! it under the terms of the GNU General Public License as published by
00013 ! the Free Software Foundation; either version 3 of the License, or
00014 ! (at your option) any later version.
00015 !
00016 ! This program is distributed in the hope that it will be useful,
00017 ! but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 ! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00019 ! GNU General Public License for more details.
00020 ! You should have received a copy of the GNU General Public License
00021 ! along with this program.  If not, see http://www.gnu.org/licenses/.
00022 !=======================================================================
00023 !> @brief module mpi_module
00024 !> @details This module contains declarations needed to implement the
00025 !! Message Passing Interface (MPI) paralelization.
00026 !-----------------------------------------------------------------------
00027 module mpi_module
00028         implicit none
00029 #ifdef MPIP
00030         include "mpif.h"
00031 
00032 !> @brief rank of the master node (who is in charge of the I/O)
00033 integer, parameter :: master=0
00034 
00035 !> @brief rank of each processor (if MPI is disabled has a value of 0)
00036 integer :: rank
00037 !> @brief total number of processors (if MPI is disabled has a value of 1)
00038 integer :: np
00039 integer :: err                                          !< @brief MPI error variable
00040 integer :: status(MPI_STATUS_SIZE)      !< @brief MPI status variable
00041 
00042 #else
00043 
00044 integer, parameter :: np=1, master=0, rank=0
00045 
00046 #endif
00047 
00048 end module mpi_module
00049 !-----------------------------------------------------------------------
00050 !> @brief module func
00051 !! @details This module contains global functions and subroutines used
00052 !! by AGA-V1
00053 module func
00054 contains
00055 !-----------------------------------------------------------------------
00056 !> @brief Updates the size of the hyper-boxes
00057 !> @param[in] npar : number of free parameters (parameter space
00058 !! dimension, denoted by "n" in the paper)
00059 !> @param[in] niter : number of iteration counter
00060 !> @param[in] nind : number of individials in the entire population
00061 !> @param[in] deltaconst : if equal to 1 the reduction of the hyperboxes
00062 !! is at a constant rate (see reduc), otherwise hyperboxes are reduced 
00063 !! with the standard deviation of each parameter.
00064 !> @param[in] reduc : reducing factor, if a constant speed is chosen the
00065 !! hyper-box is reduced according to: 
00066 !! @f$\Delta_{i,niter}=\Delta_{i,niter-1}*reduc^{niter}@f$
00067 !> @param[in] arrmain(npar,nind) : Entire population of "nind" individuals, 
00068 !! each with "npar" parameters.
00069 !> @param[in] delta0(npar) : Original size of the hyperboxes, 
00070 !! array of @f$\Delta_{i,1}@f$.
00071 !> @param[out] delta(npar) : array of @f$\Delta_{i,niter}@f$ (niter 
00072 !! is constant, thus is only a vector w/npar entries). 
00073 !!@f$\Delta_{i,niter}@f$ is the size of the hyper-box corresponding to 
00074 !! the "i-th" parameter
00075   subroutine deltabox(npar,niter,nind,deltaconst,reduc,arrmain,delta0,delta)
00076     implicit none
00077     real,dimension(npar), intent(in)  :: delta0
00078     real,dimension(npar), intent(out) :: delta
00079     real,    intent(in),  dimension(npar,nind)       :: arrmain
00080     integer, intent(in):: npar,niter,deltaconst,nind
00081     real, intent(in) :: reduc
00082     real :: mean
00083     integer :: i
00084     
00085     if (deltaconst .eq. 1 .or. niter .eq. 1) then
00086        do i=1,npar
00087           delta(i) = delta0(i)*reduc**niter
00088        enddo
00089     else
00090        do i=1,npar
00091           delta(i)=sigm(arrmain(i,:),nind)
00092        enddo
00093     endif
00094 
00095   end subroutine deltabox
00096 !-----------------------------------------------------------------------
00097 !> @brief Computes the mean value
00098 !> @param[in] N : number of data points
00099 !> @param[in] stat(N) : vector from which the mean is to be obtained
00100 !> @return Arithmetic mean value of stat(N)
00101    real function med(stat,N)
00102      implicit none
00103      integer, intent(in)   :: N
00104      real, dimension(N), intent(in) :: stat
00105      integer :: i
00106      !
00107      med=0.
00108      do i=1,N
00109         med=med+stat(i)
00110      enddo
00111      !
00112      med=med/N
00113      !
00114     return
00115     !
00116   end function med
00117 !-----------------------------------------------------------------------
00118 !> @brief Computes the standard deviation
00119 !> @param[in] N : number of data points
00120 !> @param[in] stat(N) : vector from which the standard deviaiton is to 
00121 !! be obtained
00122 !> @return standard deviation of stat(N)
00123    real function sigm(stat,N)
00124      implicit none
00125      integer, intent(in)   :: N
00126      real, intent(in), dimension(N) :: stat
00127      real :: mean
00128      integer :: i
00129      !
00130      mean=med(stat,N)
00131      !
00132      sigm=0.
00133      do i=1,N
00134         sigm=sigm+(stat(i)-mean)**2
00135      enddo
00136      !
00137      sigm=sqrt(sigm/(N))
00138      !
00139      return
00140      !
00141    end function sigm
00142 !-----------------------------------------------------------------------
00143 !> @brief Asexual reproduction routine
00144 !> @param[in] npar : number of free parameters
00145 !> @param[in] gensize : size of the new generation from each parent.
00146 !! Since the parent is kept gensize= num of sons + 1
00147 !> @param[in] nmig : turns on/off migration. If its value is 0, 
00148 !! migration is disabled, otherwise is enabled
00149 !> @param[in] ngaussdev : if value equal to 1, offsprinf is obtained
00150 !! with a Gaussian distribution, otherwise they are obtained with
00151 !! uniform random deviates.
00152 !> @param[in] delta(npar) : Size of the parent hyper-box.
00153 !> @param[in] qpar(npar) : parent parameters (its location in the 
00154 !! npar-dimensional parameter space
00155 !> @param[in] qbounds(npar) : bounds of the initial universe
00156 !> @param[out] qfam(npar,gensize) : A new family (progeny+parent)
00157   subroutine spawn(npar,gensize,nmig,ngaussdev,delta,qpar,qbounds,qfam)
00158     implicit none
00159     integer, intent(in) :: npar,gensize,nmig,ngaussdev
00160     real, dimension(npar), intent(in):: delta, qpar
00161     real, dimension(2,npar), intent(in) ::qbounds
00162     real, dimension(npar,gensize) :: qfam
00163     integer :: i,j,rand_seed
00164     real :: ran1,ran
00165     !
00166     do i=1,npar
00167        qfam(i,1)=qpar(i)
00168     enddo
00169 
00170         do j=2,gensize
00171                 i=1
00172                 do while (i.le.npar)
00173                 if (ngaussdev .eq. 1) then
00174                     ran1=gaussdev(rand_seed)
00175                 else    
00176              call random_number(ran)
00177              ran1=2.*ran-1.
00178                         endif
00179                         
00180                         qfam(i,j)=qfam(i,1)+delta(i)*ran1
00181           
00182                         if (nmig.ne.0) then
00183                                 i=i+1
00184                         else if ((qfam(i,j) .ge. qbounds(1,i)).and.                 &
00185                                  (qfam(i,j) .le. qbounds(2,i)) ) then
00186                                 i=i+1
00187                         endif
00188         enddo 
00189         enddo   
00190 
00191 return
00192 end subroutine spawn
00193 !-----------------------------------------------------------------------
00194 !> @brief Evaluates convergence criterion
00195 !> @param[in] npar : Number of free parameters
00196 !> @param[in] q(npar) : Individual data
00197 !> @param[in] delta(npar) : Window size of the individual
00198 !> @param[in] beta : Tolerance value
00199 !> @param[out] ncrit : Return value=1 if criterion met, otherwise is not
00200 !! modified
00201 subroutine criterion(npar,q,delta,beta,ncrit)
00202   implicit none
00203   integer, intent(in)  :: npar
00204   real, intent(in), dimension(npar) :: q, delta
00205   real, intent(in) :: beta
00206   logical, dimension(npar) :: crit
00207   integer, intent(out) :: ncrit
00208   integer :: i
00209 
00210   crit(:)=.False.
00211   do i=1,npar
00212      if (abs(delta(i)/q(i)) .le. beta) crit(i)=.true.
00213   enddo
00214 
00215   if (all(crit(:)).eq. .true.) ncrit=1
00216 
00217   return
00218 end subroutine criterion
00219 !-----------------------------------------------------------------------
00220 !> @brief Generates new realization from experimental data
00221 !> @param[in] ndata : number of experimental data points
00222 !> @param[in,out] yobs(ndata) : experimental data
00223 !> @param[in] ysigma(ndata) : associated uncertainties of yobs
00224 !> @todo Hay que implementar dispersion Gaussiana y checar por que no se 
00225 !! guarda yobs0
00226 subroutine randdata(ndata, yobs, ysigma)
00227   implicit none
00228   integer, intent(in) :: ndata
00229   real, intent(inout), dimension(ndata) :: yobs
00230   real, intent(in), dimension(ndata) :: ysigma
00231   integer :: i
00232   real :: ran1,ran
00233   !
00234   do i=1,ndata
00235      call random_number(ran)
00236      ran1 = 2.*ran-1.
00237      yobs(i)= yobs(i)+ysigma(i)*ran1
00238   end do
00239 !
00240 return
00241 !
00242 end subroutine randdata
00243 !-----------------------------------------------------------------------
00244 !> @brief Generates pseudo-random (Gaussian distributtion)
00245 !> @details Modified from "Numerical Recipes in Fortran 77, second ed."
00246 !! (Press et al., Cambridge University Press)
00247 !> @param[in] idum : dummy variable (required)
00248 !> @return Pseudo-random number, drawn from a normal distribution
00249 !! (Gaussian with mean=0 and standard deviation=1)
00250 function gaussdev(idum)
00251   implicit none
00252   real :: gaussdev
00253   !  
00254   integer :: iset,idum
00255   real :: fac,gset,rsq,v1,v2,ran
00256   save iset,gset
00257   data iset/0/
00258   !
00259   rsq=0.
00260   if (idum .lt. 0.) iset=0
00261   if (iset .eq. 0) then
00262      do while (rsq .gt. 1.0 .or. rsq .eq. 0.)
00263         call random_number(ran)
00264         v1=2.*ran-1.
00265         call random_number(ran)
00266         v2=2.*ran-1.
00267         rsq=v1**2+v2**2
00268      enddo
00269      fac=sqrt(-2.*log10(rsq)/rsq)
00270      gset=v1*fac
00271      gaussdev=v2*fac
00272      iset=1
00273   else
00274      gaussdev=gset
00275      iset=0.
00276   endif
00277   !
00278   return
00279 end function gaussdev
00280 !-----------------------------------------------------------------------
00281 !> @brief Select the fittest individuals (nparents number of future
00282 !! parents) from the entire population. Based in the smallest value of
00283 !! the merit function (smaller number=fittest, e.g. @f$\chi^2@f$)
00284 !> @param[in] npar : numbr of free parameters
00285 !> @param[in] nind : number of individuals in the entire population
00286 !> @param[in] nparents: number of parents, total of fittest individuals
00287 !! to survive for the next generation
00288 !> @param[in] arrmain(npar,nind) : entire population
00289 !> @param[in,out] fitness(nind) : fitness level of each individual, 
00290 !! given by the merit function provided b the user in "tarfunc.f90".
00291 !> @param[out] arrpars(npar,nparents) : array of the fittest individuals,
00292 !! which will be parents in the following generation.
00293 subroutine pickbest(npar,nind,nparents,arrmain,fitness,arrpars)
00294   implicit none
00295   integer, intent(in) :: npar,nparents,nind
00296   real,    intent(in),  dimension(npar,nind)       :: arrmain
00297   real,    intent(inout),  dimension(nind)         :: fitness
00298   real                  ,  dimension(nind)         :: fit2
00299   real,    intent(out), dimension(npar,nparents):: arrpars
00300   integer, dimension(nind) :: index
00301   integer :: i
00302   
00303   call indexx(nind,fitness,index)
00304   do i=1,nparents
00305      arrpars(:,i)=arrmain(:,index(i))
00306      fit2(i)=fitness(index(i))
00307   end do
00308   
00309   fitness(1:nparents)=fit2(1:nparents)
00310   
00311 contains
00312 !-----------------------------------------------------------------------
00313 !> @brief indexing routine
00314 !> @details Modified from "Numerical Recipes in Fortran 77, second ed."
00315 !! (Press et al., Cambridge University Press)
00316 !> @param[in] n: number of elements in the list
00317 !> @param[in] arr(n) : array to be indexed
00318 !> @param[in] indx(n) : index list, such that arr(indx(j)) is in
00319 !> ascending order for j=1, 2, 3 ...n.  arr and n are not changed
00320   subroutine indexx(n,arr,indx)
00321     implicit none
00322     integer, intent(in)   :: n
00323     real, intent(in),  dimension(n) :: arr
00324     integer, intent(out), dimension(n) :: indx
00325     integer :: i,indxt,ir,itemp,j,jstack,k,l
00326     real    :: a
00327     integer, parameter :: m=15, nstack=50
00328     integer, dimension(nstack) :: istack
00329     !
00330     do j=1,n
00331        indx(j)=j
00332     end do
00333     jstack=0
00334     l=1
00335     ir=n
00336     do
00337        if(ir-l.lt.m)then
00338           do j=l+1,ir
00339              indxt=indx(j)
00340              a=arr(indxt)
00341              do i=j-1,l,-1
00342                 if(arr(indx(i)).le.a) exit
00343                 indx(i+1)=indx(i)
00344              end do
00345              indx(i+1)=indxt
00346           end do
00347           if(jstack.eq.0) RETURN
00348           ir=istack(jstack)
00349           l=istack(jstack-1)
00350           jstack=jstack-2
00351        else
00352           k=(l+ir)/2
00353           itemp=indx(k)
00354           indx(k)=indx(l+1)
00355           indx(l+1)=itemp
00356           if (arr(indx(l)).gt.arr(indx(ir))) then
00357              itemp=indx(l)
00358              indx(l)=indx(ir)
00359              indx(ir)=itemp
00360           end if
00361           if (arr(indx(l+1)).gt.arr(indx(ir))) then
00362              itemp=indx(l+1)
00363              indx(l+1)=indx(ir)
00364              indx(ir)=itemp
00365           end if
00366           if (arr(indx(l)).gt.arr(indx(l+1))) then
00367              itemp=indx(l)
00368              indx(l)=indx(l+1)
00369              indx(l+1)=itemp
00370           end if
00371           i=l+1
00372           j=ir
00373           indxt=indx(l+1)
00374           a=arr(indxt)
00375           do
00376              do
00377                 i=i+1
00378                 if(arr(indx(i)).ge.a) exit
00379              end do
00380              do
00381                 j=j-1
00382                 if(arr(indx(j)).le.a) exit
00383              end do
00384              if(j.lt.i) exit   
00385              itemp=indx(i)
00386              indx(i)=indx(j)
00387              indx(j)=itemp
00388           end do
00389           indx(l+1)=indx(j)
00390           indx(j)=indxt
00391           jstack=jstack+2
00392           if(jstack.gt.nstack) pause 'NSTACK to small to indexx'
00393           if(ir-i+1.ge.j-l)then
00394              istack(jstack)=ir
00395              istack(jstack-1)=i
00396              ir=j-1
00397           else
00398              istack(jstack)=j-1
00399              istack(jstack-1)=l
00400              l=i
00401           end if
00402        end if
00403     end do
00404     !
00405   end subroutine indexx
00406 
00407 end subroutine pickbest
00408 !-----------------------------------------------------------------------
00409 !> @todo Preguntarle a ary que chingaos hace esta rutina
00410 subroutine gaussian(ngaus,i,arrmain)
00411 implicit none
00412 integer :: ng,ng2
00413 real, dimension(3) :: aux
00414 integer, intent(in) :: i,ngaus
00415 real, intent(inout), dimension(:,:) :: arrmain
00416 !
00417 do ng=ngaus-1,1,-1
00418    do ng2=0,ng-1
00419       !
00420       if(arrmain(3*ng2+2,i) .gt. arrmain(3*ng2+5,i)) then
00421          aux(1:3)=arrmain(3*ng2+1:3*ng2+3,i)
00422          arrmain(3*ng2+1:3*ng2+3,i)=arrmain(3*ng2+4:3*ng2+6,i)
00423          arrmain(3*ng2+4:3*ng2+6,i)=aux(1:3)
00424       end if
00425       !
00426    enddo
00427 enddo
00428 !
00429 end subroutine gaussian
00430 !
00431 end module func
00432 !-----------------------------------------------------------------------
 All Namespaces Files Functions Variables