source: branches/flexpart91_hasod/src_parallel/releaseparticles.f90 @ 8

Last change on this file since 8 was 8, checked in by hasod, 11 years ago

Added parallel version of Flexpart91

File size: 16.6 KB
Line 
1!**********************************************************************
2! Copyright 1998,1999,2000,2001,2002,2005,2007,2008,2009,2010         *
3! Andreas Stohl, Petra Seibert, A. Frank, Gerhard Wotawa,             *
4! Caroline Forster, Sabine Eckhardt, John Burkhart, Harald Sodemann   *
5!                                                                     *
6! This file is part of FLEXPART.                                      *
7!                                                                     *
8! FLEXPART is free software: you can redistribute it and/or modify    *
9! it under the terms of the GNU General Public License as published by*
10! the Free Software Foundation, either version 3 of the License, or   *
11! (at your option) any later version.                                 *
12!                                                                     *
13! FLEXPART is distributed in the hope that it will be useful,         *
14! but WITHOUT ANY WARRANTY; without even the implied warranty of      *
15! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       *
16! GNU General Public License for more details.                        *
17!                                                                     *
18! You should have received a copy of the GNU General Public License   *
19! along with FLEXPART.  If not, see <http://www.gnu.org/licenses/>.   *
20!**********************************************************************
21
22subroutine releaseparticles(itime)
23  !                              o
24  !*****************************************************************************
25  !                                                                            *
26  !     This subroutine releases particles from the release locations.         *
27  !                                                                            *
28  !     It searches for a "vacant" storage space and assigns all particle      *
29  !     information to that space. A space is vacant either when no particle   *
30  !     is yet assigned to it, or when it's particle is expired and, thus,     *
31  !     the storage space is made available to a new particle.                 *
32  !                                                                            *
33  !     Author: A. Stohl                                                       *
34  !                                                                            *
35  !     29 June 2002                                                           *
36  !                                                                            *
37  !*****************************************************************************
38  !                                                                            *
39  ! Variables:                                                                 *
40  ! itime [s]            current time                                          *
41  ! ireleasestart, ireleaseend          start and end times of all releases    *
42  ! npart(maxpoint)      number of particles to be released in total           *
43  ! numrel               number of particles to be released during this time   *
44  !                      step                                                  *
45  !                                                                            *
46  !*****************************************************************************
47
48  use point_mod
49  use xmass_mod
50  use par_mod
51  use com_mod
52  use random_mod, only: ran1
53
54  implicit none
55
56  !real xaux,yaux,zaux,ran1,rfraction,xmasssave(maxpoint)
57  real :: xaux,yaux,zaux,rfraction
58  real :: topo,rhoaux(2),r,t,rhoout,ddx,ddy,rddx,rddy,p1,p2,p3,p4
59  real :: dz1,dz2,dz,xtn,ytn,xlonav,timecorrect(maxspec),press,pressold
60  real :: presspart,average_timecorrect
61  integer :: itime,numrel,i,j,k,n,ix,jy,ixp,jyp,ipart,minpart,ii
62  integer :: indz,indzp,kz,ngrid
63  integer :: nweeks,ndayofweek,nhour,jjjjmmdd,ihmmss,mm
64  real(kind=dp) :: juldate,julmonday,jul,jullocal,juldiff
65  real,parameter :: eps=nxmax/3.e5,eps2=1.e-6
66
67  integer :: idummy = -7
68  !save idummy,xmasssave
69  !data idummy/-7/,xmasssave/maxpoint*0./
70
71
72  ! Determine the actual date and time in Greenwich (i.e., UTC + correction for daylight savings time)
73  !*****************************************************************************
74
75  julmonday=juldate(19000101,0)          ! this is a Monday
76  jul=bdate+real(itime,kind=dp)/86400._dp    ! this is the current day
77  call caldate(jul,jjjjmmdd,ihmmss)
78  mm=(jjjjmmdd-10000*(jjjjmmdd/10000))/100
79  if ((mm.ge.4).and.(mm.le.9)) jul=jul+1._dp/24._dp   ! daylight savings time in summer
80
81
82  ! For every release point, check whether we are in the release time interval
83  !***************************************************************************
84
85  minpart=1
86  do i=1,numpoint
87    if ((itime.ge.ireleasestart(i)).and. &! are we within release interval?
88         (itime.le.ireleaseend(i))) then
89
90  ! Determine the local day and time
91  !*********************************
92
93      xlonav=xlon0+(xpoint2(i)+xpoint1(i))/2.*dx  ! longitude needed to determine local time
94      if (xlonav.lt.-180.) xlonav=xlonav+360.
95      if (xlonav.gt.180.) xlonav=xlonav-360.
96      jullocal=jul+real(xlonav,kind=dp)/360._dp   ! correct approximately for time zone to obtain local time
97
98      juldiff=jullocal-julmonday
99      nweeks=int(juldiff/7._dp)
100      juldiff=juldiff-real(nweeks,kind=dp)*7._dp
101      ndayofweek=int(juldiff)+1              ! this is the current day of week, starting with Monday
102      nhour=nint((juldiff-real(ndayofweek-1,kind=dp))*24._dp)    ! this is the current hour
103      if (nhour.eq.0) then
104        nhour=24
105        ndayofweek=ndayofweek-1
106        if (ndayofweek.eq.0) ndayofweek=7
107      endif
108
109  ! Calculate a species- and time-dependent correction factor, distinguishing between
110  ! area (those with release starting at surface) and point (release starting above surface) sources
111  ! Also, calculate an average time correction factor (species independent)
112  !*****************************************************************************
113      average_timecorrect=0.
114      do k=1,nspec
115        if (zpoint1(i).gt.0.5) then      ! point source
116          timecorrect(k)=point_hour(k,nhour)*point_dow(k,ndayofweek)
117        else                             ! area source
118          timecorrect(k)=area_hour(k,nhour)*area_dow(k,ndayofweek)
119        endif
120        average_timecorrect=average_timecorrect+timecorrect(k)
121      end do
122      average_timecorrect=average_timecorrect/real(nspec)
123
124  ! Determine number of particles to be released this time; at start and at end of release,
125  ! only half the particles are released
126  !*****************************************************************************
127
128      if (ireleasestart(i).ne.ireleaseend(i)) then
129        rfraction=abs(real(npart(i))*real(lsynctime)/ &
130             real(ireleaseend(i)-ireleasestart(i)))
131        if ((itime.eq.ireleasestart(i)).or. &
132             (itime.eq.ireleaseend(i))) rfraction=rfraction/2.
133
134  ! Take the species-average time correction factor in order to scale the
135  ! number of particles released this time
136  !**********************************************************************
137        rfraction=rfraction*average_timecorrect
138
139        rfraction=rfraction+xmasssave(i)  ! number to be released at this time
140        numrel=int(rfraction)
141        xmasssave(i)=rfraction-real(numrel)
142      else
143        numrel=npart(i)
144      endif
145
146      xaux=xpoint2(i)-xpoint1(i)
147      yaux=ypoint2(i)-ypoint1(i)
148      zaux=zpoint2(i)-zpoint1(i)
149      do j=1,numrel                       ! loop over particles to be released this time
150        do ipart=minpart,maxpart          ! search for free storage space
151
152  ! If a free storage space is found, attribute everything to this array element
153  !*****************************************************************************
154
155          if (itra1(ipart).ne.itime) then
156
157  ! Particle coordinates are determined by using a random position within the release volume
158  !*****************************************************************************
159
160  ! Determine horizontal particle position
161  !***************************************
162
163            xtra1(ipart)=xpoint1(i)+ran1(idummy)*xaux
164            if (xglobal) then
165              if (xtra1(ipart).gt.real(nxmin1)) xtra1(ipart)= &
166                   xtra1(ipart)-real(nxmin1, dp)
167              if (xtra1(ipart).lt.0.) xtra1(ipart)= &
168                   xtra1(ipart)+real(nxmin1, dp)
169            endif
170            ytra1(ipart)=ypoint1(i)+ran1(idummy)*yaux
171
172  ! Assign mass to particle: Total mass divided by total number of particles.
173  ! Time variation has partly been taken into account already by a species-average
174  ! correction factor, by which the number of particles released this time has been
175  ! scaled. Adjust the mass per particle by the species-dependent time correction factor
176  ! divided by the species-average one
177  !*****************************************************************************
178            do k=1,nspec
179               xmass1(ipart,k)=xmass(i,k)/real(npart(i)) &
180                    *timecorrect(k)/average_timecorrect
181  !            write (*,*) 'xmass1: ',xmass1(ipart,k),ipart,k
182  ! Assign certain properties to particle
183  !**************************************
184            end do
185            nclass(ipart)=min(int(ran1(idummy)*real(nclassunc))+1, &
186                 nclassunc)
187            numparticlecount=numparticlecount+1
188            if (mquasilag.eq.0) then
189              npoint(ipart)=i
190            else
191              npoint(ipart)=numparticlecount
192            endif
193            idt(ipart)=mintime               ! first time step
194            itra1(ipart)=itime
195            itramem(ipart)=itra1(ipart)
196            itrasplit(ipart)=itra1(ipart)+ldirect*itsplit
197
198
199  ! Determine vertical particle position
200  !*************************************
201
202            ztra1(ipart)=zpoint1(i)+ran1(idummy)*zaux
203
204  ! Interpolation of topography and density
205  !****************************************
206
207  ! Determine the nest we are in
208  !*****************************
209
210            ngrid=0
211            do k=numbnests,1,-1
212              if ((xtra1(ipart).gt.xln(k)+eps).and. &
213                   (xtra1(ipart).lt.xrn(k)-eps).and. &
214                   (ytra1(ipart).gt.yln(k)+eps).and. &
215                   (ytra1(ipart).lt.yrn(k)-eps)) then
216                ngrid=k
217                goto 43
218              endif
219            end do
22043          continue
221
222  ! Determine (nested) grid coordinates and auxiliary parameters used for interpolation
223  !*****************************************************************************
224
225            if (ngrid.gt.0) then
226              xtn=(real(xtra1(ipart))-xln(ngrid))*xresoln(ngrid)
227              ytn=(real(ytra1(ipart))-yln(ngrid))*yresoln(ngrid)
228              ix=int(xtn)
229              jy=int(ytn)
230              ddy=ytn-real(jy)
231              ddx=xtn-real(ix)
232            else
233              ix=int(xtra1(ipart))
234              jy=int(ytra1(ipart))
235              ddy=real(ytra1(ipart))-real(jy)
236              ddx=real(xtra1(ipart))-real(ix)
237            endif
238            ixp=ix+1
239            jyp=jy+1
240            rddx=1.-ddx
241            rddy=1.-ddy
242            p1=rddx*rddy
243            p2=ddx*rddy
244            p3=rddx*ddy
245            p4=ddx*ddy
246
247            if (ngrid.gt.0) then
248              topo=p1*oron(ix ,jy ,ngrid) &
249                   + p2*oron(ixp,jy ,ngrid) &
250                   + p3*oron(ix ,jyp,ngrid) &
251                   + p4*oron(ixp,jyp,ngrid)
252            else
253              topo=p1*oro(ix ,jy) &
254                   + p2*oro(ixp,jy) &
255                   + p3*oro(ix ,jyp) &
256                   + p4*oro(ixp,jyp)
257            endif
258
259  ! If starting height is in pressure coordinates, retrieve pressure profile and convert zpart1 to meters
260  !*****************************************************************************
261            if (kindz(i).eq.3) then
262              presspart=ztra1(ipart)
263              do kz=1,nz
264                if (ngrid.gt.0) then
265                  r=p1*rhon(ix ,jy ,kz,2,ngrid) &
266                       +p2*rhon(ixp,jy ,kz,2,ngrid) &
267                       +p3*rhon(ix ,jyp,kz,2,ngrid) &
268                       +p4*rhon(ixp,jyp,kz,2,ngrid)
269                  t=p1*ttn(ix ,jy ,kz,2,ngrid) &
270                       +p2*ttn(ixp,jy ,kz,2,ngrid) &
271                       +p3*ttn(ix ,jyp,kz,2,ngrid) &
272                       +p4*ttn(ixp,jyp,kz,2,ngrid)
273                else
274                  r=p1*rho(ix ,jy ,kz,2) &
275                       +p2*rho(ixp,jy ,kz,2) &
276                       +p3*rho(ix ,jyp,kz,2) &
277                       +p4*rho(ixp,jyp,kz,2)
278                  t=p1*tt(ix ,jy ,kz,2) &
279                       +p2*tt(ixp,jy ,kz,2) &
280                       +p3*tt(ix ,jyp,kz,2) &
281                       +p4*tt(ixp,jyp,kz,2)
282                endif
283                press=r*r_air*t/100.
284                if (kz.eq.1) pressold=press
285
286                if (press.lt.presspart) then
287                  if (kz.eq.1) then
288                    ztra1(ipart)=height(1)/2.
289                  else
290                    dz1=pressold-presspart
291                    dz2=presspart-press
292                    ztra1(ipart)=(height(kz-1)*dz2+height(kz)*dz1) &
293                         /(dz1+dz2)
294                  endif
295                  goto 71
296                endif
297                pressold=press
298              end do
29971            continue
300            endif
301
302  ! If release positions are given in meters above sea level, subtract the
303  ! topography from the starting height
304  !***********************************************************************
305
306            if (kindz(i).eq.2) ztra1(ipart)=ztra1(ipart)-topo
307            if (ztra1(ipart).lt.eps2) ztra1(ipart)=eps2   ! Minimum starting height is eps2
308            if (ztra1(ipart).gt.height(nz)-0.5) ztra1(ipart)= &
309                 height(nz)-0.5 ! Maximum starting height is uppermost level - 0.5 meters
310
311  ! For special simulations, multiply particle concentration air density;
312  ! Simply take the 2nd field in memory to do this (accurate enough)
313  !***********************************************************************
314  !AF IND_SOURCE switches between different units for concentrations at the source
315  !Af    NOTE that in backward simulations the release of particles takes place at the
316  !Af         receptor and the sampling at the source.
317  !Af          1="mass"
318  !Af          2="mass mixing ratio"
319  !Af IND_RECEPTOR switches between different units for concentrations at the receptor
320  !Af          1="mass"
321  !Af          2="mass mixing ratio"
322
323  !Af switches for the releasefile:
324  !Af IND_REL =  1 : xmass * rho
325  !Af IND_REL =  0 : xmass * 1
326
327  !Af ind_rel is defined in readcommand.f
328
329            if (ind_rel .eq. 1) then
330
331  ! Interpolate the air density
332  !****************************
333
334              do ii=2,nz
335                if (height(ii).gt.ztra1(ipart)) then
336                  indz=ii-1
337                  indzp=ii
338                  goto 6
339                endif
340              end do
3416             continue
342
343              dz1=ztra1(ipart)-height(indz)
344              dz2=height(indzp)-ztra1(ipart)
345              dz=1./(dz1+dz2)
346
347              if (ngrid.gt.0) then
348                do n=1,2
349                  rhoaux(n)=p1*rhon(ix ,jy ,indz+n-1,2,ngrid) &
350                       +p2*rhon(ixp,jy ,indz+n-1,2,ngrid) &
351                       +p3*rhon(ix ,jyp,indz+n-1,2,ngrid) &
352                       +p4*rhon(ixp,jyp,indz+n-1,2,ngrid)
353                end do
354              else
355                do n=1,2
356                  rhoaux(n)=p1*rho(ix ,jy ,indz+n-1,2) &
357                       +p2*rho(ixp,jy ,indz+n-1,2) &
358                       +p3*rho(ix ,jyp,indz+n-1,2) &
359                       +p4*rho(ixp,jyp,indz+n-1,2)
360                end do
361              endif
362              rhoout=(dz2*rhoaux(1)+dz1*rhoaux(2))*dz
363              rho_rel(i)=rhoout
364
365
366  ! Multiply "mass" (i.e., mass mixing ratio in forward runs) with density
367  !********************************************************************
368
369              do k=1,nspec
370                xmass1(ipart,k)=xmass1(ipart,k)*rhoout
371              end do
372            endif
373
374
375            numpart=max(numpart,ipart)
376            goto 34      ! Storage space has been found, stop searching
377          endif
378        end do
379        if (ipart.gt.maxpart) goto 996
380
38134      minpart=ipart+1
382      end do
383      endif
384  end do
385
386
387  return
388
389996   continue
390  write(*,*) '#####################################################'
391  write(*,*) '#### FLEXPART MODEL SUBROUTINE RELEASEPARTICLES: ####'
392  write(*,*) '####                                             ####'
393  write(*,*) '#### ERROR - TOTAL NUMBER OF PARTICLES REQUIRED  ####'
394  write(*,*) '#### EXCEEDS THE MAXIMUM ALLOWED NUMBER. REDUCE  ####'
395  write(*,*) '#### EITHER NUMBER OF PARTICLES PER RELEASE POINT####'
396  write(*,*) '#### OR REDUCE NUMBER OF RELEASE POINTS.         ####'
397  write(*,*) '#####################################################'
398  stop
399
400end subroutine releaseparticles
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG