| 1 | module coagulation_mod |
|---|
| 2 | |
|---|
| 3 | ! ------------------------ |
|---|
| 4 | ! Dust coagulation scheme |
|---|
| 5 | ! Based on Bertrand et al., 2022 |
|---|
| 6 | ! Author: T. Bertrand |
|---|
| 7 | ! ------------------------ |
|---|
| 8 | |
|---|
| 9 | use comcstfi_h, only: pi,g,r,mugaz |
|---|
| 10 | use tracer_mod, only: igcm_dust_mass,igcm_dust_number, & |
|---|
| 11 | igcm_stormdust_mass,igcm_stormdust_number, & |
|---|
| 12 | igcm_topdust_mass,igcm_topdust_number |
|---|
| 13 | use microphys_h, only: kbz,m0co2 |
|---|
| 14 | use callkeys_mod, only: kernel_b,kernel_g,kernel_de,kernel_ti, & |
|---|
| 15 | fullcoag, coal_kg |
|---|
| 16 | implicit none |
|---|
| 17 | |
|---|
| 18 | public :: coagul_init |
|---|
| 19 | |
|---|
| 20 | ! ------------------------------- |
|---|
| 21 | ! Coagulation Input Parameters |
|---|
| 22 | ! ------------------------------- |
|---|
| 23 | real :: effb=1. ! Sticking efficiency for B coagulation |
|---|
| 24 | real :: coal_fac=1. ! Overall coalescence factor |
|---|
| 25 | ! Bin discretization of particle sizes |
|---|
| 26 | real*8, save :: r1_coag = 0.01e-6 ! min radius |
|---|
| 27 | real*8, save :: rn_coag = 40.e-6 ! max radius |
|---|
| 28 | integer,parameter :: nres_coag = 10 ! nb bins |
|---|
| 29 | real*8, save :: vrat_coag ! volume ratio |
|---|
| 30 | real*8, save, allocatable :: rads_coag(:),vols_coag(:),deltar_coag(:) |
|---|
| 31 | |
|---|
| 32 | !$OMP THREADPRIVATE(r1_coag,rn_coag,vrat_coag) |
|---|
| 33 | !$OMP THREADPRIVATE(rads_coag,vols_coag,deltar_coag) |
|---|
| 34 | |
|---|
| 35 | ! parameters of the look up tables of coagulation coefficients |
|---|
| 36 | integer,parameter :: table_numt = 15 ! Nb of temperature bins |
|---|
| 37 | integer,parameter :: table_nump = 25 ! Nb of pressure bins |
|---|
| 38 | integer,parameter :: table_numm = 25 ! Nb of mass bins |
|---|
| 39 | real, save :: table_pt(table_numt) |
|---|
| 40 | real, save :: table_pres(table_nump) |
|---|
| 41 | real, save :: table_mfp(table_numm) |
|---|
| 42 | real, save :: table_b(table_numt,table_nump,nres_coag,nres_coag) ! Brownian |
|---|
| 43 | real, save :: table_g(table_numt,table_nump,nres_coag,nres_coag) ! Gravitational |
|---|
| 44 | real, save :: table_de(table_numt,table_nump,nres_coag,nres_coag) ! Brownian diffusion enhancement |
|---|
| 45 | real, save :: table_ti(table_numt,table_nump,nres_coag,nres_coag) ! Turbulent |
|---|
| 46 | real*8, public :: dev_dt = 0.63676 ! standard deviation of dust distribution |
|---|
| 47 | real, public ::rho_dust=2500. ! Mars dust density (kg.m-3) |
|---|
| 48 | |
|---|
| 49 | !$OMP THREADPRIVATE(table_pt,table_pres,table_mfp) |
|---|
| 50 | !$OMP THREADPRIVATE(table_b,table_g,table_de,table_ti) |
|---|
| 51 | |
|---|
| 52 | contains |
|---|
| 53 | |
|---|
| 54 | !####################################################################### |
|---|
| 55 | |
|---|
| 56 | subroutine coagul_init() |
|---|
| 57 | |
|---|
| 58 | ! Initialisation of the particle bin discretization |
|---|
| 59 | |
|---|
| 60 | integer :: i |
|---|
| 61 | allocate(rads_coag(nres_coag)) |
|---|
| 62 | allocate(vols_coag(nres_coag)) |
|---|
| 63 | allocate(deltar_coag(nres_coag)) |
|---|
| 64 | |
|---|
| 65 | vrat_coag=(rn_coag/r1_coag)**(3./(nres_coag-1)) |
|---|
| 66 | |
|---|
| 67 | do i = 1, nres_coag |
|---|
| 68 | rads_coag(i) = r1_coag*vrat_coag**((i-1)/3.) |
|---|
| 69 | vols_coag(i) = 4./3.*pi*r1_coag**3*vrat_coag**(i-1) |
|---|
| 70 | enddo |
|---|
| 71 | ! diameter width |
|---|
| 72 | deltar_coag(:)=2.*rads_coag(:)*2.**(1/3.)*(vrat_coag**(1./3.)-1)/(1+vrat_coag)**(1./3.) |
|---|
| 73 | |
|---|
| 74 | ! Making Lookup Tables |
|---|
| 75 | if (.not.fullcoag) then |
|---|
| 76 | call make_tables() |
|---|
| 77 | endif |
|---|
| 78 | !deallocate(rads_coag) |
|---|
| 79 | !deallocate(vols_coag) |
|---|
| 80 | !deallocate(deltar_coag) |
|---|
| 81 | |
|---|
| 82 | end subroutine coagul_init |
|---|
| 83 | |
|---|
| 84 | !####################################################################### |
|---|
| 85 | |
|---|
| 86 | SUBROUTINE coagul_main( & |
|---|
| 87 | ngrid, nlayer, nq, ptime, ptimestep, pq, pdqfi, pt, pdtfi, & |
|---|
| 88 | pplay, pplev, pdqcoag) |
|---|
| 89 | |
|---|
| 90 | !-------------------------------------------------------- |
|---|
| 91 | ! Input Variables |
|---|
| 92 | !-------------------------------------------------------- |
|---|
| 93 | INTEGER, INTENT(IN) :: ngrid ! number of horizontal grid points |
|---|
| 94 | INTEGER, INTENT(IN) :: nlayer ! number of vertical grid points |
|---|
| 95 | INTEGER, INTENT(IN) :: nq ! number of tracer species |
|---|
| 96 | REAL, INTENT(IN) :: ptime |
|---|
| 97 | REAL, INTENT(IN) :: ptimestep |
|---|
| 98 | |
|---|
| 99 | REAL, INTENT(IN) :: pq(ngrid,nlayer,nq) ! advected field nq |
|---|
| 100 | REAL, INTENT(IN) :: pdqfi(ngrid,nlayer,nq)! tendancy field pq |
|---|
| 101 | REAL, INTENT(IN) :: pt(ngrid,nlayer) ! temperature at mid-layer (K) |
|---|
| 102 | REAL, INTENT(IN) :: pdtfi(ngrid,nlayer) ! tendancy temperature at mid-layer (K) |
|---|
| 103 | REAL, INTENT(IN) :: pplay(ngrid,nlayer) ! pressure at middle of the layers |
|---|
| 104 | REAL, INTENT(IN) :: pplev(ngrid,nlayer+1) ! pressure at intermediate levels |
|---|
| 105 | |
|---|
| 106 | !-------------------------------------------------------- |
|---|
| 107 | ! Output Variables |
|---|
| 108 | !-------------------------------------------------------- |
|---|
| 109 | REAL, INTENT(OUT) :: pdqcoag(ngrid,nlayer,nq) ! tendancy field for dust coagulation |
|---|
| 110 | |
|---|
| 111 | !----------------------------------------------------------------------- |
|---|
| 112 | ! Local variables |
|---|
| 113 | !----------------------------------------------------------------------- |
|---|
| 114 | integer :: ie, je, id, jd, iq, i, j, k, l, ii, jj |
|---|
| 115 | real dens,dev,cst,sig0 |
|---|
| 116 | real mfp0,pt0,rad0,rad10,rad20,rho0,pres0 |
|---|
| 117 | real term1,term2,kernel,norm |
|---|
| 118 | real, dimension(ngrid, nlayer) :: r0, rho, rn, ntot, mtot, mtotnew |
|---|
| 119 | real, dimension(ngrid, nlayer, nq) :: numb_new, numb_ini, numb_ini_dis, mass_ini, mass_new |
|---|
| 120 | real, dimension(ngrid, nlayer, nres_coag) :: ndis, ndis_new |
|---|
| 121 | real, dimension(ngrid,nlayer,nres_coag,nq) :: ndis_tab,rat_tab,ndis_tab_new |
|---|
| 122 | real, dimension(ngrid, nlayer) :: zt |
|---|
| 123 | real, dimension(ngrid, nlayer, nq) :: zq |
|---|
| 124 | |
|---|
| 125 | logical, save :: firstcall = .true. |
|---|
| 126 | !$OMP THREADPRIVATE(firstcall) |
|---|
| 127 | !for boxinterp function: |
|---|
| 128 | integer :: t1,t2,p1,p2,m1,m2 |
|---|
| 129 | |
|---|
| 130 | !====================================================================== |
|---|
| 131 | ! Main routine |
|---|
| 132 | |
|---|
| 133 | !----------------------------------------------------------------------- |
|---|
| 134 | !*** 1) Initialisations |
|---|
| 135 | !----------------------------------------------------------------------- |
|---|
| 136 | |
|---|
| 137 | !!! Particles properties |
|---|
| 138 | dens = rho_dust ! density dust |
|---|
| 139 | sig0 = dev_dt ! Standard deviation of the dust distribution |
|---|
| 140 | cst = .75 / (pi*dens) * exp( -4.5*sig0**2. ) ! fixed distribution |
|---|
| 141 | |
|---|
| 142 | !!! Radius and Volumes defined in coagul_init |
|---|
| 143 | ! rads_coag, vols_coag, deltar_coag, vrat_coag |
|---|
| 144 | |
|---|
| 145 | !!! Getting tracers and temperature fields |
|---|
| 146 | zq(:,:,:)=pq(:,:,:)+pdqfi(:,:,:)*ptimestep |
|---|
| 147 | zt(:,:)=pt(:,:)+pdtfi(:,:)*ptimestep |
|---|
| 148 | |
|---|
| 149 | !!! Atmospheric state |
|---|
| 150 | DO l=1,nlayer |
|---|
| 151 | rho(:,l)=pplay(:,l)/(r*pt(:,l)) |
|---|
| 152 | ENDDO |
|---|
| 153 | |
|---|
| 154 | !!! Initializing tracers and other fields |
|---|
| 155 | pdqcoag(:,:,:)=0.d0 |
|---|
| 156 | ndis_tab(:,:,:,:)=0.d0 |
|---|
| 157 | ndis_new(:,:,:)=0.d0 |
|---|
| 158 | mtot(:,:)=0.d0 |
|---|
| 159 | rat_tab(:,:,:,:) = 0.d0 |
|---|
| 160 | numb_ini_dis(:,:,:) = 0.d0 |
|---|
| 161 | numb_ini(:,:,:) = 0.d0 |
|---|
| 162 | numb_new(:,:,:) = 0.d0 |
|---|
| 163 | mass_ini(:,:,:) = 0.d0 |
|---|
| 164 | mass_new(:,:,:) = 0.d0 |
|---|
| 165 | |
|---|
| 166 | !!! Preparing the initial log normal distribution |
|---|
| 167 | do iq=1,nq |
|---|
| 168 | if ((iq.eq.igcm_dust_mass).or.(iq.eq.igcm_stormdust_mass).or.(iq.eq.igcm_topdust_mass)) then |
|---|
| 169 | mass_ini(:,:,iq)=max(zq(:,:,iq),1e-15) |
|---|
| 170 | numb_ini(:,:,iq)=max(zq(:,:,iq-1),1e-15) |
|---|
| 171 | |
|---|
| 172 | !!! Get total mass to ensure mass conservation |
|---|
| 173 | mtot(:,:)=mtot(:,:)+mass_ini(:,:,iq) |
|---|
| 174 | |
|---|
| 175 | !!! Initial Lognormal distribution |
|---|
| 176 | ! sig0 remains constant |
|---|
| 177 | r0(:,:)=(3/4.*mass_ini(:,:,iq)/(pi*numb_ini(:,:,iq)*dens))**(1/3.)*exp(-1.5*sig0**2) |
|---|
| 178 | |
|---|
| 179 | do i=1,nres_coag ! Sum of the ndis for all dust modes |
|---|
| 180 | ndis_tab(:,:,i,iq)=numb_ini(:,:,iq)*rho(:,:)*deltar_coag(i)/(2.*rads_coag(i)*(2*pi)**0.5*sig0)*exp(-0.5*(log(rads_coag(i)/r0(:,:)))**2/sig0**2) |
|---|
| 181 | enddo |
|---|
| 182 | !!! Initial number mixing ratio from bin discretization nb/kg |
|---|
| 183 | numb_ini_dis(:,:,iq)=sum(ndis_tab(:,:,:,iq),3)/rho(:,:) |
|---|
| 184 | numb_new(:,:,iq)=numb_ini_dis(:,:,iq) |
|---|
| 185 | endif |
|---|
| 186 | enddo |
|---|
| 187 | |
|---|
| 188 | |
|---|
| 189 | !!! Defining initial number ratio for each mode |
|---|
| 190 | do iq=1,nq |
|---|
| 191 | if ((iq.eq.igcm_dust_mass).or.(iq.eq.igcm_stormdust_mass).or.(iq.eq.igcm_topdust_mass)) then |
|---|
| 192 | rat_tab(:,:,:,iq)=ndis_tab(:,:,:,iq)/sum(ndis_tab(:,:,:,:),4) |
|---|
| 193 | endif |
|---|
| 194 | enddo |
|---|
| 195 | |
|---|
| 196 | !!! Normalizing the ratio (make sure sum=1) |
|---|
| 197 | do iq=1,nq |
|---|
| 198 | if ((iq.eq.igcm_dust_mass).or.(iq.eq.igcm_stormdust_mass).or.(iq.eq.igcm_topdust_mass)) then |
|---|
| 199 | rat_tab(:,:,:,iq)=rat_tab(:,:,:,iq)/sum(rat_tab(:,:,:,:),4) |
|---|
| 200 | endif |
|---|
| 201 | enddo |
|---|
| 202 | |
|---|
| 203 | !!! Total initial distribution nb/m3 per bin |
|---|
| 204 | ndis(:,:,:)=sum(ndis_tab(:,:,:,:),4) |
|---|
| 205 | !!! Total initial distribution nb/kg |
|---|
| 206 | ntot(:,:)=sum(ndis(:,:,:),3)/rho(:,:) |
|---|
| 207 | |
|---|
| 208 | !----------------------------------------------------------------------- |
|---|
| 209 | !*** 2) Coagulation |
|---|
| 210 | !----------------------------------------------------------------------- |
|---|
| 211 | ! Spatial loop => 1D |
|---|
| 212 | |
|---|
| 213 | if (fullcoag) then ! computing full coagulation equations |
|---|
| 214 | do i=1,ngrid |
|---|
| 215 | do j=1,nlayer |
|---|
| 216 | if (ntot(i,j).gt.1000.) then ! activating coagulation above this threshold |
|---|
| 217 | pt0=pt(i,j) |
|---|
| 218 | rho0=rho(i,j) |
|---|
| 219 | mfp0=mfp(pt0,rho0) |
|---|
| 220 | |
|---|
| 221 | ! Bin loop |
|---|
| 222 | do k=1,nres_coag |
|---|
| 223 | |
|---|
| 224 | ! Term 1 |
|---|
| 225 | term1=0. |
|---|
| 226 | do jj=1,k |
|---|
| 227 | do ii=1,k-1 |
|---|
| 228 | kernel=0. |
|---|
| 229 | if (kernel_b) kernel=kernel+betab(pt0,mfp0,rads_coag(ii),rads_coag(jj)) |
|---|
| 230 | if (kernel_g) kernel=kernel+betag(pt0,mfp0,rads_coag(ii),rads_coag(jj)) |
|---|
| 231 | if (kernel_de) kernel=kernel+betade(pt0,mfp0,rho0,rads_coag(ii),rads_coag(jj)) |
|---|
| 232 | if (kernel_ti) kernel=kernel+betati(pt0,mfp0,rho0,rads_coag(ii),rads_coag(jj)) |
|---|
| 233 | term1=term1+frac(ii,jj,k)*vols_coag(ii)*kernel*ndis_new(i,j,ii)*ndis(i,j,jj) |
|---|
| 234 | enddo |
|---|
| 235 | enddo |
|---|
| 236 | term1=term1*ptimestep/vols_coag(k) |
|---|
| 237 | |
|---|
| 238 | ! Term 2 |
|---|
| 239 | term2=0. |
|---|
| 240 | do jj=1,nres_coag |
|---|
| 241 | kernel=0. |
|---|
| 242 | if (kernel_b) kernel=kernel+betab(pt0,mfp0,rads_coag(k),rads_coag(jj)) |
|---|
| 243 | if (kernel_g) kernel=kernel+betag(pt0,mfp0,rads_coag(k),rads_coag(jj)) |
|---|
| 244 | if (kernel_de) kernel=kernel+betade(pt0,mfp0,rho0,rads_coag(k),rads_coag(jj)) |
|---|
| 245 | if (kernel_ti) kernel=kernel+betati(pt0,mfp0,rho0,rads_coag(k),rads_coag(jj)) |
|---|
| 246 | term2=term2+(1-frac(k,jj,k))*kernel*ndis(i,j,jj) |
|---|
| 247 | enddo |
|---|
| 248 | term2=term2*ptimestep |
|---|
| 249 | |
|---|
| 250 | ndis_new(i,j,k)=(ndis(i,j,k)+coal_fac*term1)/(1.+coal_fac*term2) |
|---|
| 251 | |
|---|
| 252 | enddo |
|---|
| 253 | |
|---|
| 254 | norm=sum(ndis(i,j,:)*vols_coag(:))/sum(ndis_new(i,j,:)*vols_coag(:)) |
|---|
| 255 | ndis_new(i,j,:)=ndis_new(i,j,:)*norm |
|---|
| 256 | |
|---|
| 257 | endif |
|---|
| 258 | enddo |
|---|
| 259 | enddo |
|---|
| 260 | |
|---|
| 261 | else ! fullcoag |
|---|
| 262 | |
|---|
| 263 | ! Using Lookup tables |
|---|
| 264 | do i=1,ngrid |
|---|
| 265 | do j=1,nlayer |
|---|
| 266 | if (ntot(i,j).gt.1000.) then ! activating coagulation above this threshold |
|---|
| 267 | pt0=pt(i,j) |
|---|
| 268 | rho0=rho(i,j) |
|---|
| 269 | mfp0=mfp(pt0,rho0) |
|---|
| 270 | pres0=pplay(i,j) |
|---|
| 271 | !find the corners for interpolation |
|---|
| 272 | t2=findval(table_pt,pt0) |
|---|
| 273 | if (t2==0) t2=table_numt |
|---|
| 274 | if (t2==1) t2=2 |
|---|
| 275 | t1=t2-1 |
|---|
| 276 | m2=findval(table_mfp,mfp0) |
|---|
| 277 | if (m2==0) m2=table_numm |
|---|
| 278 | if (m2==1) m2=2 |
|---|
| 279 | m1=m2-1 |
|---|
| 280 | p2=findval(table_pres,pres0) |
|---|
| 281 | if (p2==0) p2=table_numt |
|---|
| 282 | if (p2==1) p2=2 |
|---|
| 283 | p1=p2-1 |
|---|
| 284 | |
|---|
| 285 | ! Bin loop |
|---|
| 286 | do k=1,nres_coag |
|---|
| 287 | |
|---|
| 288 | ! Term 1 |
|---|
| 289 | term1=0. |
|---|
| 290 | do jj=1,k |
|---|
| 291 | do ii=1,k-1 |
|---|
| 292 | kernel=0. |
|---|
| 293 | if (kernel_b) kernel=kernel+boxinterp(table_b(t1,m1,ii,jj), & |
|---|
| 294 | table_b(t1,m2,ii,jj), & |
|---|
| 295 | table_b(t2,m1,ii,jj), & |
|---|
| 296 | table_b(t2,m2,ii,jj), & |
|---|
| 297 | table_pt(t1),table_pt(t2),log10(table_mfp(m1)),log10(table_mfp(m2)),pt0,log10(mfp0)) |
|---|
| 298 | if (kernel_g) kernel=kernel+boxinterp(table_g(t1,m1,ii,jj), & |
|---|
| 299 | table_g(t1,m2,ii,jj), & |
|---|
| 300 | table_g(t2,m1,ii,jj), & |
|---|
| 301 | table_g(t2,m2,ii,jj), & |
|---|
| 302 | table_pt(t1),table_pt(t2),log10(table_mfp(m1)),log10(table_mfp(m2)),pt0,log10(mfp0)) |
|---|
| 303 | if (kernel_de) kernel=kernel+boxinterp(table_de(t1,p1,ii,jj), & |
|---|
| 304 | table_de(t1,p2,ii,jj), & |
|---|
| 305 | table_de(t2,p1,ii,jj), & |
|---|
| 306 | table_de(t2,p2,ii,jj), & |
|---|
| 307 | table_pt(t1),table_pt(t2),log10(table_pres(p1)),log10(table_pres(p2)),pt0,log10(pres0)) |
|---|
| 308 | ! if (kernel_ti) kernel=kernel+betati(pt0,mfp0,rho(i,j,l),ii,jj) !not implemented yet |
|---|
| 309 | term1=term1+frac(ii,jj,k)*vols_coag(ii)*kernel*ndis_new(i,j,ii)*ndis(i,j,jj) |
|---|
| 310 | enddo |
|---|
| 311 | enddo |
|---|
| 312 | term1=term1*ptimestep/vols_coag(k) |
|---|
| 313 | |
|---|
| 314 | |
|---|
| 315 | ! Term 2 |
|---|
| 316 | term2=0. |
|---|
| 317 | do jj=1,nres_coag |
|---|
| 318 | kernel=0. |
|---|
| 319 | if (kernel_b) kernel=kernel+boxinterp(table_b(t1,m1,k,jj), & |
|---|
| 320 | table_b(t1,m2,k,jj), & |
|---|
| 321 | table_b(t2,m1,k,jj), & |
|---|
| 322 | table_b(t2,m2,k,jj), & |
|---|
| 323 | table_pt(t1),table_pt(t2),log10(table_mfp(m1)),log10(table_mfp(m2)),pt0,log10(mfp0)) |
|---|
| 324 | if (kernel_g) kernel=kernel+boxinterp(table_g(t1,m1,k,jj), & |
|---|
| 325 | table_g(t1,m2,k,jj), & |
|---|
| 326 | table_g(t2,m1,k,jj), & |
|---|
| 327 | table_g(t2,m2,k,jj), & |
|---|
| 328 | table_pt(t1),table_pt(t2),log10(table_mfp(m1)),log10(table_mfp(m2)),pt0,log10(mfp0)) |
|---|
| 329 | if (kernel_de) kernel=kernel+boxinterp(table_de(t1,p1,k,jj), & |
|---|
| 330 | table_de(t1,p2,k,jj), & |
|---|
| 331 | table_de(t2,p1,k,jj), & |
|---|
| 332 | table_de(t2,p2,k,jj), & |
|---|
| 333 | table_pt(t1),table_pt(t2),log10(table_pres(p1)),log10(table_pres(p2)),pt0,log10(pres0)) |
|---|
| 334 | ! if (kernel_ti) kernel=kernel+betati(pt0,mfp0,rho(i,j,l),k,jj) !not implemented yet |
|---|
| 335 | term2=term2+(1-frac(k,jj,k))*kernel*ndis(i,j,jj) |
|---|
| 336 | enddo |
|---|
| 337 | term2=term2*ptimestep |
|---|
| 338 | |
|---|
| 339 | ndis_new(i,j,k)=(ndis(i,j,k)+coal_fac*term1)/(1.+coal_fac*term2) |
|---|
| 340 | enddo |
|---|
| 341 | |
|---|
| 342 | !! Volume conservation |
|---|
| 343 | norm=sum(ndis(i,j,:)*vols_coag(:))/sum(ndis_new(i,j,:)*vols_coag(:)) |
|---|
| 344 | ndis_new(i,j,:)=ndis_new(i,j,:)*norm |
|---|
| 345 | |
|---|
| 346 | endif |
|---|
| 347 | |
|---|
| 348 | enddo |
|---|
| 349 | enddo |
|---|
| 350 | endif ! fullcoag |
|---|
| 351 | |
|---|
| 352 | !----------------------------------------------------------------------- |
|---|
| 353 | !*** 3) new moments mass and number |
|---|
| 354 | !----------------------------------------------------------------------- |
|---|
| 355 | mtotnew(:,:)=1.d-15 |
|---|
| 356 | |
|---|
| 357 | do iq=1,nq |
|---|
| 358 | if ((iq.eq.igcm_dust_mass).or.(iq.eq.igcm_stormdust_mass).or.(iq.eq.igcm_topdust_mass)) then |
|---|
| 359 | !! Estimate new distribution in each dust mode using the initial number ratios |
|---|
| 360 | ndis_tab_new(:,:,:,iq)=ndis_new(:,:,:)*rat_tab(:,:,:,iq) |
|---|
| 361 | |
|---|
| 362 | do i=1,ngrid |
|---|
| 363 | do j=1,nlayer |
|---|
| 364 | !! New number and mass mixing ratio in each mode |
|---|
| 365 | numb_new(i,j,iq)=sum(ndis_tab_new(i,j,:,iq))/rho(i,j) |
|---|
| 366 | mass_new(i,j,iq)=sum(ndis_tab_new(i,j,:,iq)*vols_coag(:))*dens/rho(i,j) |
|---|
| 367 | enddo |
|---|
| 368 | enddo |
|---|
| 369 | |
|---|
| 370 | !! New total mass |
|---|
| 371 | mtotnew(:,:)=mtotnew(:,:)+mass_new(:,:,iq) |
|---|
| 372 | endif |
|---|
| 373 | enddo |
|---|
| 374 | |
|---|
| 375 | do iq=1,nq |
|---|
| 376 | if ((iq.eq.igcm_dust_mass).or.(iq.eq.igcm_stormdust_mass).or.(iq.eq.igcm_topdust_mass)) then |
|---|
| 377 | !! mass conservation |
|---|
| 378 | mass_new(:,:,iq)=mass_new(:,:,iq)/mtotnew(:,:)*mtot(:,:) |
|---|
| 379 | !! New tendancy |
|---|
| 380 | pdqcoag(:,:,iq)=(mass_new(:,:,iq)-mass_ini(:,:,iq))/ptimestep |
|---|
| 381 | !pdqcoag(:,:,iq-1)=(numb_new(:,:,iq)-numb_ini(:,:,iq))/ptimestep |
|---|
| 382 | pdqcoag(:,:,iq-1)=(numb_new(:,:,iq)-numb_ini_dis(:,:,iq))/ptimestep |
|---|
| 383 | !! check |
|---|
| 384 | where (zq(:,:,iq)+pdqcoag(:,:,iq)*ptimestep.le.0.) |
|---|
| 385 | pdqcoag(:,:,iq)=-zq(:,:,iq)/ptimestep+1.e-15 |
|---|
| 386 | end where |
|---|
| 387 | where (zq(:,:,iq-1)+pdqcoag(:,:,iq-1)*ptimestep.le.0.) |
|---|
| 388 | pdqcoag(:,:,iq-1)=-zq(:,:,iq-1)/ptimestep+1.e-14 |
|---|
| 389 | end where |
|---|
| 390 | endif |
|---|
| 391 | enddo |
|---|
| 392 | |
|---|
| 393 | end subroutine coagul_main |
|---|
| 394 | |
|---|
| 395 | |
|---|
| 396 | !====================================================================== |
|---|
| 397 | !====================================================================== |
|---|
| 398 | real function dynvis(pt) |
|---|
| 399 | implicit none |
|---|
| 400 | ! dynamic viscosity following sutherland's formula for CO2 |
|---|
| 401 | ! Pa.s = kg m-1 s-1 |
|---|
| 402 | real, intent(in) :: pt |
|---|
| 403 | dynvis=1.37e-5*(273.15 + 222.)/(pt + 222.)*(pt/273.15)**(3./2.) |
|---|
| 404 | end function dynvis |
|---|
| 405 | |
|---|
| 406 | real function kinvis(pt,rho) |
|---|
| 407 | implicit none |
|---|
| 408 | real, intent(in) :: pt,rho |
|---|
| 409 | kinvis=dynvis(pt)/rho |
|---|
| 410 | end function kinvis |
|---|
| 411 | |
|---|
| 412 | real function thervel(pt,massm) |
|---|
| 413 | implicit none |
|---|
| 414 | ! thermal velocity of an air molecule or a dust particle |
|---|
| 415 | ! m s-1 |
|---|
| 416 | real, intent(in) :: pt, massm |
|---|
| 417 | thervel=(8*kbz*pt/(pi*massm))**0.5 |
|---|
| 418 | end function thervel |
|---|
| 419 | |
|---|
| 420 | real function mfp(pt,rho) |
|---|
| 421 | implicit none |
|---|
| 422 | ! thermal velocity of an air molecule |
|---|
| 423 | ! m s-1 |
|---|
| 424 | real, intent(in) :: pt, rho |
|---|
| 425 | mfp=2.*kinvis(pt,rho)/thervel(pt,m0co2) ! mean free path (m) |
|---|
| 426 | end function mfp |
|---|
| 427 | |
|---|
| 428 | real function cun(pt,mfp,rad) |
|---|
| 429 | implicit none |
|---|
| 430 | !! Cunningham slip flow correction |
|---|
| 431 | real, intent(in) :: pt, mfp, rad |
|---|
| 432 | cun=1.+mfp/rad*(1.246+0.42*exp(-0.87/(mfp/rad))) |
|---|
| 433 | end function cun |
|---|
| 434 | |
|---|
| 435 | real function diff(pt,mfp,rad) |
|---|
| 436 | implicit none |
|---|
| 437 | !! diffusion coefficient |
|---|
| 438 | real, intent(in) :: pt, mfp, rad |
|---|
| 439 | diff=kbz*pt/(6.*pi*rad*dynvis(pt))*cun(pt,mfp,rad) |
|---|
| 440 | end function diff |
|---|
| 441 | |
|---|
| 442 | real function lambda(pt, mfp, rad) |
|---|
| 443 | implicit none |
|---|
| 444 | !! particle mean free path |
|---|
| 445 | real, intent(in) :: pt,mfp,rad |
|---|
| 446 | real massm,dens |
|---|
| 447 | dens = rho_dust ! density dust |
|---|
| 448 | massm=dens*4./3.*pi*rad**3 |
|---|
| 449 | lambda=2.*diff(pt, mfp, rad)/(pi*thervel(pt,massm)) |
|---|
| 450 | end function lambda |
|---|
| 451 | |
|---|
| 452 | real function delta(pt,mfp,rad) |
|---|
| 453 | implicit none |
|---|
| 454 | !! mean distance |
|---|
| 455 | real, intent(in) :: pt,mfp,rad |
|---|
| 456 | real :: ltmp |
|---|
| 457 | |
|---|
| 458 | ltmp=lambda(pt,mfp,rad) |
|---|
| 459 | delta=( (2.*rad+ltmp)**3 - (4.*rad**2+ltmp**2)**1.5 ) /(6*rad*ltmp) - 2*rad |
|---|
| 460 | end function delta |
|---|
| 461 | |
|---|
| 462 | real function fallv(pt,mfp,rad) |
|---|
| 463 | implicit none |
|---|
| 464 | !! fall velocity |
|---|
| 465 | real, intent(in) :: pt,mfp,rad |
|---|
| 466 | real dens |
|---|
| 467 | dens = rho_dust ! density dust |
|---|
| 468 | fallv=2./9.*rad**2*dens*g/dynvis(pt)*cun(pt,mfp,rad) |
|---|
| 469 | end function fallv |
|---|
| 470 | |
|---|
| 471 | real function reyn(pt,mfp,rad,rho) |
|---|
| 472 | implicit none |
|---|
| 473 | !! Reynold number |
|---|
| 474 | real, intent(in) :: pt,rad,mfp,rho |
|---|
| 475 | reyn=2.*rad*fallv(pt,mfp,rad)/kinvis(pt,rho) |
|---|
| 476 | end function reyn |
|---|
| 477 | |
|---|
| 478 | real function stokes(pt,mfp,rad1,rad2) |
|---|
| 479 | implicit none |
|---|
| 480 | !! Stokes number |
|---|
| 481 | real, intent(in) :: pt,mfp,rad1,rad2 |
|---|
| 482 | real :: f1 |
|---|
| 483 | |
|---|
| 484 | f1=fallv(pt,mfp,rad1) |
|---|
| 485 | stokes=f1*abs(fallv(pt,mfp,rad2)-f1)/(rad2*g) |
|---|
| 486 | end function stokes |
|---|
| 487 | |
|---|
| 488 | real function schmidt(pt,mfp,rho,rad) |
|---|
| 489 | implicit none |
|---|
| 490 | !! Schmidt number |
|---|
| 491 | real, intent(in) :: pt,mfp,rho,rad |
|---|
| 492 | schmidt=kinvis(pt,rho)/diff(pt,mfp,rad) |
|---|
| 493 | end function schmidt |
|---|
| 494 | |
|---|
| 495 | real function coal(pt,mfp,rad1,rad2,rho) |
|---|
| 496 | implicit none |
|---|
| 497 | !! Coalescence efficiency |
|---|
| 498 | real, intent(in) :: pt,mfp,rad1,rad2,rho |
|---|
| 499 | real :: coalea,coalev |
|---|
| 500 | real :: stmp,rtmp |
|---|
| 501 | |
|---|
| 502 | stmp=stokes(pt,mfp,rad1,rad2) |
|---|
| 503 | rtmp=reyn(pt,mfp,rad2,rho) |
|---|
| 504 | coalea=stmp**2/(stmp+0.5)**2 |
|---|
| 505 | if (stmp>1.214) then |
|---|
| 506 | coalev=(1+0.75*log(2.*stmp)/(stmp-1.214))**(-2) |
|---|
| 507 | else |
|---|
| 508 | coalev=0. |
|---|
| 509 | endif |
|---|
| 510 | coal=(60.*coalev+coalea*rtmp)/(60.+rtmp) |
|---|
| 511 | end function coal |
|---|
| 512 | |
|---|
| 513 | real function betab(pt,mfp,rad1,rad2) |
|---|
| 514 | implicit none |
|---|
| 515 | real, intent(in) :: pt,mfp,rad1,rad2 |
|---|
| 516 | real :: m1,m2,num,den1,den2 |
|---|
| 517 | real :: dens |
|---|
| 518 | real :: d1,d2 |
|---|
| 519 | |
|---|
| 520 | dens = rho_dust ! density dust |
|---|
| 521 | d1=diff(pt,mfp,rad1) |
|---|
| 522 | d2=diff(pt,mfp,rad2) |
|---|
| 523 | !! kernel transition regime |
|---|
| 524 | ! Mass of 1 particle 1 and 2 |
|---|
| 525 | m1=dens*4./3.*pi*rad1**3 |
|---|
| 526 | m2=dens*4./3.*pi*rad2**3 |
|---|
| 527 | num=4.*pi*(rad1+rad2)*(d1+d2) |
|---|
| 528 | den1=(rad1+rad2)/(rad1+rad2+(delta(pt,mfp,rad1)**2+delta(pt,mfp,rad2)**2)**0.5) |
|---|
| 529 | den2=4./effb*(d1+d2)/((thervel(pt,m1)**2+thervel(pt,m2)**2)**0.5*(rad1+rad2)) |
|---|
| 530 | betab=num/(den1+den2) |
|---|
| 531 | end function betab |
|---|
| 532 | |
|---|
| 533 | real function betag(pt,mfp,rad1,rad2) |
|---|
| 534 | implicit none |
|---|
| 535 | real, intent(in) :: pt,mfp,rad1,rad2 |
|---|
| 536 | real w1,w2,ee |
|---|
| 537 | real :: radt |
|---|
| 538 | !! kernel gravitation |
|---|
| 539 | ! fall vel |
|---|
| 540 | w1=fallv(pt,mfp,rad1) |
|---|
| 541 | w2=fallv(pt,mfp,rad2) |
|---|
| 542 | radt=(rad1+rad2)**2 |
|---|
| 543 | if (coal_kg.eq.0) then ! E=1 |
|---|
| 544 | ee=1. |
|---|
| 545 | elseif (coal_kg.eq.1) then |
|---|
| 546 | ee=1.5*(min(rad1,rad2))**2/radt |
|---|
| 547 | elseif (coal_kg.eq.2) then |
|---|
| 548 | ee=0.25*(min(rad1,rad2))**2/radt |
|---|
| 549 | endif |
|---|
| 550 | !b=coal(pt,r1,r2)*pi*(r1+r2)**2*abs(w1-w2) |
|---|
| 551 | betag=ee*pi*radt*abs(w1-w2) |
|---|
| 552 | end function betag |
|---|
| 553 | |
|---|
| 554 | real function betade(pt,mfp,rho,rad1,rad2) |
|---|
| 555 | implicit none |
|---|
| 556 | real, intent(in) :: pt,mfp,rad1,rad2,rho |
|---|
| 557 | real rd,sc |
|---|
| 558 | !! kernel diffusion enhancement |
|---|
| 559 | rd=reyn(pt,mfp,max(rad1,rad2),rho) |
|---|
| 560 | sc=schmidt(pt,mfp,rho,min(rad1,rad2)) |
|---|
| 561 | if (rd.le.1.) then |
|---|
| 562 | betade=betab(pt,mfp,rad1,rad2)*0.45*rd**(1/3.)*sc**(1/3.) |
|---|
| 563 | else |
|---|
| 564 | betade=betab(pt,mfp,rad1,rad2)*0.45*rd**(1/2.)*sc**(1/3.) |
|---|
| 565 | endif |
|---|
| 566 | end function betade |
|---|
| 567 | |
|---|
| 568 | real function betade_tabfunc(pt,pres,rad1,rad2) |
|---|
| 569 | implicit none |
|---|
| 570 | real, intent(in) :: pt,pres,rad1,rad2 |
|---|
| 571 | real rd,sc,rho,mf |
|---|
| 572 | !! kernel diffusion enhancement |
|---|
| 573 | rho=pres/(pt*r) |
|---|
| 574 | mf=mfp(pt,rho) |
|---|
| 575 | rd=reyn(pt,mf,max(rad1,rad2),rho) |
|---|
| 576 | sc=schmidt(pt,mf,rho,min(rad1,rad2)) |
|---|
| 577 | if (rd.le.1.) then |
|---|
| 578 | betade_tabfunc=betab(pt,mf,rad1,rad2)*0.45*rd**(1/3.)*sc**(1/3.) |
|---|
| 579 | else |
|---|
| 580 | betade_tabfunc=betab(pt,mf,rad1,rad2)*0.45*rd**(1/2.)*sc**(1/3.) |
|---|
| 581 | endif |
|---|
| 582 | end function betade_tabfunc |
|---|
| 583 | |
|---|
| 584 | real function betati(pt,mfp,rho,rad1,rad2) |
|---|
| 585 | implicit none |
|---|
| 586 | real, intent(in) :: pt,mfp,rad1,rad2,rho |
|---|
| 587 | real w1,w2,eps |
|---|
| 588 | ! fall vel |
|---|
| 589 | w1=fallv(pt,mfp,rad1) |
|---|
| 590 | w2=fallv(pt,mfp,rad2) |
|---|
| 591 | betati=eps**(0.75)*pi/(g*kinvis(pt,rho)**(0.25))*(rad1+rad2)**2*abs(w1-w2) |
|---|
| 592 | end function betati |
|---|
| 593 | |
|---|
| 594 | real function betati_tabfunc(pt,pres,rad1,rad2) |
|---|
| 595 | implicit none |
|---|
| 596 | real, intent(in) :: pt,rad1,rad2 |
|---|
| 597 | real w1,w2,eps,mf,rho,pres |
|---|
| 598 | rho=pres/(pt*r) |
|---|
| 599 | mf=mfp(pt,rho) |
|---|
| 600 | ! fall vel |
|---|
| 601 | w1=fallv(pt,mf,rad1) |
|---|
| 602 | w2=fallv(pt,mf,rad2) |
|---|
| 603 | betati_tabfunc=eps**(0.75)*pi/(g*kinvis(pt,rho)**(0.25))*(rad1+rad2)**2*abs(w1-w2) |
|---|
| 604 | end function betati_tabfunc |
|---|
| 605 | |
|---|
| 606 | real function frac(i,j,k) |
|---|
| 607 | implicit none |
|---|
| 608 | integer, intent(in) :: i,j,k |
|---|
| 609 | real vint |
|---|
| 610 | ! intermediate volume |
|---|
| 611 | vint=vols_coag(i)+vols_coag(j) |
|---|
| 612 | if (k.lt.nres_coag) then |
|---|
| 613 | if ( (vint.ge.vols_coag(k)) .and. (vint.lt.vols_coag(k+1))) then |
|---|
| 614 | frac=(vols_coag(k+1)-vint)/(vols_coag(k+1)-vols_coag(k))*vols_coag(k)/vint |
|---|
| 615 | return |
|---|
| 616 | endif |
|---|
| 617 | endif |
|---|
| 618 | if ((k.eq.nres_coag) .and. (vint.ge.vols_coag(k))) then |
|---|
| 619 | frac=1. |
|---|
| 620 | return |
|---|
| 621 | endif |
|---|
| 622 | if (k.gt.1) then |
|---|
| 623 | if ( (vint.lt.vols_coag(k)) .and. (vint.gt.vols_coag(k-1))) then |
|---|
| 624 | frac=(-vols_coag(k-1)+vint)/(-vols_coag(k-1)+vols_coag(k))*vols_coag(k)/vint |
|---|
| 625 | return |
|---|
| 626 | endif |
|---|
| 627 | endif |
|---|
| 628 | |
|---|
| 629 | frac=0. |
|---|
| 630 | return |
|---|
| 631 | end function frac |
|---|
| 632 | |
|---|
| 633 | ! ********************************************************* |
|---|
| 634 | ! Building lookup tables : called in the firstcall |
|---|
| 635 | ! ********************************************************* |
|---|
| 636 | |
|---|
| 637 | subroutine make_tables() |
|---|
| 638 | |
|---|
| 639 | implicit none |
|---|
| 640 | integer :: i,j,k,l |
|---|
| 641 | real :: t1,t2,p1,p2 |
|---|
| 642 | |
|---|
| 643 | do i = 1,table_numt |
|---|
| 644 | table_pt(i)=50.+25.*real(i) |
|---|
| 645 | end do |
|---|
| 646 | |
|---|
| 647 | do j = 1,table_nump |
|---|
| 648 | table_pres(j)=(1.e-8)*10.**(real(j)/2.) |
|---|
| 649 | end do |
|---|
| 650 | |
|---|
| 651 | do j = 1,table_numm |
|---|
| 652 | table_mfp(j)=(1.e-8)*10.**(real(j)/2.) |
|---|
| 653 | end do |
|---|
| 654 | |
|---|
| 655 | do i = 1,table_numt |
|---|
| 656 | do j = 1,table_numm |
|---|
| 657 | do k = 1,nres_coag |
|---|
| 658 | do l = 1,nres_coag |
|---|
| 659 | table_b(i,j,k,l)=betab(table_pt(i),table_mfp(j),rads_coag(k),rads_coag(l)) |
|---|
| 660 | table_g(i,j,k,l)=betag(table_pt(i),table_mfp(j),rads_coag(k),rads_coag(l)) |
|---|
| 661 | end do |
|---|
| 662 | end do |
|---|
| 663 | end do |
|---|
| 664 | end do |
|---|
| 665 | |
|---|
| 666 | do i = 1,table_numt |
|---|
| 667 | do j = 1,table_nump |
|---|
| 668 | do k = 1,nres_coag |
|---|
| 669 | do l = 1,nres_coag |
|---|
| 670 | table_de(i,j,k,l)=betade_tabfunc(table_pt(i),table_pres(j),rads_coag(k),rads_coag(l)) |
|---|
| 671 | end do |
|---|
| 672 | end do |
|---|
| 673 | end do |
|---|
| 674 | end do |
|---|
| 675 | |
|---|
| 676 | end subroutine make_tables |
|---|
| 677 | |
|---|
| 678 | !======================================================================C |
|---|
| 679 | !======================================================================C |
|---|
| 680 | |
|---|
| 681 | real function boxinterp(ft1p1,ft2p1,ft1p2,ft2p2,tref1,tref2,pref1, & |
|---|
| 682 | pref2,tmid,pmid) |
|---|
| 683 | ! |
|---|
| 684 | ! Calculate 2d interpolation from pressure and temperature |
|---|
| 685 | !----------------------------------------------------------------------! |
|---|
| 686 | ! T2 .FT2P1 .FT2P2 |
|---|
| 687 | ! |
|---|
| 688 | ! |
|---|
| 689 | ! T1 .FT1P1 .FT1P2 |
|---|
| 690 | ! P1 P2 |
|---|
| 691 | !----------------------------------------------------------------------! |
|---|
| 692 | |
|---|
| 693 | implicit none |
|---|
| 694 | |
|---|
| 695 | real :: ft1p1, ft2p1, ft1p2, ft2p2, tref1, tref2 |
|---|
| 696 | real :: pref1, pref2, tmid, pmid, ans1, ans2, ans |
|---|
| 697 | |
|---|
| 698 | !======================================================================C |
|---|
| 699 | |
|---|
| 700 | ans1 = ft1p1 + (ft2p1 - ft1p1)*(tmid - tref1)/(tref2 - tref1) |
|---|
| 701 | ans2 = ft1p2 + (ft2p2 - ft1p2)*(tmid - tref1)/(tref2 - tref1) |
|---|
| 702 | boxinterp = ans1 + (ans2 - ans1)*(pmid - pref1)/(pref2 - pref1) |
|---|
| 703 | |
|---|
| 704 | end function boxinterp |
|---|
| 705 | |
|---|
| 706 | !======================================================================C |
|---|
| 707 | !======================================================================C |
|---|
| 708 | |
|---|
| 709 | integer function findval(array,value) |
|---|
| 710 | implicit none |
|---|
| 711 | real :: array(:) |
|---|
| 712 | real :: value |
|---|
| 713 | |
|---|
| 714 | findval=minloc(array,dim=1,mask = (array > value)) |
|---|
| 715 | |
|---|
| 716 | end function findval |
|---|
| 717 | |
|---|
| 718 | end module coagulation_mod |
|---|
| 719 | |
|---|