source: flexpart.git/src/boundcond_domainfill_mpi.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: 28.0 KB
RevLine 
[92fab65]1! SPDX-FileCopyrightText: FLEXPART 1998-2019, see flexpart_license.txt
2! SPDX-License-Identifier: GPL-3.0-or-later
[332fbbd]3
[8a65cb0]4subroutine boundcond_domainfill(itime,loutend)
[16b61a5]5!                                  i      i
6!*****************************************************************************
7!                                                                            *
8! Particles are created by this subroutine continuously throughout the       *
9! simulation at the boundaries of the domain-filling box.                    *
10! All particles carry the same amount of mass which alltogether comprises the*
11! mass of air within the box, which remains (more or less) constant.         *
12!                                                                            *
13!     Author: A. Stohl                                                       *
14!                                                                            *
15!     16 October 2002                                                        *
16!                                                                            *
17!*****************************************************************************
18!                                                                            *
19! Variables:                                                                 *
20!                                                                            *
21! nx_we(2)       grid indices for western and eastern boundary of domain-    *
22!                filling trajectory calculations                             *
23! ny_sn(2)       grid indices for southern and northern boundary of domain-  *
24!                filling trajectory calculations                             *
25!                                                                            *
26!*****************************************************************************
27!  CHANGES                                                                   
28!    08/2016 eso: MPI version:                                               
29!
30!   -Root process release particles and distributes to other processes.
31!    Temporary arrays are used, also for the non-root (receiving) processes.
32!   -The scheme can be improved by having all processes report numpart
33!    (keeping track of how many particles have left the domain), so that
34!    a proportional amount of new particles can be distributed (however
35!    we have a separate function called from timemanager that will
36!    redistribute particles among processes if there are imbalances)     
37!*****************************************************************************
[8a65cb0]38
39  use point_mod
40  use par_mod
41  use com_mod
42  use random_mod, only: ran1
43  use mpi_mod
44
45  implicit none
46
47  real :: dz,dz1,dz2,dt1,dt2,dtt,ylat,xm,cosfact,accmasst
48  integer :: itime,in,indz,indzp,i,loutend
49  integer :: j,k,ix,jy,m,indzh,indexh,minpart,ipart,mmass
[16b61a5]50  integer :: numactiveparticles, numpart_total, rel_counter
51  integer,allocatable,dimension(:) ::  numrel_mpi !, numactiveparticles_mpi
[8a65cb0]52
53  real :: windl(2),rhol(2)
54  real :: windhl(2),rhohl(2)
55  real :: windx,rhox
56  real :: deltaz,boundarea,fluxofmass
57
58  integer :: ixm,ixp,jym,jyp,indzm,mm
59  real :: pvpart,ddx,ddy,rddx,rddy,p1,p2,p3,p4,y1(2),yh1(2)
60
61  integer :: idummy = -11
[16b61a5]62  integer :: mtag
[8a65cb0]63  logical :: first_call=.true.
[16b61a5]64! Sizes of temporary arrays are maxpartfract*maxpart. Increase maxpartfract if
65! needed. 
66  real,parameter :: maxpartfract=0.1
67  integer :: tmp_size = int(maxpartfract*maxpart)
[8a65cb0]68
[16b61a5]69! Use different seed for each process
[8a65cb0]70  if (first_call) then
71    idummy=idummy+mp_seed
72    first_call=.false.
73  end if
74
75
[16b61a5]76! If domain-filling is global, no boundary conditions are needed
77!***************************************************************
[8a65cb0]78
79  if (gdomainfill) return
80
81  accmasst=0.
82  numactiveparticles=0
[16b61a5]83! Keep track of active particles on each process
84  allocate(numrel_mpi(0:mp_partgroup_np-1))
85! numactiveparticles_mpi(0:mp_partgroup_np-1)
[8a65cb0]86
[16b61a5]87! New particles to be released on each process
88  numrel_mpi(:)=0
89
90! Terminate trajectories that have left the domain, if domain-filling
91! trajectory calculation domain is not global. Done for all processes
92!********************************************************************
[8a65cb0]93
94  do i=1,numpart
95    if (itra1(i).eq.itime) then
96      if ((ytra1(i).gt.real(ny_sn(2))).or. &
97           (ytra1(i).lt.real(ny_sn(1)))) itra1(i)=-999999999
98      if (((.not.xglobal).or.(nx_we(2).ne.(nx-2))).and. &
99           ((xtra1(i).lt.real(nx_we(1))).or. &
100           (xtra1(i).gt.real(nx_we(2))))) itra1(i)=-999999999
101    endif
102    if (itra1(i).ne.-999999999) numactiveparticles= &
103         numactiveparticles+1
104  end do
[16b61a5]105!  numactiveparticles_mpi(mp_partid) = numactiveparticles
[8a65cb0]106
107
[16b61a5]108! Collect number of active particles from all processes
109  ! call MPI_Allgather(numactiveparticles, 1, MPI_INTEGER, &
110  !      &numactiveparticles_mpi, 1, MPI_INTEGER, mp_comm_used, mp_ierr)
[8a65cb0]111
112
[16b61a5]113! Total number of new releases
114  numpart_total = 0
[8a65cb0]115
116
[16b61a5]117! This section only done by root process
118!***************************************
119
120  if (lroot) then
121
122! Use separate arrays for newly released particles
123!*************************************************
124
125    allocate(itra1_tmp(tmp_size),npoint_tmp(tmp_size),nclass_tmp(tmp_size),&
126         & idt_tmp(tmp_size),itramem_tmp(tmp_size),itrasplit_tmp(tmp_size),&
127         & xtra1_tmp(tmp_size),ytra1_tmp(tmp_size),ztra1_tmp(tmp_size),&
128         & xmass1_tmp(tmp_size, maxspec))
129
130! Initialize all particles as non-existent   
131    itra1_tmp(:)=-999999999
132
133! Determine auxiliary variables for time interpolation
134!*****************************************************
[8a65cb0]135
[16b61a5]136    dt1=real(itime-memtime(1))
137    dt2=real(memtime(2)-itime)
138    dtt=1./(dt1+dt2)
[8a65cb0]139
[16b61a5]140! Initialize auxiliary variable used to search for vacant storage space
141!**********************************************************************
[8a65cb0]142
[16b61a5]143    minpart=1
[8a65cb0]144
[16b61a5]145!***************************************
146! Western and eastern boundary condition
147!***************************************
[8a65cb0]148
[16b61a5]149! Loop from south to north
150!*************************
[8a65cb0]151
[16b61a5]152    do jy=ny_sn(1),ny_sn(2)
[8a65cb0]153
[16b61a5]154! Loop over western (index 1) and eastern (index 2) boundary
155!***********************************************************
[8a65cb0]156
[16b61a5]157      do k=1,2
[8a65cb0]158
[16b61a5]159! Loop over all release locations in a column
160!********************************************
[8a65cb0]161
[16b61a5]162        do j=1,numcolumn_we(k,jy)
[8a65cb0]163
[16b61a5]164! Determine, for each release location, the area of the corresponding boundary
165!*****************************************************************************
[8a65cb0]166
[16b61a5]167          if (j.eq.1) then
168            deltaz=(zcolumn_we(k,jy,2)+zcolumn_we(k,jy,1))/2.
169          else if (j.eq.numcolumn_we(k,jy)) then
170!        deltaz=height(nz)-(zcolumn_we(k,jy,j-1)+
171!    +        zcolumn_we(k,jy,j))/2.
172! In order to avoid taking a very high column for very many particles,
173! use the deltaz from one particle below instead
174            deltaz=(zcolumn_we(k,jy,j)-zcolumn_we(k,jy,j-2))/2.
175          else
176            deltaz=(zcolumn_we(k,jy,j+1)-zcolumn_we(k,jy,j-1))/2.
177          endif
178          if ((jy.eq.ny_sn(1)).or.(jy.eq.ny_sn(2))) then
179            boundarea=deltaz*111198.5/2.*dy
180          else
181            boundarea=deltaz*111198.5*dy
[8a65cb0]182          endif
183
184
[16b61a5]185! Interpolate the wind velocity and density to the release location
186!******************************************************************
[8a65cb0]187
[16b61a5]188! Determine the model level below the release position
189!*****************************************************
[8a65cb0]190
[16b61a5]191          do i=2,nz
192            if (height(i).gt.zcolumn_we(k,jy,j)) then
193              indz=i-1
194              indzp=i
195              goto 6
196            endif
[8a65cb0]197          end do
[16b61a5]1986         continue
[8a65cb0]199
[16b61a5]200! Vertical distance to the level below and above current position
201!****************************************************************
[8a65cb0]202
[16b61a5]203          dz1=zcolumn_we(k,jy,j)-height(indz)
204          dz2=height(indzp)-zcolumn_we(k,jy,j)
205          dz=1./(dz1+dz2)
[8a65cb0]206
[16b61a5]207! Vertical and temporal interpolation
208!************************************
[8a65cb0]209
[16b61a5]210          do m=1,2
211            indexh=memind(m)
212            do in=1,2
213              indzh=indz+in-1
214              windl(in)=uu(nx_we(k),jy,indzh,indexh)
215              rhol(in)=rho(nx_we(k),jy,indzh,indexh)
216            end do
[8a65cb0]217
[16b61a5]218            windhl(m)=(dz2*windl(1)+dz1*windl(2))*dz
219            rhohl(m)=(dz2*rhol(1)+dz1*rhol(2))*dz
220          end do
221
222          windx=(windhl(1)*dt2+windhl(2)*dt1)*dtt
223          rhox=(rhohl(1)*dt2+rhohl(2)*dt1)*dtt
224
225! Calculate mass flux
226!********************
227
228          fluxofmass=windx*rhox*boundarea*real(lsynctime)
[8a65cb0]229
230
[16b61a5]231! If the mass flux is directed into the domain, add it to previous mass fluxes;
232! if it is out of the domain, set accumulated mass flux to zero
233!******************************************************************************
234
235          if (k.eq.1) then
236            if (fluxofmass.ge.0.) then
237              acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)+fluxofmass
238            else
239              acc_mass_we(k,jy,j)=0.
240            endif
[8a65cb0]241          else
[16b61a5]242            if (fluxofmass.le.0.) then
243              acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)+abs(fluxofmass)
244            else
245              acc_mass_we(k,jy,j)=0.
246            endif
[8a65cb0]247          endif
[16b61a5]248          accmasst=accmasst+acc_mass_we(k,jy,j)
249
250! If the accumulated mass exceeds half the mass that each particle shall carry,
251! one (or more) particle(s) is (are) released and the accumulated mass is
252! reduced by the mass of this (these) particle(s)
253!******************************************************************************
254
255          if (acc_mass_we(k,jy,j).ge.xmassperparticle/2.) then
256            mmass=int((acc_mass_we(k,jy,j)+xmassperparticle/2.)/ &
257                 xmassperparticle)
258            acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)- &
259                 real(mmass)*xmassperparticle
[8a65cb0]260          else
[16b61a5]261            mmass=0
[8a65cb0]262          endif
263
[16b61a5]264          do m=1,mmass
265            do ipart=minpart,maxpart
266
267! If a vacant storage space is found, attribute everything to this array element
268! TODO: for the MPI version this test can be removed, as all
269!       elements in _tmp arrays are initialized to zero
270!*****************************************************************************
271
272              if (itra1_tmp(ipart).ne.itime) then
273
274! Assign particle positions
275!**************************
276
277                xtra1_tmp(ipart)=real(nx_we(k))
278                if (jy.eq.ny_sn(1)) then
279                  ytra1_tmp(ipart)=real(jy)+0.5*ran1(idummy)
280                else if (jy.eq.ny_sn(2)) then
281                  ytra1_tmp(ipart)=real(jy)-0.5*ran1(idummy)
282                else
283                  ytra1_tmp(ipart)=real(jy)+(ran1(idummy)-.5)
[8a65cb0]284                endif
[16b61a5]285                if (j.eq.1) then
286                  ztra1_tmp(ipart)=zcolumn_we(k,jy,1)+(zcolumn_we(k,jy,2)- &
287                       zcolumn_we(k,jy,1))/4.
288                else if (j.eq.numcolumn_we(k,jy)) then
289                  ztra1_tmp(ipart)=(2.*zcolumn_we(k,jy,j)+ &
290                       zcolumn_we(k,jy,j-1)+height(nz))/4.
291                else
292                  ztra1_tmp(ipart)=zcolumn_we(k,jy,j-1)+ran1(idummy)* &
293                       (zcolumn_we(k,jy,j+1)-zcolumn_we(k,jy,j-1))
294                endif
295
296! Interpolate PV to the particle position
297!****************************************
298                ixm=int(xtra1_tmp(ipart))
299                jym=int(ytra1_tmp(ipart))
300                ixp=ixm+1
301                jyp=jym+1
302                ddx=xtra1_tmp(ipart)-real(ixm)
303                ddy=ytra1_tmp(ipart)-real(jym)
304                rddx=1.-ddx
305                rddy=1.-ddy
306                p1=rddx*rddy
307                p2=ddx*rddy
308                p3=rddx*ddy
309                p4=ddx*ddy
310                do i=2,nz
311                  if (height(i).gt.ztra1_tmp(ipart)) then
312                    indzm=i-1
313                    indzp=i
314                    goto 26
315                  endif
[8a65cb0]316                end do
[16b61a5]31726              continue
318                dz1=ztra1_tmp(ipart)-height(indzm)
319                dz2=height(indzp)-ztra1_tmp(ipart)
320                dz=1./(dz1+dz2)
321                do mm=1,2
322                  indexh=memind(mm)
323                  do in=1,2
324                    indzh=indzm+in-1
325                    y1(in)=p1*pv(ixm,jym,indzh,indexh) &
326                         +p2*pv(ixp,jym,indzh,indexh) &
327                         +p3*pv(ixm,jyp,indzh,indexh) &
328                         +p4*pv(ixp,jyp,indzh,indexh)
329                  end do
330                  yh1(mm)=(dz2*y1(1)+dz1*y1(2))*dz
331                end do
332                pvpart=(yh1(1)*dt2+yh1(2)*dt1)*dtt
333                ylat=ylat0+ytra1_tmp(ipart)*dy
334                if (ylat.lt.0.) pvpart=-1.*pvpart
335
336
337! For domain-filling option 2 (stratospheric O3), do the rest only in the stratosphere
338!*****************************************************************************
339
340                if (((ztra1_tmp(ipart).gt.3000.).and. &
341                     (pvpart.gt.pvcrit)).or.(mdomainfill.eq.1)) then
342                  nclass_tmp(ipart)=min(int(ran1(idummy)* &
343                       real(nclassunc))+1,nclassunc)
344                  numactiveparticles=numactiveparticles+1
345                  numparticlecount=numparticlecount+1
346                  npoint_tmp(ipart)=numparticlecount
347                  idt_tmp(ipart)=mintime
348                  itra1_tmp(ipart)=itime
349                  itramem_tmp(ipart)=itra1_tmp(ipart)
350                  itrasplit_tmp(ipart)=itra1_tmp(ipart)+ldirect*itsplit
351                  xmass1_tmp(ipart,1)=xmassperparticle
352                  if (mdomainfill.eq.2) xmass1_tmp(ipart,1)= &
353                       xmass1_tmp(ipart,1)*pvpart*48./29.*ozonescale/10.**9
354                else
355                  goto 71
356                endif
[8a65cb0]357
358
[16b61a5]359! Increase numpart, if necessary
360!*******************************
[8a65cb0]361
[16b61a5]362                numpart_total=max(numpart_total,ipart)
363                goto 73      ! Storage space has been found, stop searching
364              endif
365            end do
366            if (ipart.gt.tmp_size) &
367                 stop 'boundcond_domainfill_mpi.f90: too many particles required'
36873          minpart=ipart+1
36971          continue
[8a65cb0]370          end do
371
372
[16b61a5]373        end do
[8a65cb0]374      end do
375    end do
376
377
[16b61a5]378!*****************************************
379! Southern and northern boundary condition
380!*****************************************
[8a65cb0]381
[16b61a5]382! Loop from west to east
383!***********************
[8a65cb0]384
[16b61a5]385    do ix=nx_we(1),nx_we(2)
[8a65cb0]386
[16b61a5]387! Loop over southern (index 1) and northern (index 2) boundary
388!*************************************************************
[8a65cb0]389
[16b61a5]390      do k=1,2
391        ylat=ylat0+real(ny_sn(k))*dy
392        cosfact=cos(ylat*pi180)
[8a65cb0]393
[16b61a5]394! Loop over all release locations in a column
395!********************************************
[8a65cb0]396
[16b61a5]397        do j=1,numcolumn_sn(k,ix)
[8a65cb0]398
[16b61a5]399! Determine, for each release location, the area of the corresponding boundary
400!*****************************************************************************
401
402          if (j.eq.1) then
403            deltaz=(zcolumn_sn(k,ix,2)+zcolumn_sn(k,ix,1))/2.
404          else if (j.eq.numcolumn_sn(k,ix)) then
405!        deltaz=height(nz)-(zcolumn_sn(k,ix,j-1)+
406!    +        zcolumn_sn(k,ix,j))/2.
407! In order to avoid taking a very high column for very many particles,
408! use the deltaz from one particle below instead
409            deltaz=(zcolumn_sn(k,ix,j)-zcolumn_sn(k,ix,j-2))/2.
410          else
411            deltaz=(zcolumn_sn(k,ix,j+1)-zcolumn_sn(k,ix,j-1))/2.
412          endif
413          if ((ix.eq.nx_we(1)).or.(ix.eq.nx_we(2))) then
414            boundarea=deltaz*111198.5/2.*cosfact*dx
415          else
416            boundarea=deltaz*111198.5*cosfact*dx
417          endif
[8a65cb0]418
419
[16b61a5]420! Interpolate the wind velocity and density to the release location
421!******************************************************************
[8a65cb0]422
[16b61a5]423! Determine the model level below the release position
424!*****************************************************
[8a65cb0]425
[16b61a5]426          do i=2,nz
427            if (height(i).gt.zcolumn_sn(k,ix,j)) then
428              indz=i-1
429              indzp=i
430              goto 16
431            endif
432          end do
43316        continue
[8a65cb0]434
[16b61a5]435! Vertical distance to the level below and above current position
436!****************************************************************
[8a65cb0]437
[16b61a5]438          dz1=zcolumn_sn(k,ix,j)-height(indz)
439          dz2=height(indzp)-zcolumn_sn(k,ix,j)
440          dz=1./(dz1+dz2)
[8a65cb0]441
[16b61a5]442! Vertical and temporal interpolation
443!************************************
[8a65cb0]444
[16b61a5]445          do m=1,2
446            indexh=memind(m)
447            do in=1,2
448              indzh=indz+in-1
449              windl(in)=vv(ix,ny_sn(k),indzh,indexh)
450              rhol(in)=rho(ix,ny_sn(k),indzh,indexh)
451            end do
[8a65cb0]452
[16b61a5]453            windhl(m)=(dz2*windl(1)+dz1*windl(2))*dz
454            rhohl(m)=(dz2*rhol(1)+dz1*rhol(2))*dz
[8a65cb0]455          end do
456
[16b61a5]457          windx=(windhl(1)*dt2+windhl(2)*dt1)*dtt
458          rhox=(rhohl(1)*dt2+rhohl(2)*dt1)*dtt
[8a65cb0]459
[16b61a5]460! Calculate mass flux
461!********************
[8a65cb0]462
[16b61a5]463          fluxofmass=windx*rhox*boundarea*real(lsynctime)
[8a65cb0]464
[16b61a5]465! If the mass flux is directed into the domain, add it to previous mass fluxes;
466! if it is out of the domain, set accumulated mass flux to zero
467!******************************************************************************
[8a65cb0]468
[16b61a5]469          if (k.eq.1) then
470            if (fluxofmass.ge.0.) then
471              acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)+fluxofmass
472            else
473              acc_mass_sn(k,ix,j)=0.
474            endif
[8a65cb0]475          else
[16b61a5]476            if (fluxofmass.le.0.) then
477              acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)+abs(fluxofmass)
478            else
479              acc_mass_sn(k,ix,j)=0.
480            endif
[8a65cb0]481          endif
[16b61a5]482          accmasst=accmasst+acc_mass_sn(k,ix,j)
483
484! If the accumulated mass exceeds half the mass that each particle shall carry,
485! one (or more) particle(s) is (are) released and the accumulated mass is
486! reduced by the mass of this (these) particle(s)
487!******************************************************************************
488
489          if (acc_mass_sn(k,ix,j).ge.xmassperparticle/2.) then
490            mmass=int((acc_mass_sn(k,ix,j)+xmassperparticle/2.)/ &
491                 xmassperparticle)
492            acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)- &
493                 real(mmass)*xmassperparticle
[8a65cb0]494          else
[16b61a5]495            mmass=0
[8a65cb0]496          endif
497
[16b61a5]498          do m=1,mmass
499            do ipart=minpart,maxpart
500
501! If a vacant storage space is found, attribute everything to this array element
502!*****************************************************************************
[8a65cb0]503
[16b61a5]504              if (itra1_tmp(ipart).ne.itime) then
505
506! Assign particle positions
507!**************************
508
509                ytra1_tmp(ipart)=real(ny_sn(k))
510                if (ix.eq.nx_we(1)) then
511                  xtra1_tmp(ipart)=real(ix)+0.5*ran1(idummy)
512                else if (ix.eq.nx_we(2)) then
513                  xtra1_tmp(ipart)=real(ix)-0.5*ran1(idummy)
514                else
515                  xtra1_tmp(ipart)=real(ix)+(ran1(idummy)-.5)
[8a65cb0]516                endif
[16b61a5]517                if (j.eq.1) then
518                  ztra1_tmp(ipart)=zcolumn_sn(k,ix,1)+(zcolumn_sn(k,ix,2)- &
519                       zcolumn_sn(k,ix,1))/4.
520                else if (j.eq.numcolumn_sn(k,ix)) then
521                  ztra1_tmp(ipart)=(2.*zcolumn_sn(k,ix,j)+ &
522                       zcolumn_sn(k,ix,j-1)+height(nz))/4.
523                else
524                  ztra1_tmp(ipart)=zcolumn_sn(k,ix,j-1)+ran1(idummy)* &
525                       (zcolumn_sn(k,ix,j+1)-zcolumn_sn(k,ix,j-1))
526                endif
527
528
529! Interpolate PV to the particle position
530!****************************************
531                ixm=int(xtra1_tmp(ipart))
532                jym=int(ytra1_tmp(ipart))
533                ixp=ixm+1
534                jyp=jym+1
535                ddx=xtra1_tmp(ipart)-real(ixm)
536                ddy=ytra1_tmp(ipart)-real(jym)
537                rddx=1.-ddx
538                rddy=1.-ddy
539                p1=rddx*rddy
540                p2=ddx*rddy
541                p3=rddx*ddy
542                p4=ddx*ddy
543                do i=2,nz
544                  if (height(i).gt.ztra1_tmp(ipart)) then
545                    indzm=i-1
546                    indzp=i
547                    goto 126
548                  endif
[8a65cb0]549                end do
[16b61a5]550126             continue
551                dz1=ztra1_tmp(ipart)-height(indzm)
552                dz2=height(indzp)-ztra1_tmp(ipart)
553                dz=1./(dz1+dz2)
554                do mm=1,2
555                  indexh=memind(mm)
556                  do in=1,2
557                    indzh=indzm+in-1
558                    y1(in)=p1*pv(ixm,jym,indzh,indexh) &
559                         +p2*pv(ixp,jym,indzh,indexh) &
560                         +p3*pv(ixm,jyp,indzh,indexh) &
561                         +p4*pv(ixp,jyp,indzh,indexh)
562                  end do
563                  yh1(mm)=(dz2*y1(1)+dz1*y1(2))*dz
564                end do
565                pvpart=(yh1(1)*dt2+yh1(2)*dt1)*dtt
566                if (ylat.lt.0.) pvpart=-1.*pvpart
567
568
569! For domain-filling option 2 (stratospheric O3), do the rest only in the stratosphere
570!*****************************************************************************
571
572                if (((ztra1_tmp(ipart).gt.3000.).and. &
573                     (pvpart.gt.pvcrit)).or.(mdomainfill.eq.1)) then
574                  nclass_tmp(ipart)=min(int(ran1(idummy)* &
575                       real(nclassunc))+1,nclassunc)
576                  numactiveparticles=numactiveparticles+1
577                  numparticlecount=numparticlecount+1
578                  npoint_tmp(ipart)=numparticlecount
579                  idt_tmp(ipart)=mintime
580                  itra1_tmp(ipart)=itime
581                  itramem_tmp(ipart)=itra1_tmp(ipart)
582                  itrasplit_tmp(ipart)=itra1_tmp(ipart)+ldirect*itsplit
583                  xmass1_tmp(ipart,1)=xmassperparticle
584                  if (mdomainfill.eq.2) xmass1_tmp(ipart,1)= &
585                       xmass1_tmp(ipart,1)*pvpart*48./29.*ozonescale/10.**9
586                else
587                  goto 171
588                endif
[8a65cb0]589
590
[16b61a5]591! Increase numpart, if necessary
592!*******************************
593                numpart_total=max(numpart_total,ipart)
594                goto 173      ! Storage space has been found, stop searching
595              endif
596            end do
597            if (ipart.gt.tmp_size) &
598                 stop 'boundcond_domainfill.f: too many particles required'
599173         minpart=ipart+1
600171         continue
[8a65cb0]601          end do
602
603
[16b61a5]604        end do
[8a65cb0]605      end do
606    end do
[16b61a5]607
608
609! xm=0.
610! do i=1,numpart_total
611!   if (itra1_tmp(i).eq.itime) xm=xm+xmass1(i,1)
612! end do
613
614!write(*,*) itime,numactiveparticles,numparticlecount,numpart,
615!    +xm,accmasst,xm+accmasst
616
617  end if ! if lroot
618
619! Distribute the number of particles to be released
620! *************************************************
621  call MPI_Bcast(numpart_total, 1, MPI_INTEGER, id_root, mp_comm_used, mp_ierr)
622
623  do i=0, mp_partgroup_np-1
624    numrel_mpi(i) = numpart_total/mp_partgroup_np
625    if (i.lt.mod(numpart_total,mp_partgroup_np)) numrel_mpi(i) = numrel_mpi(i) + 1
[8a65cb0]626  end do
627
[16b61a5]628! Allocate temporary arrays for receiving processes
629  if (.not.lroot) then
630    allocate(itra1_tmp(numrel_mpi(mp_partid)),&
631         & npoint_tmp(numrel_mpi(mp_partid)),&
632         & nclass_tmp(numrel_mpi(mp_partid)),&
633         & idt_tmp(numrel_mpi(mp_partid)),&
634         & itramem_tmp(numrel_mpi(mp_partid)),&
635         & itrasplit_tmp(numrel_mpi(mp_partid)),&
636         & xtra1_tmp(numrel_mpi(mp_partid)),&
637         & ytra1_tmp(numrel_mpi(mp_partid)),&
638         & ztra1_tmp(numrel_mpi(mp_partid)),&
639         & xmass1_tmp(numrel_mpi(mp_partid),maxspec))
640     
641! Initialize all particles as non-existent   
642    itra1_tmp(:)=-999999999
643  end if
[8a65cb0]644
[16b61a5]645! Distribute particles
646! Keep track of released particles so far
647  rel_counter = 0
648  mtag = 1000
649
650  do i=0, mp_partgroup_np-1
651
652! For root process, nothing to do except update release count
653    if (i.eq.0) then
654      rel_counter = rel_counter + numrel_mpi(i)
655      cycle
656    end if
657     
658! Send particles from root to non-root processes
659    if (lroot.and.numrel_mpi(i).gt.0) then
660
661      call MPI_SEND(nclass_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
662           &numrel_mpi(i),MPI_INTEGER,i,mtag+1*i,mp_comm_used,mp_ierr)
663
664      call MPI_SEND(npoint_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
665           &numrel_mpi(i),MPI_INTEGER,i,mtag+2*i,mp_comm_used,mp_ierr)
666
667      call MPI_SEND(itra1_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
668           &numrel_mpi(i),MPI_INTEGER,i,mtag+3*i,mp_comm_used,mp_ierr)
669
670      call MPI_SEND(idt_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
671           &numrel_mpi(i),MPI_INTEGER,i,mtag+4*i,mp_comm_used,mp_ierr)
672
673      call MPI_SEND(itramem_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
674           &numrel_mpi(i),MPI_INTEGER,i,mtag+5*i,mp_comm_used,mp_ierr)
675
676      call MPI_SEND(itrasplit_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
677           &numrel_mpi(i),MPI_INTEGER,i,mtag+6*i,mp_comm_used,mp_ierr)
678
679      call MPI_SEND(xtra1_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
680           &numrel_mpi(i),mp_dp,i,mtag+7*i,mp_comm_used,mp_ierr)
681
682      call MPI_SEND(ytra1_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
683           &numrel_mpi(i),mp_dp,i,mtag+8*i,mp_comm_used,mp_ierr)
684
685      call MPI_SEND(ztra1_tmp(rel_counter+1:rel_counter+numrel_mpi(i)),&
686           &numrel_mpi(i),mp_sp,i,mtag+9*i,mp_comm_used,mp_ierr)
687
688      do j=1,nspec
689        call MPI_SEND(xmass1_tmp(rel_counter+1:rel_counter+numrel_mpi(i),j),&
690             &numrel_mpi(i),mp_sp,i,mtag+(9+j)*i,mp_comm_used,mp_ierr)
691      end do
692
693! Non-root processes issue receive requests
694    else if (i.eq.mp_partid.and.numrel_mpi(i).gt.0) then
695      call MPI_RECV(nclass_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
696           &MPI_INTEGER,id_root,mtag+1*i,mp_comm_used,mp_status,mp_ierr)
697
698      call MPI_RECV(npoint_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
699           &MPI_INTEGER,id_root,mtag+2*i,mp_comm_used,mp_status,mp_ierr)
700
701      call MPI_RECV(itra1_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
702           &MPI_INTEGER,id_root,mtag+3*i,mp_comm_used,mp_status,mp_ierr)
703
704      call MPI_RECV(idt_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
705           &MPI_INTEGER,id_root,mtag+4*i,mp_comm_used,mp_status,mp_ierr)
706
707      call MPI_RECV(itramem_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
708           &MPI_INTEGER,id_root,mtag+5*i,mp_comm_used,mp_status,mp_ierr)
709
710      call MPI_RECV(itrasplit_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
711           &MPI_INTEGER,id_root,mtag+6*i,mp_comm_used,mp_status,mp_ierr)
712
713      call MPI_RECV(xtra1_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
714           &mp_dp,id_root,mtag+7*i,mp_comm_used,mp_status,mp_ierr)
715
716      call MPI_RECV(ytra1_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
717           &mp_dp,id_root,mtag+8*i,mp_comm_used,mp_status,mp_ierr)
718
719      call MPI_RECV(ztra1_tmp(1:numrel_mpi(i)),numrel_mpi(i),&
720           &mp_sp,id_root,mtag+9*i,mp_comm_used,mp_status,mp_ierr)
721
722      do j=1,nspec
723        call MPI_RECV(xmass1_tmp(1:numrel_mpi(i),j),numrel_mpi(i),&
724             &mp_sp,id_root,mtag+(9+j)*i,mp_comm_used,mp_status,mp_ierr)
725
726      end do
727    end if
728    rel_counter = rel_counter + numrel_mpi(i)
[8a65cb0]729  end do
730
[16b61a5]731! Find free storage space for the new particles.
732! This section is independent of the redistribution scheme used
733! ********************************************************************
[8a65cb0]734
[16b61a5]735! Keep track of released particles so far
736  minpart=1
737   
738! The algorithm should be correct also for root process
739  do i=1, numrel_mpi(mp_partid)
740    do ipart=minpart, maxpart
741      if (itra1(ipart).ne.itime) then
742        itra1(ipart) = itra1_tmp(i)
743        npoint(ipart) = npoint_tmp(i)
744        nclass(ipart) = nclass_tmp(i)
745        idt(ipart) = idt_tmp(i)
746        itramem(ipart) = itramem_tmp(i)
747        itrasplit(ipart) = itrasplit_tmp(i)
748        xtra1(ipart) = xtra1_tmp(i)
749        ytra1(ipart) = ytra1_tmp(i)
750        ztra1(ipart) = ztra1_tmp(i)
751        xmass1(ipart,:) = xmass1_tmp(i,:)
752! Increase numpart, if necessary
753        numpart=max(numpart,ipart)
754        goto 200 ! Storage space has been found, stop searching
755      end if
756    end do
757200 minpart=ipart+1
758  end do
[8a65cb0]759
[16b61a5]760! If particles shall be dumped, then accumulated masses at the domain boundaries
761! must be dumped, too, to be used for later runs
762!*****************************************************************************
[8a65cb0]763
764  if ((ipout.gt.0).and.(itime.eq.loutend)) then
[7999df47]765    if (lroot) then
[16b61a5]766      call mpif_mtime('iotime',0)
[7999df47]767      open(unitboundcond,file=path(2)(1:length(2))//'boundcond.bin', &
768           form='unformatted')
769      write(unitboundcond) numcolumn_we,numcolumn_sn, &
770           zcolumn_we,zcolumn_sn,acc_mass_we,acc_mass_sn
771      close(unitboundcond)
[16b61a5]772      call mpif_mtime('iotime',1)
[7999df47]773    end if
[8a65cb0]774  endif
775
[16b61a5]776! Deallocate temporary arrays
777  deallocate(itra1_tmp,npoint_tmp,nclass_tmp,idt_tmp,itramem_tmp,itrasplit_tmp,&
778       & xtra1_tmp,ytra1_tmp,ztra1_tmp,xmass1_tmp,numrel_mpi)
779! numactiveparticles_mpi
780
781
[8a65cb0]782end subroutine boundcond_domainfill
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG