source: flexpart.git/src/releaseparticles.f90

10.4.1_peseiGFS_025bugfixes+enhancementsdevrelease-10release-10.4.1scaling-bug
Last change on this file was 92fab65, checked in by Ignacio Pisso <ip@…>, 4 years ago

add SPDX-License-Identifier to all .f90 files

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