source: branches/jerome/src_flexwrf_v3.1/init_domainfill.f90 @ 16

Last change on this file since 16 was 16, checked in by jebri, 10 years ago

sources for flexwrf v3.1

File size: 18.0 KB
Line 
1!***********************************************************************
2!* Copyright 2012,2013                                                *
3!* Jerome Brioude, Delia Arnold, Andreas Stohl, Wayne Angevine,       *
4!* John Burkhart, Massimo Cassiani, Adam Dingwell, Richard C Easter, Sabine Eckhardt,*
5!* Stephanie Evan, Jerome D Fast, Don Morton, Ignacio Pisso,          *
6!* Petra Seibert, Gerard Wotawa, Caroline Forster, Harald Sodemann,   *
7!*                                                                     *
8!* This file is part of FLEXPART WRF                                   *
9!*                                                                     *
10!* FLEXPART is free software: you can redistribute it and/or modify    *
11!* it under the terms of the GNU General Public License as published by*
12!* the Free Software Foundation, either version 3 of the License, or   *
13!* (at your option) any later version.                                 *
14!*                                                                     *
15!* FLEXPART is distributed in the hope that it will be useful,         *
16!* but WITHOUT ANY WARRANTY; without even the implied warranty of      *
17!* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the       *
18!* GNU General Public License for more details.                        *
19!*                                                                     *
20!* You should have received a copy of the GNU General Public License   *
21!* along with FLEXPART.  If not, see <http://www.gnu.org/licenses/>.   *
22!***********************************************************************
23      subroutine init_domainfill
24!
25!*******************************************************************************
26!                                                                              *
27!     Note:  This is the FLEXPART_WRF version of subroutine init_domainfill.   *
28!            The computational grid is the WRF x-y grid rather than lat-lon.   *
29!                                                                              *
30! Initializes particles equally distributed over the first release location    *
31! specified in file RELEASES. This box is assumed to be the domain for doing   *
32! domain-filling trajectory calculations.                                      *
33! All particles carry the same amount of mass which alltogether comprises the  *
34! mass of air within the box.                                                  *
35!                                                                              *
36!     Author: A. Stohl                                                         *
37!                                                                              *
38!     15 October 2002                                                          *
39!                                                                              *
40!    26 Oct 2005, R. Easter - changes for gridarea                             *
41!                             associated with WRF horizontal grid.             *
42!                             Also calc. true ylat for pv stuff.               *
43!    11 Nov 2005, R. Easter - fixed error involving xy to latlon               *
44!                                                                              *
45!                                                                              *
46!*******************************************************************************
47!                                                                              *
48! Variables:                                                                   *
49!                                                                              *
50! numparticlecount    consecutively counts the number of particles released    *
51! nx_we(2)       grid indices for western and eastern boundary of domain-      *
52!                filling trajectory calculations                               *
53! ny_sn(2)       grid indices for southern and northern boundary of domain-    *
54!                filling trajectory calculations                               *
55!                                                                              *
56!*******************************************************************************
57
58  use point_mod
59  use par_mod
60  use com_mod
61
62  implicit none
63
64      integer :: j,ix,jy,kz,ncolumn,numparttot
65!,idummy
66
67!     real gridarea(0:nymax-1),pp(nzmax),ylat,ylatp,ylatm,hzone,ran1
68      real :: gridarea(0:nymax-1),pp(nzmax),ylat,                  ran1
69!     real cosfactm,cosfactp,pih,deltacol,dz1,dz2,dz,pnew,fractus
70      real ::                deltacol,dz1,dz2,dz,pnew,fractus
71      real :: xlon
72
73      real,parameter :: pih=pi/180.
74      real :: colmass(0:nxmax-1,0:nymax-1),colmasstotal,zposition
75
76      integer :: ixm,ixp,jym,jyp,indzm,indzp,in,indzh,i,jj
77      real :: pvpart,ddx,ddy,rddx,rddy,p1,p2,p3,p4,y1(2)
78
79  integer :: idummy = -11
80
81
82! Determine the release region (only full grid cells), over which particles
83! shall be initialized
84! Use 2 fields for west/east and south/north boundary
85!**************************************************************************
86
87      nx_we(1)=max(int(xpoint1(1)),0)
88      nx_we(2)=min((int(xpoint2(1))+1),nxmin1)
89      ny_sn(1)=max(int(ypoint1(1)),0)
90      ny_sn(2)=min((int(ypoint2(1))+1),nymin1)
91
92! For global simulations (both global wind data and global domain-filling),
93! set a switch, such that no boundary conditions are used
94!**************************************************************************
95      if (xglobal.and.sglobal.and.nglobal) then
96        if ((nx_we(1).eq.0).and.(nx_we(2).eq.nxmin1).and. &
97        (ny_sn(1).eq.0).and.(ny_sn(2).eq.nymin1)) then
98          gdomainfill=.true.
99        else
100          gdomainfill=.false.
101        endif
102      endif
103
104! Do not release particles twice (i.e., not at both in the leftmost and rightmost
105! grid cell) for a global domain
106!********************************************************************************
107      if (xglobal) nx_we(2)=min(nx_we(2),nx-2)
108
109
110! Calculate area of grid cell with formula M=2*pi*R*h*dx/360,
111! see Netz, Formeln der Mathematik, 5. Auflage (1983), p.90
112!************************************************************
113
114      do jy=ny_sn(1),ny_sn(2)      ! loop about latitudes
115
116!        ylat=ylat0+real(jy)*dy
117!        ylatp=ylat+0.5*dy
118!        ylatm=ylat-0.5*dy
119!        if ((ylatm.lt.0).and.(ylatp.gt.0.)) then
120!          hzone=1./dyconst
121!        else
122!          cosfactp=cos(ylatp*pih)*r_earth
123!          cosfactm=cos(ylatm*pih)*r_earth
124!          if (cosfactp.lt.cosfactm) then
125!            hzone=sqrt(r_earth**2-cosfactp**2)-
126!     +      sqrt(r_earth**2-cosfactm**2)
127!          else
128!            hzone=sqrt(r_earth**2-cosfactm**2)-
129!     +      sqrt(r_earth**2-cosfactp**2)
130!          endif
131!        endif
132!10      gridarea(jy)=2.*pi*r_earth*hzone*dx/360.
133
134! for FLEXPART_WRF, dx & dy are in meters, and no cos(lat) is needed
135! ??? should maybe include map factor here ???
136        gridarea(jy)=dx*dy
137         enddo
138! Do the same for the south pole
139
140      if (sglobal) then
141         write(*,*)
142         write(*,*) '*** stopping in init_domainfill ***'
143         write(*,*) '    the s-pole code section should not be active'
144         write(*,*)
145!        ylat=ylat0
146!        ylatp=ylat+0.5*dy
147!        ylatm=ylat
148!        cosfactm=0.
149!        cosfactp=cos(ylatp*pih)*r_earth
150!        hzone=sqrt(r_earth**2-cosfactm**2)-
151!     +  sqrt(r_earth**2-cosfactp**2)
152!        gridarea(0)=2.*pi*r_earth*hzone*dx/360.
153      endif
154
155! Do the same for the north pole
156
157      if (nglobal) then
158         write(*,*)
159         write(*,*) '*** stopping in init_domainfill ***'
160         write(*,*) '    the s-pole code section should not be active'
161         write(*,*)
162!        ylat=ylat0+real(nymin1)*dy
163!        ylatp=ylat
164!        ylatm=ylat-0.5*dy
165!        cosfactp=0.
166!        cosfactm=cos(ylatm*pih)*r_earth
167!        hzone=sqrt(r_earth**2-cosfactp**2)-
168!     +  sqrt(r_earth**2-cosfactm**2)
169!        gridarea(nymin1)=2.*pi*r_earth*hzone*dx/360.
170      endif
171
172
173! Calculate total mass of each grid column and of the whole atmosphere
174!*********************************************************************
175
176      colmasstotal=0.
177      do jy=ny_sn(1),ny_sn(2)          ! loop about latitudes
178        do ix=nx_we(1),nx_we(2)      ! loop about longitudes
179          pp(1)=rho(ix,jy,1,1)*r_air*tt(ix,jy,1,1)
180          pp(nz)=rho(ix,jy,nz,1)*r_air*tt(ix,jy,nz,1)
181          colmass(ix,jy)=(pp(1)-pp(nz))/ga*gridarea(jy)
182          colmasstotal=colmasstotal+colmass(ix,jy)
183        enddo
184        enddo
185               write(*,*) 'Atm. mass: ',colmasstotal
186
187
188      if (ipin.eq.0) numpart=0
189
190! Determine the particle positions
191!*********************************
192
193      numparttot=0
194      numcolumn=0
195      do jy=ny_sn(1),ny_sn(2)      ! loop about latitudes
196!       ylat=ylat0+real(jy)*dy
197        do ix=nx_we(1),nx_we(2)      ! loop about longitudes
198
199! for FLEXPART_WRF, x & y coords are in meters.
200! In the "do 30" loop, ylat is only needed for pv calcs.
201          call xyindex_to_ll_wrf( 0, real(ix), real(jy), xlon, ylat )
202
203          ncolumn=nint(0.999*real(npart(1))*colmass(ix,jy)/ &
204         colmasstotal)
205          if (ncolumn.eq.0) goto 30
206          if (ncolumn.gt.numcolumn) numcolumn=ncolumn
207
208! Calculate pressure at the altitudes of model surfaces, using the air density
209! information, which is stored as a 3-d field
210!*****************************************************************************
211
212          do kz=1,nz
213            pp(kz)=rho(ix,jy,kz,1)*r_air*tt(ix,jy,kz,1)
214          enddo
215
216          deltacol=(pp(1)-pp(nz))/real(ncolumn)
217          pnew=pp(1)+deltacol/2.
218          jj=0
219          do j=1,ncolumn
220            jj=jj+1
221
222
223! For columns with many particles (i.e. around the equator), distribute
224! the particles equally, for columns with few particles (i.e. around the
225! poles), distribute the particles randomly
226!***********************************************************************
227
228
229            if (ncolumn.gt.20) then
230              pnew=pnew-deltacol
231            else
232              pnew=pp(1)-ran1(idummy)*(pp(1)-pp(nz))
233            endif
234
235            do kz=1,nz-1
236              if ((pp(kz).ge.pnew).and.(pp(kz+1).lt.pnew)) then
237                dz1=pp(kz)-pnew
238                dz2=pnew-pp(kz+1)
239                dz=1./(dz1+dz2)
240
241! Assign particle position
242!*************************
243! Do the following steps only if particles are not read in from previous model run
244!*********************************************************************************
245                if (ipin.eq.0) then
246                  xtra1(numpart+jj)=real(ix)-0.5+ran1(idummy)
247                  if (ix.eq.0) xtra1(numpart+jj)=ran1(idummy)
248                  if (ix.eq.nxmin1) xtra1(numpart+jj)= &
249                  real(nxmin1)-ran1(idummy)
250                  ytra1(numpart+jj)=real(jy)-0.5+ran1(idummy)
251                  ztra1(numpart+jj)=(height(kz)*dz2+height(kz+1)*dz1)*dz
252                  if (ztra1(numpart+jj).gt.height(nz)-0.5) &
253                  ztra1(numpart+jj)=height(nz)-0.5
254
255
256! Interpolate PV to the particle position
257!****************************************
258                  ixm=int(xtra1(numpart+jj))
259                  jym=int(ytra1(numpart+jj))
260                  ixp=ixm+1
261                  jyp=jym+1
262                  ddx=xtra1(numpart+jj)-real(ixm)
263                  ddy=ytra1(numpart+jj)-real(jym)
264                  rddx=1.-ddx
265                  rddy=1.-ddy
266                  p1=rddx*rddy
267                  p2=ddx*rddy
268                  p3=rddx*ddy
269                  p4=ddx*ddy
270                  do i=2,nz
271                    if (height(i).gt.ztra1(numpart+jj)) then
272                      indzm=i-1
273                      indzp=i
274                      goto 6
275                    endif
276                  enddo
2776                 continue
278                  dz1=ztra1(numpart+jj)-height(indzm)
279                  dz2=height(indzp)-ztra1(numpart+jj)
280                  dz=1./(dz1+dz2)
281                  do  in=1,2     
282                    indzh=indzm+in-1
283                    y1(in)=p1*pv(ixm,jym,indzh,1) &
284                          +p2*pv(ixp,jym,indzh,1) &
285                          +p3*pv(ixm,jyp,indzh,1) &
286                          +p4*pv(ixp,jyp,indzh,1)
287                  enddo
288                  pvpart=(dz2*y1(1)+dz1*y1(2))*dz
289                  if (ylat.lt.0.) pvpart=-1.*pvpart
290
291
292! For domain-filling option 2 (stratospheric O3), do the rest only in the stratosphere
293!*************************************************************************************
294
295                  if (((ztra1(numpart+jj).gt.3000.).and. &
296                  (pvpart.gt.pvcrit)).or.(mdomainfill.eq.1)) then
297!                 if (((ztra1(numpart+jj).lt.8000.)
298!    +            ).or.(mdomainfill.eq.1)) then
299
300! Assign certain properties to the particle
301!******************************************
302                    nclass(numpart+jj)=min(int(ran1(idummy)* &
303                    real(nclassunc))+1,nclassunc)
304                    numparticlecount=numparticlecount+1
305                    npoint(numpart+jj)=numparticlecount
306                    idt(numpart+jj)=mintime
307                    itra1(numpart+jj)=0
308                    itramem(numpart+jj)=0
309                    itrasplit(numpart+jj)=itra1(numpart+jj)+ldirect* &
310                    itsplit
311                    xmass1(numpart+jj,1)=colmass(ix,jy)/real(ncolumn)
312                    if (mdomainfill.eq.2) xmass1(numpart+jj,1)= &
313                   xmass1(numpart+jj,1)*pvpart*48./29.*ozonescale/10.**9
314!                  xmass1(numpart+jj,1)*60.*48./29./10.**9
315                  else
316                    jj=jj-1
317                  endif
318                endif
319              endif
320        end do
321      end do
322          numparttot=numparttot+ncolumn
323          if (ipin.eq.0) numpart=numpart+jj
32430        continue
325    end do
326  end do
327
328               
329! Check whether numpart is really smaller than maxpart
330!*****************************************************
331
332      if (numpart.gt.maxpart) then
333        write(*,*) 'numpart too large: change source in init_atm_mass.f'
334        write(*,*) 'numpart: ',numpart,' maxpart: ',maxpart
335      endif
336
337
338      xmassperparticle=colmasstotal/real(numparttot)
339
340
341! Make sure that all particles are within domain
342!***********************************************
343
344      do j=1,numpart
345        if ((xtra1(j).lt.0.).or.(xtra1(j).ge.real(nxmin1)).or. &
346        (ytra1(j).lt.0.).or.(ytra1(j).ge.real(nymin1))) then
347          itra1(j)=-999999999
348        endif
349        enddo
350
351
352
353
354! For boundary conditions, we need fewer particle release heights per column,
355! because otherwise it takes too long until enough mass has accumulated to
356! release a particle at the boundary (would take dx/u seconds), leading to
357! relatively large position errors of the order of one grid distance.
358! It's better to release fewer particles per column, but to do so more often.
359! Thus, use on the order of nz starting heights per column.
360! We thus repeat the above to determine fewer starting heights, that are
361! used furtheron in subroutine boundcond_domainfill.f.
362!****************************************************************************
363
364      fractus=real(numcolumn)/real(nz)
365      write(*,*) 'Total number of particles at model start: ',numpart
366      write(*,*) 'Maximum number of particles per column: ',numcolumn
367      write(*,*) 'If ',fractus,' <1, better use more particles'
368      fractus=sqrt(max(fractus,1.))/2.
369
370      do jy=ny_sn(1),ny_sn(2)      ! loop about latitudes
371        do ix=nx_we(1),nx_we(2)      ! loop about longitudes
372          ncolumn=nint(0.999/fractus*real(npart(1))*colmass(ix,jy) &
373          /colmasstotal)
374          if (ncolumn.gt.maxcolumn) stop 'maxcolumn too small'
375          if (ncolumn.eq.0) goto 80
376
377
378! Memorize how many particles per column shall be used for all boundaries
379! This is further used in subroutine boundcond_domainfill.f
380! Use 2 fields for west/east and south/north boundary
381!************************************************************************
382
383          if (ix.eq.nx_we(1)) numcolumn_we(1,jy)=ncolumn
384          if (ix.eq.nx_we(2)) numcolumn_we(2,jy)=ncolumn
385          if (jy.eq.ny_sn(1)) numcolumn_sn(1,ix)=ncolumn
386          if (jy.eq.ny_sn(2)) numcolumn_sn(2,ix)=ncolumn
387
388! Calculate pressure at the altitudes of model surfaces, using the air density
389! information, which is stored as a 3-d field
390!*****************************************************************************
391
392          do  kz=1,nz
393            pp(kz)=rho(ix,jy,kz,1)*r_air*tt(ix,jy,kz,1)
394          enddo
395! Determine the reference starting altitudes
396!*******************************************
397
398          deltacol=(pp(1)-pp(nz))/real(ncolumn)
399          pnew=pp(1)+deltacol/2.
400          do j=1,ncolumn
401            pnew=pnew-deltacol
402            do kz=1,nz-1
403              if ((pp(kz).ge.pnew).and.(pp(kz+1).lt.pnew)) then
404                dz1=pp(kz)-pnew
405                dz2=pnew-pp(kz+1)
406                dz=1./(dz1+dz2)
407                zposition=(height(kz)*dz2+height(kz+1)*dz1)*dz
408               if (zposition.gt.height(nz)-0.5) zposition=height(nz)-0.5
409
410! Memorize vertical positions where particles are introduced
411! This is further used in subroutine boundcond_domainfill.f
412!***********************************************************
413
414                if (ix.eq.nx_we(1)) zcolumn_we(1,jy,j)=zposition
415                if (ix.eq.nx_we(2)) zcolumn_we(2,jy,j)=zposition
416                if (jy.eq.ny_sn(1)) zcolumn_sn(1,ix,j)=zposition
417                if (jy.eq.ny_sn(2)) zcolumn_sn(2,ix,j)=zposition
418
419! Initialize mass that has accumulated at boundary to zero
420!*********************************************************
421
422                acc_mass_we(1,jy,j)=0.
423                acc_mass_we(2,jy,j)=0.
424                acc_mass_sn(1,jy,j)=0.
425                acc_mass_sn(2,jy,j)=0.
426          endif
427        end do
428      end do
42980    continue
430    end do
431  end do
432
433
434! If particles shall be read in to continue an existing run,
435! then the accumulated masses at the domain boundaries must be read in, too.
436! This overrides any previous calculations.
437!***************************************************************************
438
439      if (ipin.eq.1) then
440        open(unitboundcond,file=path(1)(1:length(1))//'boundcond.bin', &
441        form='unformatted')
442        read(unitboundcond) numcolumn_we,numcolumn_sn, &
443        zcolumn_we,zcolumn_sn,acc_mass_we,acc_mass_sn
444        close(unitboundcond)
445      endif
446
447
448
449
450end subroutine init_domainfill
451
Note: See TracBrowser for help on using the repository browser.
hosted by ZAMG