Index: src/boundcond_domainfill.f90
===================================================================
--- src/boundcond_domainfill.f90	(revision e200b7adb07d4dfa7bf42f7cb43e0c85b4dbf894)
+++ src/boundcond_domainfill.f90	(revision e200b7adb07d4dfa7bf42f7cb43e0c85b4dbf894)
@@ -0,0 +1,588 @@
+!**********************************************************************
+! Copyright 1998,1999,2000,2001,2002,2005,2007,2008,2009,2010         *
+! Andreas Stohl, Petra Seibert, A. Frank, Gerhard Wotawa,             *
+! Caroline Forster, Sabine Eckhardt, John Burkhart, Harald Sodemann   *
+!                                                                     *
+! This file is part of FLEXPART.                                      *
+!                                                                     *
+! FLEXPART is free software: you can redistribute it and/or modify    *
+! it under the terms of the GNU General Public License as published by*
+! the Free Software Foundation, either version 3 of the License, or   *
+! (at your option) any later version.                                 *
+!                                                                     *
+! FLEXPART is distributed in the hope that it will be useful,         *
+! but WITHOUT ANY WARRANTY; without even the implied warranty of      *
+! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       *
+! GNU General Public License for more details.                        *
+!                                                                     *
+! You should have received a copy of the GNU General Public License   *
+! along with FLEXPART.  If not, see <http://www.gnu.org/licenses/>.   *
+!**********************************************************************
+
+subroutine boundcond_domainfill(itime,loutend)
+  !                                  i      i
+  !*****************************************************************************
+  !                                                                            *
+  ! Particles are created by this subroutine continuously throughout the       *
+  ! simulation at the boundaries of the domain-filling box.                    *
+  ! All particles carry the same amount of mass which alltogether comprises the*
+  ! mass of air within the box, which remains (more or less) constant.         *
+  !                                                                            *
+  !     Author: A. Stohl                                                       *
+  !                                                                            *
+  !     16 October 2002                                                        *
+  !                                                                            *
+  !*****************************************************************************
+  !                                                                            *
+  ! Variables:                                                                 *
+  !                                                                            *
+  ! nx_we(2)       grid indices for western and eastern boundary of domain-    *
+  !                filling trajectory calculations                             *
+  ! ny_sn(2)       grid indices for southern and northern boundary of domain-  *
+  !                filling trajectory calculations                             *
+  !                                                                            *
+  !*****************************************************************************
+
+  use point_mod
+  use par_mod
+  use com_mod
+
+  implicit none
+
+  real :: dz,dz1,dz2,ran1,dt1,dt2,dtt,ylat,xm,cosfact,accmasst
+  integer :: itime,in,indz,indzp,i,loutend
+  integer :: j,k,ix,jy,m,indzh,indexh,minpart,ipart,mmass
+  integer :: numactiveparticles
+
+  real :: windl(2),rhol(2)
+  real :: windhl(2),rhohl(2)
+  real :: windx,rhox
+  real :: deltaz,boundarea,fluxofmass
+
+  integer :: ixm,ixp,jym,jyp,indzm,mm
+  real :: pvpart,ddx,ddy,rddx,rddy,p1,p2,p3,p4,y1(2),yh1(2)
+
+  integer :: idummy = -11
+
+
+  ! If domain-filling is global, no boundary conditions are needed
+  !***************************************************************
+
+  if (gdomainfill) return
+
+  accmasst=0.
+  numactiveparticles=0
+
+  ! Terminate trajectories that have left the domain, if domain-filling
+  ! trajectory calculation domain is not global
+  !********************************************************************
+
+  do i=1,numpart
+    if (itra1(i).eq.itime) then
+      if ((ytra1(i).gt.real(ny_sn(2))).or. &
+           (ytra1(i).lt.real(ny_sn(1)))) itra1(i)=-999999999
+      if (((.not.xglobal).or.(nx_we(2).ne.(nx-2))).and. &
+           ((xtra1(i).lt.real(nx_we(1))).or. &
+           (xtra1(i).gt.real(nx_we(2))))) itra1(i)=-999999999
+    endif
+    if (itra1(i).ne.-999999999) numactiveparticles= &
+         numactiveparticles+1
+  end do
+
+
+  ! Determine auxiliary variables for time interpolation
+  !*****************************************************
+
+  dt1=real(itime-memtime(1))
+  dt2=real(memtime(2)-itime)
+  dtt=1./(dt1+dt2)
+
+  ! Initialize auxiliary variable used to search for vacant storage space
+  !**********************************************************************
+
+  minpart=1
+
+  !***************************************
+  ! Western and eastern boundary condition
+  !***************************************
+
+  ! Loop from south to north
+  !*************************
+
+  do jy=ny_sn(1),ny_sn(2)
+
+  ! Loop over western (index 1) and eastern (index 2) boundary
+  !***********************************************************
+
+    do k=1,2
+
+  ! Loop over all release locations in a column
+  !********************************************
+
+      do j=1,numcolumn_we(k,jy)
+
+  ! Determine, for each release location, the area of the corresponding boundary
+  !*****************************************************************************
+
+        if (j.eq.1) then
+          deltaz=(zcolumn_we(k,jy,2)+zcolumn_we(k,jy,1))/2.
+        else if (j.eq.numcolumn_we(k,jy)) then
+  !        deltaz=height(nz)-(zcolumn_we(k,jy,j-1)+
+  !    +        zcolumn_we(k,jy,j))/2.
+  ! In order to avoid taking a very high column for very many particles,
+  ! use the deltaz from one particle below instead
+          deltaz=(zcolumn_we(k,jy,j)-zcolumn_we(k,jy,j-2))/2.
+        else
+          deltaz=(zcolumn_we(k,jy,j+1)-zcolumn_we(k,jy,j-1))/2.
+        endif
+        if ((jy.eq.ny_sn(1)).or.(jy.eq.ny_sn(2))) then
+          boundarea=deltaz*111198.5/2.*dy
+        else
+          boundarea=deltaz*111198.5*dy
+        endif
+
+
+  ! Interpolate the wind velocity and density to the release location
+  !******************************************************************
+
+  ! Determine the model level below the release position
+  !*****************************************************
+
+        do i=2,nz
+          if (height(i).gt.zcolumn_we(k,jy,j)) then
+            indz=i-1
+            indzp=i
+            goto 6
+          endif
+        end do
+6       continue
+
+  ! Vertical distance to the level below and above current position
+  !****************************************************************
+
+        dz1=zcolumn_we(k,jy,j)-height(indz)
+        dz2=height(indzp)-zcolumn_we(k,jy,j)
+        dz=1./(dz1+dz2)
+
+  ! Vertical and temporal interpolation
+  !************************************
+
+        do m=1,2
+          indexh=memind(m)
+          do in=1,2
+            indzh=indz+in-1
+            windl(in)=uu(nx_we(k),jy,indzh,indexh)
+            rhol(in)=rho(nx_we(k),jy,indzh,indexh)
+          end do
+
+          windhl(m)=(dz2*windl(1)+dz1*windl(2))*dz
+          rhohl(m)=(dz2*rhol(1)+dz1*rhol(2))*dz
+        end do
+
+        windx=(windhl(1)*dt2+windhl(2)*dt1)*dtt
+        rhox=(rhohl(1)*dt2+rhohl(2)*dt1)*dtt
+
+  ! Calculate mass flux
+  !********************
+
+        fluxofmass=windx*rhox*boundarea*real(lsynctime)
+
+
+  ! If the mass flux is directed into the domain, add it to previous mass fluxes;
+  ! if it is out of the domain, set accumulated mass flux to zero
+  !******************************************************************************
+
+        if (k.eq.1) then
+          if (fluxofmass.ge.0.) then
+            acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)+fluxofmass
+          else
+            acc_mass_we(k,jy,j)=0.
+          endif
+        else
+          if (fluxofmass.le.0.) then
+            acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)+abs(fluxofmass)
+          else
+            acc_mass_we(k,jy,j)=0.
+          endif
+        endif
+        accmasst=accmasst+acc_mass_we(k,jy,j)
+
+  ! If the accumulated mass exceeds half the mass that each particle shall carry,
+  ! one (or more) particle(s) is (are) released and the accumulated mass is
+  ! reduced by the mass of this (these) particle(s)
+  !******************************************************************************
+
+        if (acc_mass_we(k,jy,j).ge.xmassperparticle/2.) then
+          mmass=int((acc_mass_we(k,jy,j)+xmassperparticle/2.)/ &
+               xmassperparticle)
+          acc_mass_we(k,jy,j)=acc_mass_we(k,jy,j)- &
+               real(mmass)*xmassperparticle
+        else
+          mmass=0
+        endif
+
+        do m=1,mmass
+          do ipart=minpart,maxpart
+
+  ! If a vacant storage space is found, attribute everything to this array element
+  !*****************************************************************************
+
+            if (itra1(ipart).ne.itime) then
+
+  ! Assign particle positions
+  !**************************
+
+              xtra1(ipart)=real(nx_we(k))
+              if (jy.eq.ny_sn(1)) then
+                ytra1(ipart)=real(jy)+0.5*ran1(idummy)
+              else if (jy.eq.ny_sn(2)) then
+                ytra1(ipart)=real(jy)-0.5*ran1(idummy)
+              else
+                ytra1(ipart)=real(jy)+(ran1(idummy)-.5)
+              endif
+              if (j.eq.1) then
+                ztra1(ipart)=zcolumn_we(k,jy,1)+(zcolumn_we(k,jy,2)- &
+                     zcolumn_we(k,jy,1))/4.
+              else if (j.eq.numcolumn_we(k,jy)) then
+                ztra1(ipart)=(2.*zcolumn_we(k,jy,j)+ &
+                     zcolumn_we(k,jy,j-1)+height(nz))/4.
+              else
+                ztra1(ipart)=zcolumn_we(k,jy,j-1)+ran1(idummy)* &
+                     (zcolumn_we(k,jy,j+1)-zcolumn_we(k,jy,j-1))
+              endif
+
+  ! Interpolate PV to the particle position
+  !****************************************
+              ixm=int(xtra1(ipart))
+              jym=int(ytra1(ipart))
+              ixp=ixm+1
+              jyp=jym+1
+              ddx=xtra1(ipart)-real(ixm)
+              ddy=ytra1(ipart)-real(jym)
+              rddx=1.-ddx
+              rddy=1.-ddy
+              p1=rddx*rddy
+              p2=ddx*rddy
+              p3=rddx*ddy
+              p4=ddx*ddy
+              do i=2,nz
+                if (height(i).gt.ztra1(ipart)) then
+                  indzm=i-1
+                  indzp=i
+                  goto 26
+                endif
+              end do
+26            continue
+              dz1=ztra1(ipart)-height(indzm)
+              dz2=height(indzp)-ztra1(ipart)
+              dz=1./(dz1+dz2)
+              do mm=1,2
+                indexh=memind(mm)
+                do in=1,2
+                  indzh=indzm+in-1
+                  y1(in)=p1*pv(ixm,jym,indzh,indexh) &
+                       +p2*pv(ixp,jym,indzh,indexh) &
+                       +p3*pv(ixm,jyp,indzh,indexh) &
+                       +p4*pv(ixp,jyp,indzh,indexh)
+                end do
+                yh1(mm)=(dz2*y1(1)+dz1*y1(2))*dz
+              end do
+              pvpart=(yh1(1)*dt2+yh1(2)*dt1)*dtt
+              ylat=ylat0+ytra1(ipart)*dy
+              if (ylat.lt.0.) pvpart=-1.*pvpart
+
+
+  ! For domain-filling option 2 (stratospheric O3), do the rest only in the stratosphere
+  !*****************************************************************************
+
+              if (((ztra1(ipart).gt.3000.).and. &
+                   (pvpart.gt.pvcrit)).or.(mdomainfill.eq.1)) then
+                nclass(ipart)=min(int(ran1(idummy)* &
+                     real(nclassunc))+1,nclassunc)
+                numactiveparticles=numactiveparticles+1
+                numparticlecount=numparticlecount+1
+                npoint(ipart)=numparticlecount
+                idt(ipart)=mintime
+                itra1(ipart)=itime
+                itramem(ipart)=itra1(ipart)
+                itrasplit(ipart)=itra1(ipart)+ldirect*itsplit
+                xmass1(ipart,1)=xmassperparticle
+                if (mdomainfill.eq.2) xmass1(ipart,1)= &
+                     xmass1(ipart,1)*pvpart*48./29.*ozonescale/10.**9
+              else
+                goto 71
+              endif
+
+
+  ! Increase numpart, if necessary
+  !*******************************
+
+              numpart=max(numpart,ipart)
+              goto 73      ! Storage space has been found, stop searching
+            endif
+          end do
+          if (ipart.gt.maxpart) &
+               stop 'boundcond_domainfill.f: too many particles required'
+73        minpart=ipart+1
+71        continue
+        end do
+
+
+      end do
+    end do
+  end do
+
+
+  !*****************************************
+  ! Southern and northern boundary condition
+  !*****************************************
+
+  ! Loop from west to east
+  !***********************
+
+  do ix=nx_we(1),nx_we(2)
+
+  ! Loop over southern (index 1) and northern (index 2) boundary
+  !*************************************************************
+
+    do k=1,2
+      ylat=ylat0+real(ny_sn(k))*dy
+      cosfact=cos(ylat*pi180)
+
+  ! Loop over all release locations in a column
+  !********************************************
+
+      do j=1,numcolumn_sn(k,ix)
+
+  ! Determine, for each release location, the area of the corresponding boundary
+  !*****************************************************************************
+
+        if (j.eq.1) then
+          deltaz=(zcolumn_sn(k,ix,2)+zcolumn_sn(k,ix,1))/2.
+        else if (j.eq.numcolumn_sn(k,ix)) then
+  !        deltaz=height(nz)-(zcolumn_sn(k,ix,j-1)+
+  !    +        zcolumn_sn(k,ix,j))/2.
+  ! In order to avoid taking a very high column for very many particles,
+  ! use the deltaz from one particle below instead
+          deltaz=(zcolumn_sn(k,ix,j)-zcolumn_sn(k,ix,j-2))/2.
+        else
+          deltaz=(zcolumn_sn(k,ix,j+1)-zcolumn_sn(k,ix,j-1))/2.
+        endif
+        if ((ix.eq.nx_we(1)).or.(ix.eq.nx_we(2))) then
+          boundarea=deltaz*111198.5/2.*cosfact*dx
+        else
+          boundarea=deltaz*111198.5*cosfact*dx
+        endif
+
+
+  ! Interpolate the wind velocity and density to the release location
+  !******************************************************************
+
+  ! Determine the model level below the release position
+  !*****************************************************
+
+        do i=2,nz
+          if (height(i).gt.zcolumn_sn(k,ix,j)) then
+            indz=i-1
+            indzp=i
+            goto 16
+          endif
+        end do
+16      continue
+
+  ! Vertical distance to the level below and above current position
+  !****************************************************************
+
+        dz1=zcolumn_sn(k,ix,j)-height(indz)
+        dz2=height(indzp)-zcolumn_sn(k,ix,j)
+        dz=1./(dz1+dz2)
+
+  ! Vertical and temporal interpolation
+  !************************************
+
+        do m=1,2
+          indexh=memind(m)
+          do in=1,2
+            indzh=indz+in-1
+            windl(in)=vv(ix,ny_sn(k),indzh,indexh)
+            rhol(in)=rho(ix,ny_sn(k),indzh,indexh)
+          end do
+
+          windhl(m)=(dz2*windl(1)+dz1*windl(2))*dz
+          rhohl(m)=(dz2*rhol(1)+dz1*rhol(2))*dz
+        end do
+
+        windx=(windhl(1)*dt2+windhl(2)*dt1)*dtt
+        rhox=(rhohl(1)*dt2+rhohl(2)*dt1)*dtt
+
+  ! Calculate mass flux
+  !********************
+
+        fluxofmass=windx*rhox*boundarea*real(lsynctime)
+
+  ! If the mass flux is directed into the domain, add it to previous mass fluxes;
+  ! if it is out of the domain, set accumulated mass flux to zero
+  !******************************************************************************
+
+        if (k.eq.1) then
+          if (fluxofmass.ge.0.) then
+            acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)+fluxofmass
+          else
+            acc_mass_sn(k,ix,j)=0.
+          endif
+        else
+          if (fluxofmass.le.0.) then
+            acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)+abs(fluxofmass)
+          else
+            acc_mass_sn(k,ix,j)=0.
+          endif
+        endif
+        accmasst=accmasst+acc_mass_sn(k,ix,j)
+
+  ! If the accumulated mass exceeds half the mass that each particle shall carry,
+  ! one (or more) particle(s) is (are) released and the accumulated mass is
+  ! reduced by the mass of this (these) particle(s)
+  !******************************************************************************
+
+        if (acc_mass_sn(k,ix,j).ge.xmassperparticle/2.) then
+          mmass=int((acc_mass_sn(k,ix,j)+xmassperparticle/2.)/ &
+               xmassperparticle)
+          acc_mass_sn(k,ix,j)=acc_mass_sn(k,ix,j)- &
+               real(mmass)*xmassperparticle
+        else
+          mmass=0
+        endif
+
+        do m=1,mmass
+          do ipart=minpart,maxpart
+
+  ! If a vacant storage space is found, attribute everything to this array element
+  !*****************************************************************************
+
+            if (itra1(ipart).ne.itime) then
+
+  ! Assign particle positions
+  !**************************
+
+              ytra1(ipart)=real(ny_sn(k))
+              if (ix.eq.nx_we(1)) then
+                xtra1(ipart)=real(ix)+0.5*ran1(idummy)
+              else if (ix.eq.nx_we(2)) then
+                xtra1(ipart)=real(ix)-0.5*ran1(idummy)
+              else
+                xtra1(ipart)=real(ix)+(ran1(idummy)-.5)
+              endif
+              if (j.eq.1) then
+                ztra1(ipart)=zcolumn_sn(k,ix,1)+(zcolumn_sn(k,ix,2)- &
+                     zcolumn_sn(k,ix,1))/4.
+              else if (j.eq.numcolumn_sn(k,ix)) then
+                ztra1(ipart)=(2.*zcolumn_sn(k,ix,j)+ &
+                     zcolumn_sn(k,ix,j-1)+height(nz))/4.
+              else
+                ztra1(ipart)=zcolumn_sn(k,ix,j-1)+ran1(idummy)* &
+                     (zcolumn_sn(k,ix,j+1)-zcolumn_sn(k,ix,j-1))
+              endif
+
+
+  ! Interpolate PV to the particle position
+  !****************************************
+              ixm=int(xtra1(ipart))
+              jym=int(ytra1(ipart))
+              ixp=ixm+1
+              jyp=jym+1
+              ddx=xtra1(ipart)-real(ixm)
+              ddy=ytra1(ipart)-real(jym)
+              rddx=1.-ddx
+              rddy=1.-ddy
+              p1=rddx*rddy
+              p2=ddx*rddy
+              p3=rddx*ddy
+              p4=ddx*ddy
+              do i=2,nz
+                if (height(i).gt.ztra1(ipart)) then
+                  indzm=i-1
+                  indzp=i
+                  goto 126
+                endif
+              end do
+126           continue
+              dz1=ztra1(ipart)-height(indzm)
+              dz2=height(indzp)-ztra1(ipart)
+              dz=1./(dz1+dz2)
+              do mm=1,2
+                indexh=memind(mm)
+                do in=1,2
+                  indzh=indzm+in-1
+                  y1(in)=p1*pv(ixm,jym,indzh,indexh) &
+                       +p2*pv(ixp,jym,indzh,indexh) &
+                       +p3*pv(ixm,jyp,indzh,indexh) &
+                       +p4*pv(ixp,jyp,indzh,indexh)
+                end do
+                yh1(mm)=(dz2*y1(1)+dz1*y1(2))*dz
+              end do
+              pvpart=(yh1(1)*dt2+yh1(2)*dt1)*dtt
+              if (ylat.lt.0.) pvpart=-1.*pvpart
+
+
+  ! For domain-filling option 2 (stratospheric O3), do the rest only in the stratosphere
+  !*****************************************************************************
+
+              if (((ztra1(ipart).gt.3000.).and. &
+                   (pvpart.gt.pvcrit)).or.(mdomainfill.eq.1)) then
+                nclass(ipart)=min(int(ran1(idummy)* &
+                     real(nclassunc))+1,nclassunc)
+                numactiveparticles=numactiveparticles+1
+                numparticlecount=numparticlecount+1
+                npoint(ipart)=numparticlecount
+                idt(ipart)=mintime
+                itra1(ipart)=itime
+                itramem(ipart)=itra1(ipart)
+                itrasplit(ipart)=itra1(ipart)+ldirect*itsplit
+                xmass1(ipart,1)=xmassperparticle
+                if (mdomainfill.eq.2) xmass1(ipart,1)= &
+                     xmass1(ipart,1)*pvpart*48./29.*ozonescale/10.**9
+              else
+                goto 171
+              endif
+
+
+  ! Increase numpart, if necessary
+  !*******************************
+              numpart=max(numpart,ipart)
+              goto 173      ! Storage space has been found, stop searching
+            endif
+          end do
+          if (ipart.gt.maxpart) &
+               stop 'boundcond_domainfill.f: too many particles required'
+173       minpart=ipart+1
+171       continue
+        end do
+
+
+      end do
+    end do
+  end do
+
+
+  xm=0.
+  do i=1,numpart
+    if (itra1(i).eq.itime) xm=xm+xmass1(i,1)
+  end do
+
+  !write(*,*) itime,numactiveparticles,numparticlecount,numpart,
+  !    +xm,accmasst,xm+accmasst
+
+
+  ! If particles shall be dumped, then accumulated masses at the domain boundaries
+  ! must be dumped, too, to be used for later runs
+  !*****************************************************************************
+
+  if ((ipout.gt.0).and.(itime.eq.loutend)) then
+    open(unitboundcond,file=path(2)(1:length(2))//'boundcond.bin', &
+         form='unformatted')
+    write(unitboundcond) numcolumn_we,numcolumn_sn, &
+         zcolumn_we,zcolumn_sn,acc_mass_we,acc_mass_sn
+    close(unitboundcond)
+  endif
+
+end subroutine boundcond_domainfill
