![]() |
AGA V1
Asexual Genetic Algorithm Version 1.0
|
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 !-----------------------------------------------------------------------
1.7.4