SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

最近接到一个任务,就是解决FVCOM中对流扩散计算不守衡问题。导师认为是其求解时候水平和垂向计算分开求解所导致的,目前我也没搞清到底有什么问题,反正就是让把SUNTANS的对流扩散计算挪到FVCOM中,下面就把 SUNTANS 和 FVCOM 数值求解的过程贴出来,备忘

SUNTANS模型求解过程

SUNTANS模型手册:http://web.stanford.edu/group/suntans/cgi-bin/documentation/user_guide/user_guide.html

介绍文献:《An unstructured-grid, finite-volume, nonhydrostatic, parallel coastal ocean simulator》

代码所谓研究讨论之用这里只公布部分:

  1 /*
2 * File: scalars.c
3 * Author: Oliver B. Fringer
4 * Institution: Stanford University
5 * ----------------------------------------
6 * This file contains the scalar transport function.
7 *
8 * Copyright (C) 2005-2006 The Board of Trustees of the Leland Stanford Junior
9 * University. All Rights Reserved.
10 *
11 */
12 #include "scalars.h"
13 #include "util.h"
14 #include "tvd.h"
15 #include "initialization.h"
16
17 #define SMALL_CONSISTENCY 1e-5
18
19 REAL smin_value, smax_value;
20
21 /*
22 * Function: UpdateScalars
23 * Usage: UpdateScalars(grid,phys,prop,wnew,scalar,Cn,kappa,kappaH,kappa_tv,theta);
24 * ---------------------------------------------------------------------------
25 * Update the scalar quantity stored in the array denoted by scal using the
26 * theta method for vertical advection and vertical diffusion and Adams-Bashforth
27 * for horizontal advection and diffusion.
28 *
29 * Cn must store the AB terms from time step n-1 for this scalar
30 * kappa denotes the vertical scalar diffusivity
31 * kappaH denotes the horizontal scalar diffusivity
32 * kappa_tv denotes the vertical turbulent scalar diffusivity
33 *
34 */
35 void UpdateScalars(gridT *grid, physT *phys, propT *prop, REAL **wnew, REAL **scal, REAL **boundary_scal, REAL **Cn,
36 REAL kappa, REAL kappaH, REAL **kappa_tv, REAL theta,
37 REAL **src1, REAL **src2, REAL *Ftop, REAL *Fbot, int alpha_top, int alpha_bot,
38 MPI_Comm comm, int myproc, int checkflag, int TVDscheme)
39 {
40 int i, iptr, j, jptr, ib, k, nf, ktop;
41 int Nc=grid->Nc, normal, nc1, nc2, ne;
42 REAL df, dg, Ac, dt=prop->dt, fab, *a, *b, *c, *d, *ap, *am, *bd, *uflux, dznew, mass, *sp, *temp;
43 REAL smin, smax, div_local, div_da;
44 int k1, k2, kmin, imin, kmax, imax, mincount, maxcount, allmincount, allmaxcount, flag;
45
46 prop->TVD = TVDscheme;
47 // These are used mostly debugging to turn on/off vertical and horizontal TVD.
48 prop->horiTVD = 1;
49 prop->vertTVD = 1;
50
51 ap = phys->ap;
52 am = phys->am;
53 bd = phys->bp;
54 temp = phys->bm;
55 a = phys->a;
56 b = phys->b;
57 c = phys->c;
58 d = phys->d;
59
60 // Never use AB2
61 if(1) {
62 fab=1;
63 for(i=0;i<grid->Nc;i++)
64 for(k=0;k<grid->Nk[i];k++)
65 Cn[i][k]=0;
66 } else
67 fab=1.5;
68
69 for(i=0;i<Nc;i++)
70 for(k=0;k<grid->Nk[i];k++)
71 phys->stmp[i][k]=scal[i][k];
72
73 // Add on boundary fluxes, using stmp2 as the temporary storage
74 // variable
75 //for(iptr=grid->celldist[0];iptr<grid->celldist[1];iptr++) {
76 for(iptr=grid->celldist[0];iptr<grid->celldist[2];iptr++) {
77 i = grid->cellp[iptr];
78
79 for(k=grid->ctop[i];k<grid->Nk[i];k++)
80 phys->stmp2[i][k]=0;
81 }
82
83 if(boundary_scal) {
84 for(jptr=grid->edgedist[2];jptr<grid->edgedist[5];jptr++) {
85 j = grid->edgep[jptr];
86
87 ib = grid->grad[2*j];
88
89 // Set the value of stmp2 adjacent to the boundary to the value of the boundary.
90 // This will be used to add the boundary flux when stmp2 is used again below.
91 for(k=grid->ctop[ib];k<grid->Nk[ib];k++)
92 phys->stmp2[ib][k]=boundary_scal[jptr-grid->edgedist[2]][k];
93 }
94 }
95
96 // Compute the scalar on the vertical faces (for horiz. advection)
97
98 if(prop->TVD && prop->horiTVD)
99 HorizontalFaceScalars(grid,phys,prop,scal,boundary_scal,prop->TVD,comm,myproc);
100
101 //for(iptr=grid->celldist[0];iptr<grid->celldist[1];iptr++) {
102 for(iptr=grid->celldist[0];iptr<grid->celldist[2];iptr++) {
103 i = grid->cellp[iptr];
104 Ac = grid->Ac[i];
105
106 if(grid->ctop[i]>=grid->ctopold[i]) {
107 ktop=grid->ctop[i];
108 dznew=grid->dzz[i][ktop];
109 } else {
110 ktop=grid->ctopold[i];
111 dznew=0;
112 for(k=grid->ctop[i];k<=grid->ctopold[i];k++)
113 dznew+=grid->dzz[i][k];
114 }
115
116 // These are the advective components of the tridiagonal
117 // at the new time step.
118 if(!(prop->TVD && prop->vertTVD))
119 for(k=0;k<grid->Nk[i]+1;k++) {
120 ap[k] = 0.5*(wnew[i][k]+fabs(wnew[i][k]));
121 am[k] = 0.5*(wnew[i][k]-fabs(wnew[i][k]));
122 }
123 else // Compute the ap/am for TVD schemes
124 GetApAm(ap,am,phys->wp,phys->wm,phys->Cp,phys->Cm,phys->rp,phys->rm,
125 wnew,grid->dzz,scal,i,grid->Nk[i],ktop,prop->dt,prop->TVD);
126
127 for(k=ktop+1;k<grid->Nk[i];k++) {
128 a[k-ktop]=theta*dt*am[k];
129 b[k-ktop]=grid->dzz[i][k]+theta*dt*(ap[k]-am[k+1]);
130 c[k-ktop]=-theta*dt*ap[k+1];
131 }
132
133 // Top cell advection
134 a[0]=0;
135 b[0]=dznew-theta*dt*am[ktop+1];
136 c[0]=-theta*dt*ap[ktop+1];
137
138 // Bottom cell no-flux boundary condition for advection
139 b[(grid->Nk[i]-1)-ktop]+=c[(grid->Nk[i]-1)-ktop];
140
141 // Implicit vertical diffusion terms
142 for(k=ktop+1;k<grid->Nk[i];k++)
143 bd[k]=(2.0*kappa+kappa_tv[i][k-1]+kappa_tv[i][k])/
144 (grid->dzz[i][k-1]+grid->dzz[i][k]);
145
146 for(k=ktop+1;k<grid->Nk[i]-1;k++) {
147 a[k-ktop]-=theta*dt*bd[k];
148 b[k-ktop]+=theta*dt*(bd[k]+bd[k+1]);
149 c[k-ktop]-=theta*dt*bd[k+1];
150 }
151 if(src1)
152 for(k=ktop;k<grid->Nk[i];k++)
153 b[k-ktop]+=grid->dzz[i][k]*src1[i][k]*theta*dt;
154
155 // Diffusive fluxes only when more than 1 layer
156 if(ktop<grid->Nk[i]-1) {
157 // Top cell diffusion
158 b[0]+=theta*dt*(bd[ktop+1]+2*alpha_top*bd[ktop+1]);
159 c[0]-=theta*dt*bd[ktop+1];
160
161 // Bottom cell diffusion
162 a[(grid->Nk[i]-1)-ktop]-=theta*dt*bd[grid->Nk[i]-1];
163 b[(grid->Nk[i]-1)-ktop]+=theta*dt*(bd[grid->Nk[i]-1]+2*alpha_bot*bd[grid->Nk[i]-1]);
164 }
165
166 // Explicit part into source term d[]
167 for(k=ktop+1;k<grid->Nk[i];k++)
168 d[k-ktop]=grid->dzzold[i][k]*phys->stmp[i][k];
169 if(src1)
170 for(k=ktop+1;k<grid->Nk[i];k++)
171 d[k-ktop]-=src1[i][k]*(1-theta)*dt*grid->dzzold[i][k]*phys->stmp[i][k];
172
173 d[0]=0;
174 if(grid->ctopold[i]<=grid->ctop[i]) {
175 for(k=grid->ctopold[i];k<=grid->ctop[i];k++)
176 d[0]+=grid->dzzold[i][k]*phys->stmp[i][k];
177 if(src1)
178 for(k=grid->ctopold[i];k<=grid->ctop[i];k++)
179 d[0]-=src1[i][k]*(1-theta)*dt*grid->dzzold[i][k]*phys->stmp[i][k];
180 } else {
181 d[0]=grid->dzzold[i][ktop]*phys->stmp[i][ktop];
182 if(src1)
183 d[0]-=src1[i][ktop]*(1-theta)*dt*grid->dzzold[i][ktop]*phys->stmp[i][k];
184 }
185
186 // These are the advective components of the tridiagonal
187 // that use the new velocity
188 if(!(prop->TVD && prop->vertTVD))
189 for(k=0;k<grid->Nk[i]+1;k++) {
190 ap[k] = 0.5*(phys->wtmp2[i][k]+fabs(phys->wtmp2[i][k]));
191 am[k] = 0.5*(phys->wtmp2[i][k]-fabs(phys->wtmp2[i][k]));
192 }
193 else // Compute the ap/am for TVD schemes
194 GetApAm(ap,am,phys->wp,phys->wm,phys->Cp,phys->Cm,phys->rp,phys->rm,
195 phys->wtmp2,grid->dzzold,phys->stmp,i,grid->Nk[i],ktop,prop->dt,prop->TVD);
196
197 // Explicit advection and diffusion
198 for(k=ktop+1;k<grid->Nk[i]-1;k++)
199 d[k-ktop]-=(1-theta)*dt*(am[k]*phys->stmp[i][k-1]+
200 (ap[k]-am[k+1])*phys->stmp[i][k]-
201 ap[k+1]*phys->stmp[i][k+1])-
202 (1-theta)*dt*(bd[k]*phys->stmp[i][k-1]
203 -(bd[k]+bd[k+1])*phys->stmp[i][k]
204 +bd[k+1]*phys->stmp[i][k+1]);
205
206 if(ktop<grid->Nk[i]-1) {
207 //Flux through bottom of top cell
208 k=ktop;
209 d[0]=d[0]-(1-theta)*dt*(-am[k+1]*phys->stmp[i][k]-
210 ap[k+1]*phys->stmp[i][k+1])+
211 (1-theta)*dt*(-(2*alpha_top*bd[k+1]+bd[k+1])*phys->stmp[i][k]+
212 bd[k+1]*phys->stmp[i][k+1]);
213 if(Ftop) d[0]+=dt*(1-alpha_top+2*alpha_top*bd[k+1])*Ftop[i];
214
215 // Through top of bottom cell
216 k=grid->Nk[i]-1;
217 d[k-ktop]-=(1-theta)*dt*(am[k]*phys->stmp[i][k-1]+
218 ap[k]*phys->stmp[i][k])-
219 (1-theta)*dt*(bd[k]*phys->stmp[i][k-1]-
220 (bd[k]+2*alpha_bot*bd[k])*phys->stmp[i][k]);
221 if(Fbot) d[k-ktop]+=dt*(-1+alpha_bot+2*alpha_bot*bd[k])*Fbot[i];
222 }
223
224 // First add on the source term from the previous time step.
225 if(grid->ctop[i]<=grid->ctopold[i]) {
226 for(k=grid->ctop[i];k<=grid->ctopold[i];k++)
227 d[0]+=(1-fab)*Cn[i][grid->ctopold[i]]/(1+fabs(grid->ctop[i]-grid->ctopold[i]));
228 for(k=grid->ctopold[i]+1;k<grid->Nk[i];k++)
229 d[k-grid->ctopold[i]]+=(1-fab)*Cn[i][k];
230 } else {
231 for(k=grid->ctopold[i];k<=grid->ctop[i];k++)
232 d[0]+=(1-fab)*Cn[i][k];
233 for(k=grid->ctop[i]+1;k<grid->Nk[i];k++)
234 d[k-grid->ctop[i]]+=(1-fab)*Cn[i][k];
235 }
236
237 for(k=0;k<grid->ctop[i];k++)
238 Cn[i][k]=0;
239
240 if(src2)
241 for(k=grid->ctop[i];k<grid->Nk[i];k++)
242 Cn[i][k-ktop]=dt*src2[i][k]*grid->dzzold[i][k];
243 else
244 for(k=grid->ctop[i];k<grid->Nk[i];k++)
245 Cn[i][k]=0;
246
247 // Now create the source term for the current time step
248 for(k=0;k<grid->Nk[i];k++)
249 ap[k]=0;
250
251 for(nf=0;nf<grid->nfaces[i];nf++) {
252 ne = grid->face[i*grid->maxfaces+nf];
253 normal = grid->normal[i*grid->maxfaces+nf];
254 df = grid->df[ne];
255 dg = grid->dg[ne];
256 nc1 = grid->grad[2*ne];
257 nc2 = grid->grad[2*ne+1];
258 if(nc1==-1) nc1=nc2;
259 if(nc2==-1) {
260 nc2=nc1;
261 if(boundary_scal && (grid->mark[ne]==2 || grid->mark[ne]==3))
262 sp=phys->stmp2[nc1];
263 else
264 sp=phys->stmp[nc1];
265 } else
266 sp=phys->stmp[nc2];
267
268 if(!(prop->TVD && prop->horiTVD)) {
269 for(k=0;k<grid->Nke[ne];k++)
270 temp[k]=UpWind(phys->utmp2[ne][k],
271 phys->stmp[nc1][k],
272 sp[k]);
273 } else {
274 for(k=0;k<grid->Nke[ne];k++)
275 if(phys->utmp2[ne][k]>0)
276 temp[k]=phys->SfHp[ne][k];
277 else
278 temp[k]=phys->SfHm[ne][k];
279 }
280
281 for(k=0;k<grid->Nke[ne];k++)
282 ap[k] += dt*df*normal/Ac*(theta*phys->u[ne][k]+(1-theta)*phys->utmp2[ne][k])
283 *temp[k]*grid->dzf[ne][k];
284 }
285
286 for(k=ktop+1;k<grid->Nk[i];k++)
287 Cn[i][k-ktop]-=ap[k];
288
289 for(k=0;k<=ktop;k++)
290 Cn[i][0]-=ap[k];
291
292 // Add on the source from the current time step to the rhs.
293 for(k=0;k<grid->Nk[i]-ktop;k++)
294 d[k]+=fab*Cn[i][k];
295
296 // Add on the volume correction if h was < -d
297 /*
298 if(grid->ctop[i]==grid->Nk[i]-1)
299 d[grid->Nk[i]-ktop-1]+=phys->hcorr[i]*phys->stmp[i][grid->ctop[i]];
300 */
301
302 for(k=ktop;k<grid->Nk[i];k++)
303 ap[k]=Cn[i][k-ktop];
304 for(k=0;k<=ktop;k++)
305 Cn[i][k]=0;
306 for(k=ktop+1;k<grid->Nk[i];k++)
307 Cn[i][k]=ap[k];
308 for(k=grid->ctop[i];k<=ktop;k++)
309 Cn[i][k]=ap[ktop]/(1+fabs(grid->ctop[i]-ktop));
310
311 if(grid->Nk[i]-ktop>1)
312 TriSolve(a,b,c,d,&(scal[i][ktop]),grid->Nk[i]-ktop);
313 else if(prop->n>1) {
314 if(b[0]>0 && phys->active[i])
315 scal[i][ktop]=d[0]/b[0];
316 else
317 scal[i][ktop]=0;
318 }
319
320 for(k=0;k<grid->ctop[i];k++)
321 scal[i][k]=0;
322
323 for(k=grid->ctop[i];k<grid->ctopold[i];k++)
324 scal[i][k]=scal[i][ktop];
325 }
326
327 // Code to check divergence change CHECKCONSISTENCY to 1 in suntans.h
328 if(CHECKCONSISTENCY && checkflag) {
329
330 if(prop->n==1+prop->nstart) {
331 smin=INFTY;
332 smax=-INFTY;
333 for(i=0;i<grid->Nc;i++) {
334 for(k=grid->ctop[i];k<grid->Nk[i];k++) {
335 if(phys->stmp[i][k]>smax) {
336 smax=phys->stmp[i][k];
337 imax=i;
338 kmax=k;
339 }
340 if(phys->stmp[i][k]<smin) {
341 smin=phys->stmp[i][k];
342 imin=i;
343 kmin=k;
344 }
345 }
346 }
347 MPI_Reduce(&smin,&smin_value,1,MPI_DOUBLE,MPI_MIN,0,comm);
348 MPI_Reduce(&smax,&smax_value,1,MPI_DOUBLE,MPI_MAX,0,comm);
349 MPI_Bcast(&smin_value,1,MPI_DOUBLE,0,comm);
350 MPI_Bcast(&smax_value,1,MPI_DOUBLE,0,comm);
351
352 if(myproc==0)
353 printf("Minimum scalar: %.2f, maximum: %.2f\n",smin_value,smax_value);
354 }
355
356 //for(iptr=grid->celldist[0];iptr<grid->celldist[1];iptr++) {
357 for(iptr=grid->celldist[0];iptr<grid->celldist[2];iptr++) {
358 i = grid->cellp[iptr];
359
360 flag=0;
361 for(nf=0;nf<grid->nfaces[i];nf++) {
362 if(grid->mark[grid->face[i*grid->maxfaces+nf]]==2 ||
363 grid->mark[grid->face[i*grid->maxfaces+nf]]==3) {
364 flag=1;
365 break;
366 }
367 }
368
369 if(!flag) {
370 div_da=0;
371
372 for(k=0;k<grid->Nk[i];k++) {
373 div_da+=grid->Ac[i]*(grid->dzz[i][k]-grid->dzzold[i][k])/prop->dt;
374
375 div_local=0;
376 for(nf=0;nf<grid->nfaces[i];nf++) {
377 ne=grid->face[i*grid->maxfaces+nf];
378 div_local+=(theta*phys->u[ne][k]+(1-theta)*phys->utmp2[ne][k])
379 *grid->dzf[ne][k]*grid->normal[i*grid->maxfaces+nf]*grid->df[ne];
380 }
381 div_da+=div_local;
382 div_local+=grid->Ac[i]*(theta*(wnew[i][k]-wnew[i][k+1])+
383 (1-theta)*(phys->wtmp2[i][k]-phys->wtmp2[i][k+1]));
384
385 if(k>=grid->ctop[i]) {
386 if(fabs(div_local)>SMALL_CONSISTENCY && grid->dzz[imin][0]>DRYCELLHEIGHT)
387 printf("Step: %d, proc: %d, locally-divergent at %d, %d, div=%e\n",
388 prop->n,myproc,i,k,div_local);
389 }
390 }
391 if(fabs(div_da)>SMALL_CONSISTENCY && phys->h[i]+grid->dv[i]>DRYCELLHEIGHT)
392 printf("Step: %d, proc: %d, Depth-Ave divergent at i=%d, div=%e\n",
393 prop->n,myproc,i,div_da);
394 }
395 }
396
397 mincount=0;
398 maxcount=0;
399 smin=INFTY;
400 smax=-INFTY;
401 //for(iptr=grid->celldist[0];iptr<grid->celldist[1];iptr++) {
402 for(iptr=grid->celldist[0];iptr<grid->celldist[2];iptr++) {
403 i = grid->cellp[iptr];
404
405 flag=0;
406 for(nf=0;nf<grid->nfaces[i];nf++) {
407 if(grid->mark[grid->face[i*grid->maxfaces+nf]]==2 || grid->mark[grid->face[i*grid->maxfaces+nf]]==3) {
408 flag=1;
409 break;
410 }
411 }
412
413 if(!flag) {
414 for(k=grid->ctop[i];k<grid->Nk[i];k++) {
415 if(scal[i][k]>smax) {
416 smax=scal[i][k];
417 imax=i;
418 kmax=k;
419 }
420 if(scal[i][k]<smin) {
421 smin=scal[i][k];
422 imin=i;
423 kmin=k;
424 }
425
426 if(scal[i][k]>smax_value+SMALL_CONSISTENCY && grid->dzz[i][k]>DRYCELLHEIGHT)
427 maxcount++;
428 if(scal[i][k]<smin_value-SMALL_CONSISTENCY && grid->dzz[i][k]>DRYCELLHEIGHT)
429 mincount++;
430 }
431 }
432 }
433 MPI_Reduce(&mincount,&allmincount,1,MPI_INT,MPI_SUM,0,comm);
434 MPI_Reduce(&maxcount,&allmaxcount,1,MPI_INT,MPI_SUM,0,comm);
435
436 if(mincount!=0 || maxcount!=0)
437 printf("Not CWC, step: %d, proc: %d, smin = %e at i=%d,H=%e, smax = %e at i=%d,H=%e\n",
438 prop->n,myproc,
439 smin,imin,phys->h[imin]+grid->dv[imin],
440 smax,imax,phys->h[imax]+grid->dv[imax]);
441
442 if(myproc==0 && (allmincount !=0 || allmaxcount !=0))
443 printf("Total number of CWC violations (all procs): s<s_min: %d, s>s_max: %d\n",
444 allmincount,allmaxcount);
445 }
446 }

下面介绍解读UpdateScalars函数过程:

1. 首先作为一个复杂的非静压N-S模型,变量比较多是很正常的,所以不要纠结每个变量是什么意思,能看懂就看,看不懂就猜好了。

2.要从整体入手。根据目前已知信息,这是用有限体积法求解对流扩散方程模块,而所求标量值应该就是就是第5个参数 **scal 所代表的变量。那么从函数最后一次更新 scal 变量的地方,或许能获得些许线索。

第311行:

      if(grid->Nk[i]-ktop>1) TriSolve(a,b,c,d,&(scal[i][ktop]),grid->Nk[i]-ktop);

检查 TriSolve 函数的定义,原来是求解三对角方程组的解法,a,b,c 分别是系数矩阵三个对角向量,d是等号右端常向量,未知数为以 scal[i][ktop] 起始的数组。

而准备a,b,c 等系数向量时,循环变量多是按照某个三棱柱各层从上到下进行循环,所以不难看出,这个方程组求解的应该就是某个三棱柱单元体内各层标量值大小。

3. 将程序数值离散过程和理论结合起来,了解程序细节

FVCOM 模型求解过程

FVCOM 也是使用有限体积方法,但是求解和 SUNTANS 有很大不同。由于FVCOM并没有介绍对流扩散方程求解具体过程的文献,这时程序看起来就比较头疼,只能全部通过读程序来一点点理解。

FVCOM 扩散方程计算主要在程序 mod_scal.F 中,模块内全部程序如下

  1 !/===========================================================================/
2 ! Copyright (c) 2007, The University of Massachusetts Dartmouth
3 ! Produced at the School of Marine Science & Technology
4 ! Marine Ecosystem Dynamics Modeling group
5 ! All rights reserved.
6 !
7 ! FVCOM has been developed by the joint UMASSD-WHOI research team. For
8 ! details of authorship and attribution of credit please see the FVCOM
9 ! technical manual or contact the MEDM group.
10 !
11 !
12 ! This file is part of FVCOM. For details, see http://fvcom.smast.umassd.edu
13 ! The full copyright notice is contained in the file COPYRIGHT located in the
14 ! root directory of the FVCOM code. This original header must be maintained
15 ! in all distributed versions.
16 !
17 ! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 ! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 ! THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 ! PURPOSE ARE DISCLAIMED.
21 !
22 !/---------------------------------------------------------------------------/
23 ! CVS VERSION INFORMATION
24 ! $Id$
25 ! $Name$
26 ! $Revision$
27 !/===========================================================================/
28
29 !=======================================================================
30 ! FVCOM Scalar Module
31 !
32 ! contains methods:
33 ! Adv_Scal => Advect a Scalar Quantity
34 ! Vdif_Scal => Vertical Diffusion of Scalar Quantity
35 ! Bcond_Scal_OBC => Open Boundary Condition for Scalar
36 ! Bcond_Scal_PTsource => Point Sources of Scalar
37 !=======================================================================
38 Module Scalar
39
40 logical, parameter :: debug = .true.
41
42 contains
43 !==============================================================================|
44 ! Calculate Horizontal Advection and Diffusion For Scalar (f) |
45 !==============================================================================|
46 Subroutine Adv_Scal(f,fn,d_fdis,fdis,d_fflux,fflux_obc,deltat,source)
47 !------------------------------------------------------------------------------|
48
49 use all_vars
50 use lims, only: m,mt,n,nt,kbm1,kb
51 use bcs
52 use mod_obcs
53 # if defined (MULTIPROCESSOR)
54 use mod_par
55 # endif
56 # if defined (WET_DRY)
57 use mod_wd
58 # endif
59
60 # if defined (THIN_DAM)
61 use mod_dam, only : kdam,N_DAM_MATCH,IS_DAM
62 # endif
63
64 implicit none
65 real(sp), intent(in ), dimension(0:mt,kb) :: f
66 real(sp), intent(out), dimension(0:mt,kb) :: fn
67 integer , intent(in ) :: d_fdis
68 real(sp), intent(in ), dimension(d_fdis) :: fdis
69 integer , intent(in ) :: d_fflux
70 real(sp), intent(out), dimension(d_fflux,kbm1) :: fflux_obc
71 real(sp), intent(in ) :: deltat
72 logical , intent(in ) :: source
73
74 !----------------local--------------------------------------
75 real(sp), dimension(0:mt,kb) :: xflux,xflux_adv
76 real(sp), dimension(m) :: pupx,pupy,pvpx,pvpy
77 real(sp), dimension(m) :: pfpx,pfpy,pfpxd,pfpyd,viscoff
78 real(sp), dimension(3*nt) :: dtij
79 real(sp), dimension(3*nt,kbm1) :: uvn
80 real(sp), dimension(kb) :: vflux
81 real(sp) :: utmp,vtmp,sitai,ffd,ff1,x11,y11,x22,y22,x33,y33
82 real(sp) :: tmp1,tmp2,xi,yi
83 real(sp) :: dxa,dya,dxb,dyb,fij1,fij2,un
84 real(sp) :: txx,tyy,fxx,fyy,viscof,exflux,temp,fpoint
85 real(sp) :: fact,fm1,fmean
86 integer :: i,i1,i2,ia,ib,j,j1,j2,k,jtmp,jj
87 # if defined (SPHERICAL)
88 real(sp) :: ty,txpi,typi
89 # endif
90
91 # if defined (THIN_DAM)
92 INTEGER :: NX
93 real(sp) :: tmpflx
94 real(sp),dimension(kb) :: wvel
95 # endif
96
97
98 !------------------------------------------------------------------------------!
99
100 !-------------------------------------------------------
101 !Calculate Mean Values
102 !-------------------------------------------------------
103
104 fmean = sum(f(1:m,1:kbm1))/float(m*kbm1)
105
106 !-------------------------------------------------------
107 !Initialize Multipliers to Control Horizontal Diff
108 !-------------------------------------------------------
109
110 fact = 0.0_sp
111 fm1 = 1.0_sp
112 if(HORIZONTAL_MIXING_TYPE == 'closure') then
113 fact = 1.0_sp
114 fm1 = 0.0_sp
115 end if
116
117 !-------------------------------------------------------
118 !Initialize Fluxes
119 !-------------------------------------------------------
120 xflux = 0.0_sp
121 xflux_adv = 0.0_sp
122
123 !-------------------------------------------------------
124 !Calculate Normal Velocity on Control Volume Edges
125 !-------------------------------------------------------
126 !!# if !defined (WET_DRY)
127 do i=1,ncv
128 i1=ntrg(i)
129 dtij(i)=dt1(i1)
130 do k=1,kbm1
131 uvn(i,k) = v(i1,k)*dltxe(i) - u(i1,k)*dltye(i)
132
133 # if defined(PLBC)
134 uvn(i,k) = - u(i1,k)*dltye(i)
135 # endif
136
137 end do
138 end do
139 !!# else
140 !! do i=1,ncv
141 !! i1=ntrg(i)
142 !! dtij(i)=dt1(i1)
143 !! do k=1,kbm1
144 !! uvn(i,k) = vs(i1,k)*dltxe(i) - us(i1,k)*dltye(i)
145 !! end do
146 !! end do
147 !!# endif
148
149 !
150 !--Calculate the Advection and Horizontal Diffusion Terms----------------------!
151 !
152
153 do k=1,kbm1
154 pfpx = 0.0_sp
155 pfpy = 0.0_sp
156 pfpxd = 0.0_sp
157 pfpyd = 0.0_sp
158 do i=1,m
159 do j=1,ntsn(i)-1
160 i1=nbsn(i,j)
161 i2=nbsn(i,j+1)
162
163 # if defined (WET_DRY)
164 IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 1)THEN
165 FFD=0.5_SP*(f(I,K)+f(I2,K))
166 FF1=0.5_SP*(f(I,K)+f(I2,K))
167 ELSE IF(ISWETN(I1) == 1 .AND. ISWETN(I2) == 0)THEN
168 FFD=0.5_SP*(f(I1,K)+f(I,K))
169 FF1=0.5_SP*(f(I1,K)+f(I,K))
170 ELSE IF(ISWETN(I1) == 0 .AND. ISWETN(I2) == 0)THEN
171 FFD=0.5_SP*(f(I,K)+f(I,K))
172 FF1=0.5_SP*(f(I,K)+f(I,K))
173 ELSE
174 FFD=0.5_SP*(f(I1,K)+f(I2,K))
175 FF1=0.5_SP*(f(I1,K)+f(I2,K))
176 END IF
177 # else
178 ffd=0.5_sp*(f(i1,k)+f(i2,k)) !-fmean1(i1,k)-fmean1(i2,k))
179 ff1=0.5_sp*(f(i1,k)+f(i2,k))
180 # endif
181
182 # if defined (SPHERICAL)
183 ty=0.5_sp*(vy(i1)+vy(i2))
184 txpi=(vx(i2)-vx(i1))*tpi*cos(deg2rad*ty)
185 typi=(vy(i1)-vy(i2))*tpi
186 pfpx(i)=pfpx(i)+ff1*typi
187 pfpy(i)=pfpy(i)+ff1*txpi
188 pfpxd(i)=pfpxd(i)+ffd*typi
189 pfpyd(i)=pfpyd(i)+ffd*txpi
190 # else
191 pfpx(i) = pfpx(i) +ff1*(vy(i1)-vy(i2))
192 pfpy(i) = pfpy(i) +ff1*(vx(i2)-vx(i1))
193 pfpxd(i)= pfpxd(i)+ffd*(vy(i1)-vy(i2))
194 pfpyd(i)= pfpyd(i)+ffd*(vx(i2)-vx(i1))
195 # endif
196 end do
197
198 ! gather all neighboring control volumes connecting at dam node
199 # if defined (THIN_DAM)
200 IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN
201 DO NX=1,N_DAM_MATCH(I,1)
202 DO J=1,NTSN(N_DAM_MATCH(I,NX+1))-1
203 I1=NBSN(N_DAM_MATCH(I,NX+1),J)
204 I2=NBSN(N_DAM_MATCH(I,NX+1),J+1)
205 FFD=0.5_SP*(f(I1,K)+f(I2,K)) !-SMEAN1(I1,K)-SMEAN1(I2,K))
206 FF1=0.5_SP*(f(I1,K)+f(I2,K))
207 # if defined (SPHERICAL)
208 ty=0.5_sp*(vy(i1)+vy(i2))
209 txpi=(vx(i2)-vx(i1))*tpi*cos(deg2rad*ty)
210 typi=(vy(i1)-vy(i2))*tpi
211 pfpx(i)=pfpx(i)+ff1*typi
212 pfpy(i)=pfpy(i)+ff1*txpi
213 pfpxd(i)=pfpxd(i)+ffd*typi
214 pfpyd(i)=pfpyd(i)+ffd*txpi
215 # else
216 pfpx(i) = pfpx(i) +ff1*(vy(i1)-vy(i2))
217 pfpy(i) = pfpy(i) +ff1*(vx(i2)-vx(i1))
218 pfpxd(i)= pfpxd(i)+ffd*(vy(i1)-vy(i2))
219 pfpyd(i)= pfpyd(i)+ffd*(vx(i2)-vx(i1))
220 # endif
221 END DO
222 END DO
223 END IF
224 # endif
225
226 # if !defined (THIN_DAM)
227 pfpx(i) =pfpx(i )/art2(i)
228 pfpy(i) =pfpy(i )/art2(i)
229 pfpxd(i) =pfpxd(i)/art2(i)
230 pfpyd(i) =pfpyd(i)/art2(i)
231 # else
232 IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN
233 PFPX(I)=PFPX(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))
234 PFPY(I)=PFPY(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))
235 PFPXD(I)=PFPXD(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))
236 PFPYD(I)=PFPYD(I)/(ART2(I)+SUM(ART2(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))
237 ELSE
238 PFPX(I)=PFPX(I)/ART2(I)
239 PFPY(I)=PFPY(I)/ART2(I)
240 PFPXD(I)=PFPXD(I)/ART2(I)
241 PFPYD(I)=PFPYD(I)/ART2(I)
242 END IF
243 # endif
244
245 end do
246
247 if(k == kbm1)then
248 do i=1,m
249 pfpxb(i) = pfpx(i)
250 pfpyb(i) = pfpy(i)
251 end do
252 end if
253
254 do i=1,m
255 pupx(i)=0.0_sp
256 pupy(i)=0.0_sp
257 pvpx(i)=0.0_sp
258 pvpy(i)=0.0_sp
259 j=1
260 i1=nbve(i,j)
261 jtmp=nbvt(i,j)
262 j1=jtmp+1-(jtmp+1)/4*3
263 j2=jtmp+2-(jtmp+2)/4*3
264 x11=0.5_sp*(vx(i)+vx(nv(i1,j1)))
265 y11=0.5_sp*(vy(i)+vy(nv(i1,j1)))
266 x22=xc(i1)
267 y22=yc(i1)
268 x33=0.5_sp*(vx(i)+vx(nv(i1,j2)))
269 y33=0.5_sp*(vy(i)+vy(nv(i1,j2)))
270
271 # if defined (SPHERICAL)
272 ty =0.5_sp*(y11+y33)
273 txpi=(x33-x11)*tpi*cos(deg2rad*ty)
274 typi=(y11-y33)*tpi
275 pupx(i)=pupx(i)+u(i1,k)*typi
276 pupy(i)=pupy(i)+u(i1,k)*txpi
277 pvpx(i)=pvpx(i)+v(i1,k)*typi
278 pvpy(i)=pvpy(i)+v(i1,k)*txpi
279 # else
280 pupx(i)=pupx(i)+u(i1,k)*(y11-y33)
281 pupy(i)=pupy(i)+u(i1,k)*(x33-x11)
282 pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33)
283 pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11)
284 # endif
285
286 if(isonb(i) /= 0) then
287 # if defined (SPHERICAL)
288 ty=0.5_sp*(vy(i)+y11)
289 txpi=(x11-vx(i))*tpi*cos(deg2rad*ty)
290 typi=(vy(i)-y11)*tpi
291 pupx(i)=pupx(i)+u(i1,k)*typi
292 pupy(i)=pupy(i)+u(i1,k)*txpi
293 pvpx(i)=pvpx(i)+v(i1,k)*typi
294 pvpy(i)=pvpy(i)+v(i1,k)*txpi
295 # else
296 pupx(i)=pupx(i)+u(i1,k)*(vy(i)-y11)
297 pupy(i)=pupy(i)+u(i1,k)*(x11-vx(i))
298 pvpx(i)=pvpx(i)+v(i1,k)*(vy(i)-y11)
299 pvpy(i)=pvpy(i)+v(i1,k)*(x11-vx(i))
300 # endif
301 end if
302
303 do j=2,ntve(i)-1
304 i1=nbve(i,j)
305 jtmp=nbvt(i,j)
306 j1=jtmp+1-(jtmp+1)/4*3
307 j2=jtmp+2-(jtmp+2)/4*3
308 x11=0.5_sp*(vx(i)+vx(nv(i1,j1)))
309 y11=0.5_sp*(vy(i)+vy(nv(i1,j1)))
310 x22=xc(i1)
311 y22=yc(i1)
312 x33=0.5_sp*(vx(i)+vx(nv(i1,j2)))
313 y33=0.5_sp*(vy(i)+vy(nv(i1,j2)))
314
315 # if defined (SPHERICAL)
316 ty=0.5_sp*(y11+y33)
317 txpi=(x33-x11)*tpi*COS(deg2rad*TY)
318 typi=(y11-y33)*tpi
319 pupx(i)=pupx(i)+u(i1,k)*typi
320 pupy(i)=pupy(i)+u(i1,k)*txpi
321 pvpx(i)=pvpx(i)+v(i1,k)*typi
322 pvpy(i)=pvpy(i)+v(i1,k)*txpi
323 # else
324 pupx(i)=pupx(i)+u(i1,k)*(y11-y33)
325 pupy(i)=pupy(i)+u(i1,k)*(x33-x11)
326 pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33)
327 pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11)
328 # endif
329 end do
330 j=ntve(i)
331 i1=nbve(i,j)
332 jtmp=nbvt(i,j)
333 j1=jtmp+1-(jtmp+1)/4*3
334 j2=jtmp+2-(jtmp+2)/4*3
335 x11=0.5_sp*(vx(i)+vx(nv(i1,j1)))
336 y11=0.5_sp*(vy(i)+vy(nv(i1,j1)))
337 x22=xc(i1)
338 y22=yc(i1)
339 x33=0.5_sp*(vx(i)+vx(nv(i1,j2)))
340 y33=0.5_sp*(vy(i)+vy(nv(i1,j2)))
341
342 # if defined (SPHERICAL)
343 ty=0.5*(Y11+Y33)
344 txpi=(x33-x11)*tpi*cos(deg2rad*TY)
345 typi=(y11-y33)*tpi
346 pupx(i)=pupx(i)+u(i1,k)*typi
347 pupy(i)=pupy(i)+u(i1,k)*txpi
348 pvpx(i)=pvpx(i)+v(i1,k)*typi
349 pvpy(i)=pvpy(i)+v(i1,k)*txpi
350 # else
351 pupx(i)=pupx(i)+u(i1,k)*(y11-y33)
352 pupy(i)=pupy(i)+u(i1,k)*(x33-x11)
353 pvpx(i)=pvpx(i)+v(i1,k)*(y11-y33)
354 pvpy(i)=pvpy(i)+v(i1,k)*(x33-x11)
355 # endif
356
357 if(isonb(i) /= 0) then
358 # if defined (SPHERICAL)
359 ty=0.5*(Y11+VY(I))
360 txpi=(VX(I)-X11)*tpi*COS(deg2rad*ty)
361 typi=(Y11-VY(I))*tpi
362 pupx(i)=pupx(i)+u(i1,k)*typi
363 pupy(i)=pupy(i)+u(i1,k)*txpi
364 pvpx(i)=pvpx(i)+v(i1,k)*typi
365 pvpy(i)=pvpy(i)+v(i1,k)*txpi
366 # else
367 pupx(i)=pupx(i)+u(i1,k)*(y11-vy(i))
368 pupy(i)=pupy(i)+u(i1,k)*(vx(i)-x11)
369 pvpx(i)=pvpx(i)+v(i1,k)*(y11-vy(i))
370 pvpy(i)=pvpy(i)+v(i1,k)*(vx(i)-x11)
371 # endif
372 end if
373 pupx(i)=pupx(i)/art1(i)
374 pupy(i)=pupy(i)/art1(i)
375 pvpx(i)=pvpx(i)/art1(i)
376 pvpy(i)=pvpy(i)/art1(i)
377 tmp1=pupx(i)**2+pvpy(i)**2
378 tmp2=0.5_sp*(pupy(i)+pvpx(i))**2
379 viscoff(i)=sqrt(tmp1+tmp2)*art1(i)
380 end do
381 ! if(k == kbm1) then
382 ! ah_bottom(1:m) = horcon*(fact*viscoff(1:m) + fm1)
383 ! end if
384
385
386 do i=1,ncv_i
387 ia=niec(i,1)
388 ib=niec(i,2)
389 xi=0.5_sp*(xije(i,1)+xije(i,2))
390 yi=0.5_sp*(yije(i,1)+yije(i,2))
391 # if defined (SPHERICAL)
392 ty=0.5_sp*(yi+vy(ia))
393 dxa=(xi-vx(ia))*tpi*cos(deg2rad*ty)
394 dya=(yi-vy(ia))*tpi
395 ty=0.5*(YI+VY(IB))
396 DXB=(XI-VX(IB))*tpi*COS(deg2rad*ty)
397 DYB=(YI-VY(IB))*tpi
398 # else
399 dxa=xi-vx(ia)
400 dya=yi-vy(ia)
401 dxb=xi-vx(ib)
402 dyb=yi-vy(ib)
403 # endif
404 fij1=f(ia,k)+dxa*pfpx(ia)+dya*pfpy(ia)
405 fij2=f(ib,k)+dxb*pfpx(ib)+dyb*pfpy(ib)
406 un=uvn(i,k)
407
408 ! viscof=horcon*(fact*(viscoff(ia)+viscoff(ib))*0.5_sp + fm1)
409 VISCOF=(FACT*0.5_SP*(VISCOFF(IA)*NN_HVC(IA)+VISCOFF(IB)*NN_HVC(IB)) + FM1*0.5_SP*(NN_HVC(IA)+NN_HVC(IB)))
410
411 txx=0.5_sp*(pfpxd(ia)+pfpxd(ib))*viscof
412 tyy=0.5_sp*(pfpyd(ia)+pfpyd(ib))*viscof
413
414 fxx=-dtij(i)*txx*dltye(i)
415 fyy= dtij(i)*tyy*dltxe(i)
416
417 # if defined (PLBC)
418 fyy=0.0_SP
419 # endif
420
421 exflux=-un*dtij(i)* &
422 ((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp+fxx+fyy
423
424 xflux(ia,k)=xflux(ia,k)+exflux
425 xflux(ib,k)=xflux(ib,k)-exflux
426
427 xflux_adv(ia,k)=xflux_adv(ia,k)+(exflux-fxx-fyy)
428 xflux_adv(ib,k)=xflux_adv(ib,k)-(exflux-fxx-fyy)
429
430 # if defined (THIN_DAM)
431 IF(K<=KDAM(IA).AND.IS_DAM(IA)==1)THEN
432 IF(N_DAM_MATCH(IA,1)==1)THEN
433 XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX
434 XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY)
435 END IF
436 IF(N_DAM_MATCH(IA,1)==2)THEN
437 XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX
438 XFLUX(N_DAM_MATCH(IA,3),K) = XFLUX(N_DAM_MATCH(IA,3),K) + EXFLUX
439 XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY)
440 XFLUX_ADV(N_DAM_MATCH(IA,3),K) = XFLUX_ADV(N_DAM_MATCH(IA,3),K) +(EXFLUX-FXX-FYY)
441 END IF
442 IF(N_DAM_MATCH(IA,1)==3)THEN
443 XFLUX(N_DAM_MATCH(IA,2),K) = XFLUX(N_DAM_MATCH(IA,2),K) + EXFLUX
444 XFLUX(N_DAM_MATCH(IA,3),K) = XFLUX(N_DAM_MATCH(IA,3),K) + EXFLUX
445 XFLUX(N_DAM_MATCH(IA,4),K) = XFLUX(N_DAM_MATCH(IA,4),K) + EXFLUX
446 XFLUX_ADV(N_DAM_MATCH(IA,2),K) = XFLUX_ADV(N_DAM_MATCH(IA,2),K) +(EXFLUX-FXX-FYY)
447 XFLUX_ADV(N_DAM_MATCH(IA,3),K) = XFLUX_ADV(N_DAM_MATCH(IA,3),K) +(EXFLUX-FXX-FYY)
448 XFLUX_ADV(N_DAM_MATCH(IA,4),K) = XFLUX_ADV(N_DAM_MATCH(IA,4),K) +(EXFLUX-FXX-FYY)
449 END IF
450 END IF
451 IF(K<=KDAM(IB).AND.IS_DAM(IB)==1)THEN
452 IF(N_DAM_MATCH(IB,1)==1)THEN
453 XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX
454 XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY)
455 END IF
456 IF(N_DAM_MATCH(IB,1)==2)THEN
457 XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX
458 XFLUX(N_DAM_MATCH(IB,3),K) = XFLUX(N_DAM_MATCH(IB,3),K) - EXFLUX
459 XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY)
460 XFLUX_ADV(N_DAM_MATCH(IB,3),K) = XFLUX_ADV(N_DAM_MATCH(IB,3),K) - (EXFLUX-FXX-FYY)
461 END IF
462 IF(N_DAM_MATCH(IB,1)==3)THEN
463 XFLUX(N_DAM_MATCH(IB,2),K) = XFLUX(N_DAM_MATCH(IB,2),K) - EXFLUX
464 XFLUX(N_DAM_MATCH(IB,3),K) = XFLUX(N_DAM_MATCH(IB,3),K) - EXFLUX
465 XFLUX(N_DAM_MATCH(IB,4),K) = XFLUX(N_DAM_MATCH(IB,4),K) - EXFLUX
466 XFLUX_ADV(N_DAM_MATCH(IB,2),K) = XFLUX_ADV(N_DAM_MATCH(IB,2),K) - (EXFLUX-FXX-FYY)
467 XFLUX_ADV(N_DAM_MATCH(IB,3),K) = XFLUX_ADV(N_DAM_MATCH(IB,3),K) - (EXFLUX-FXX-FYY)
468 XFLUX_ADV(N_DAM_MATCH(IB,4),K) = XFLUX_ADV(N_DAM_MATCH(IB,4),K) - (EXFLUX-FXX-FYY)
469 END IF
470 END IF
471 # endif
472 end do
473 end do !!sigma loop
474
475 !---------------------------------------------------------------------------------
476 ! Accumulate Fluxes at Boundary Nodes
477 !---------------------------------------------------------------------------------
478
479 # if defined (MULTIPROCESSOR)
480 if(par)call node_match(0,nbn,bn_mlt,bn_loc,bnc,mt,kb,myid,nprocs,xflux,xflux_adv)
481 # endif
482
483 !---------------------------------------------------------------------------------
484 ! Store Advective Fluxes at the Boundary
485 !---------------------------------------------------------------------------------
486 do k=1,kbm1
487 if(iobcn > 0) then
488 do i=1,iobcn
489 i1=i_obc_n(i)
490 fflux_obc(i,k)=xflux_adv(i1,k)
491 end do
492 end if
493 end do
494
495 !---------------------------------------------------------------------------------
496 ! Calculate Vertical Advection Terms
497 !---------------------------------------------------------------------------------
498
499 do i=1,m
500 # if defined (WET_DRY)
501 if(iswetn(i)*iswetnt(i) == 1) then
502 # endif
503 # if defined (THIN_DAM)
504 if(IS_DAM(I)==1)then
505 wvel(1:kb)=0.0_sp
506 call calc_vflux(kbm1,f(i,1:kbm1),wvel(1:kb),vflux)
507 else
508 call calc_vflux(kbm1,f(i,1:kbm1),wts(i,1:kb),vflux)
509 end if
510 # else
511 call calc_vflux(kbm1,f(i,1:kbm1),wts(i,1:kb),vflux)
512 # endif
513
514 do k=1,kbm1
515 if(isonb(i) == 2) then
516 xflux(i,k)= (vflux(k)-vflux(k+1))*art1(i)/dz(i,k)
517 else
518 xflux(i,k)=xflux(i,k)+ (vflux(k)-vflux(k+1))*art1(i)/dz(i,k)
519 end if
520 # if defined (THIN_DAM)
521 IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN
522 tmpflx = (vflux(k)-vflux(k+1))*art1(i)/dz(i,k)
523 IF(N_DAM_MATCH(I,1)==1)THEN
524 XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx
525 END IF
526 IF(N_DAM_MATCH(I,1)==2)THEN
527 XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx
528 XFLUX(N_DAM_MATCH(I,3),K) = XFLUX(N_DAM_MATCH(I,3),K)+tmpflx
529 END IF
530 IF(N_DAM_MATCH(I,1)==3)THEN
531 XFLUX(N_DAM_MATCH(I,2),K) = XFLUX(N_DAM_MATCH(I,2),K)+tmpflx
532 XFLUX(N_DAM_MATCH(I,3),K) = XFLUX(N_DAM_MATCH(I,3),K)+tmpflx
533 XFLUX(N_DAM_MATCH(I,4),K) = XFLUX(N_DAM_MATCH(I,4),K)+tmpflx
534 END IF
535 END IF
536 # endif
537 end do
538 # if defined (WET_DRY)
539 end if
540 # endif
541 end do
542
543 !-------------------------------------------------------
544 !Point Source
545 !-------------------------------------------------------
546 if(source)then !!user specified
547
548 if(RIVER_TS_SETTING == 'calculated') then
549 if(RIVER_INFLOW_LOCATION == 'node') then
550 do j=1,numqbc
551 jj=inodeq(j)
552 fpoint=fdis(j)
553 do k=1,kbm1
554 xflux(jj,k)=xflux(jj,k) - qdis(j)*vqdist(j,k)*fpoint !/dz(jj,k)
555 end do
556 end do
557 else if(RIVER_INFLOW_LOCATION == 'edge') then
558 write(*,*)'scalar advection not setup for "edge" point source'
559 stop
560 end if
561 end if
562
563 else
564
565 if(RIVER_TS_SETTING == 'calculated') then
566 if(RIVER_INFLOW_LOCATION == 'node') then
567 do j=1,numqbc
568 jj=inodeq(j)
569 do k=1,kbm1
570 fpoint = f(jj,k)
571 xflux(jj,k)=xflux(jj,k) - qdis(j)*vqdist(j,k)*fpoint !/dz(jj,k)
572 end do
573 end do
574 else if(RIVER_INFLOW_LOCATION == 'edge') then
575 write(*,*)'scalar advection not setup for "edge" point source'
576 stop
577 end if
578 end if
579
580 endif
581 !------------------------------------------------------------------------
582 !Update Scalar Quantity
583 !------------------------------------------------------------------------
584
585 do i=1,m
586 # if defined (WET_DRY)
587 if(iswetn(i)*iswetnt(i) == 1 )then
588 # endif
589 do k=1,kbm1
590 # if !defined (THIN_DAM)
591 fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i))
592 # else
593 IF(IS_DAM(I)==1.AND.K<=KDAM(I))THEN
594 fn(i,k)=(f(i,k)-xflux(i,k)/(ART1(I)&
595 &+SUM(ART1(N_DAM_MATCH(I,2:1+N_DAM_MATCH(I,1)))))*(deltat/dt(i)))*(dt(i)/dtfa(i))
596 ELSE
597 fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i))
598 END IF
599 # endif
600 end do
601 # if defined (WET_DRY)
602 else
603 do k=1,kbm1
604 fn(i,k)=f(i,k)
605 end do
606 end if
607 # endif
608 end do
609
610 return
611 End Subroutine Adv_Scal
612 !==============================================================================|
613
614 !==============================================================================|
615 ! Vertical Diffusion of Scalar |
616 !==============================================================================|
617 Subroutine Vdif_Scal(f,deltat)
618
619 use mTridiagonal
620 use all_vars
621 # if defined (THIN_DAM)
622 use mod_dam,only : NODE_DAM1_N,NODE_DAM2_N,NODE_DAM3_N, &
623 &I_NODE_DAM1_N,I_NODE_DAM2_N,I_NODE_DAM3_N, &
624 &kdam
625 # endif
626
627 Implicit None
628 Real(sp), intent(inout) :: f(0:mt,kb)
629 Real(sp), intent(in ) :: deltat
630 !--local--------------------
631 integer :: i,k,ll
632 real(sp) :: dsqrd,dfdz,visb
633 real(sp) :: fsol(0:kb)
634
635 # if defined (THIN_DAM)
636 real(sp) :: ftmp,stmp
637 # endif
638
639 call init_tridiagonal(kb)
640
641 Do i=1,m
642 dsqrd = d(i)*d(i)
643
644 !----------------------------------------------------------------
645 ! Set up Diagonals of Matrix (lower=au,diag=bu,upper=cu)
646 !----------------------------------------------------------------
647
648
649 !Surface
650 au(1) = 0.0
651 cu(1)= - deltat*(kh(i,2)+umol)/(dzz(i,1)*dz(i,1)*dsqrd)
652 bu(1)= 1.0 - cu(1)
653
654 !Interior
655 do k=2,kbm1-1
656 au(k) = - deltat*(kh(i,k )+umol)/(dzz(i,k-1)*dz(i,k)*dsqrd)
657 cu(k) = - deltat*(kh(i,k+1)+umol)/(dzz(i,k )*dz(i,k)*dsqrd)
658 bu(k) = 1.0 - cu(k) - au(k)
659 end do
660
661 !Bottom
662 au(kbm1) = - deltat*(kh(i,kbm1)+umol)/(dzz(i,kbm1-1)*dz(i,kbm1)*dsqrd)
663 cu(kbm1) = 0.0
664 bu(kbm1) = 1.0 - au(kbm1)
665
666 !----------------------------------------------------------------
667 ! Set up RHS forcing vector and boundary conditions
668 !----------------------------------------------------------------
669 do k=1,kbm1
670 du(k) = f(i,k)
671 end do
672
673 !Free Surface: No flux
674
675 !Bottom: No flux
676
677
678 !----------------------------------------------------------------
679 ! Solve
680 !----------------------------------------------------------------
681
682 call tridiagonal(kb,1,kbm1,fsol)
683
684 !Transfer
685 f(i,1:kbm1) = fsol(1:kbm1)
686
687 End Do
688
689 # if defined (THIN_DAM)
690 DO K=1,KBM1
691 DO I=1,NODE_DAM1_N
692 IF(K<=KDAM(I_NODE_DAM1_N(I,1)).AND.K<=KDAM(I_NODE_DAM1_N(I,2)) )THEN
693 FTMP=F(I_NODE_DAM1_N(I,1),K)*ART1(I_NODE_DAM1_N(I,1)) &
694 & +F(I_NODE_DAM1_N(I,2),K)*ART1(I_NODE_DAM1_N(I,2))
695 STMP=ART1(I_NODE_DAM1_N(I,1))+ART1(I_NODE_DAM1_N(I,2))
696 F(I_NODE_DAM1_N(I,1),K)=FTMP/STMP
697 F(I_NODE_DAM1_N(I,2),K)=FTMP/STMP
698 END IF
699 END DO
700
701 DO I=1,NODE_DAM2_N
702 IF(K<=KDAM(I_NODE_DAM2_N(I,1)).AND.K<=KDAM(I_NODE_DAM2_N(I,2)) &
703 & .AND.K<=KDAM(I_NODE_DAM2_N(I,2)) )THEN
704 FTMP= F(I_NODE_DAM2_N(I,1),K)*ART1(I_NODE_DAM2_N(I,1)) &
705 & +F(I_NODE_DAM2_N(I,2),K)*ART1(I_NODE_DAM2_N(I,2)) &
706 & +F(I_NODE_DAM2_N(I,3),K)*ART1(I_NODE_DAM2_N(I,3))
707 STMP=ART1(I_NODE_DAM2_N(I,1))+ART1(I_NODE_DAM2_N(I,2)) &
708 & +ART1(I_NODE_DAM2_N(I,3))
709 F(I_NODE_DAM2_N(I,1),K)=FTMP/STMP
710 F(I_NODE_DAM2_N(I,2),K)=FTMP/STMP
711 F(I_NODE_DAM2_N(I,3),K)=FTMP/STMP
712 END IF
713 END DO
714
715 DO I=1,NODE_DAM3_N
716 IF(K<=KDAM(I_NODE_DAM3_N(I,1)).AND.K<=KDAM(I_NODE_DAM3_N(I,2)) &
717 & .AND.K<=KDAM(I_NODE_DAM3_N(I,3)).AND.K<=KDAM(I_NODE_DAM3_N(I,4)) )THEN
718 FTMP =F(I_NODE_DAM3_N(I,1),K)*ART1(I_NODE_DAM3_N(I,1)) &
719 & +F(I_NODE_DAM3_N(I,2),K)*ART1(I_NODE_DAM3_N(I,2)) &
720 & +F(I_NODE_DAM3_N(I,3),K)*ART1(I_NODE_DAM3_N(I,3)) &
721 & +F(I_NODE_DAM3_N(I,4),K)*ART1(I_NODE_DAM3_N(I,4))
722 STMP =ART1(I_NODE_DAM3_N(I,1)) + ART1(I_NODE_DAM3_N(I,2)) &
723 & + ART1(I_NODE_DAM3_N(I,3)) + ART1(I_NODE_DAM3_N(I,4))
724 F(I_NODE_DAM3_N(I,1),K)=FTMP/STMP
725 F(I_NODE_DAM3_N(I,2),K)=FTMP/STMP
726 F(I_NODE_DAM3_N(I,3),K)=FTMP/STMP
727 F(I_NODE_DAM3_N(I,4),K)=FTMP/STMP
728 END IF
729 END DO
730 END DO
731 # endif
732
733
734 End Subroutine Vdif_Scal
735
736
737 !==============================================================================|
738 ! Set Point Source Conditions for Scalar Function |
739 !==============================================================================|
740
741 Subroutine Bcond_Scal_PTsource(f,fn,fdis)
742
743 !------------------------------------------------------------------------------|
744 use all_vars
745 use bcs
746 use mod_obcs
747 implicit none
748 real(sp), intent(in ), dimension(0:mt,kb) :: f
749 real(sp), intent(out), dimension(0:mt,kb) :: fn
750 real(sp), intent(in ), dimension(numqbc ) :: fdis
751 !--local-------------------------------------------
752 integer :: i,j,k,j1,j11,j22
753 !------------------------------------------------------------------------------|
754
755
756 !--------------------------------------------
757 ! Set Source Terms
758 !--------------------------------------------
759 if(RIVER_TS_SETTING == 'specified') then
760 if(numqbc > 0) then
761 if(RIVER_INFLOW_LOCATION == 'node') then
762 do i=1,numqbc
763 j11=inodeq(i)
764 do k=1,kbm1
765 fn(j11,k)=fdis(i)
766 end do
767 end do
768 else if(RIVER_INFLOW_LOCATION == 'edge') then
769 do i=1,numqbc
770 j11=n_icellq(i,1)
771 j22=n_icellq(i,2)
772 do k=1,kbm1
773 fn(j11,k)=fdis(i)
774 fn(j22,k)=fdis(i)
775 end do
776 end do
777 end if
778 end if
779 end if
780
781 return
782 End Subroutine Bcond_Scal_PTSource
783 !==============================================================================|
784 !==============================================================================|
785
786 !==============================================================================|
787 ! Set Boundary Conditions for Scalar Function on Open Boundary |
788 !==============================================================================|
789
790 Subroutine Bcond_Scal_OBC(f,fn,fflux_obc,f_obc,deltat,alpha_nudge)
791
792 !------------------------------------------------------------------------------|
793 use all_vars
794 use bcs
795 use mod_obcs
796 implicit none
797 real(sp), intent(in ), dimension(0:mt,kb) :: f
798 real(sp), intent(inout), dimension(0:mt,kb) :: fn
799 real(sp), intent(in ), dimension(iobcn+1,kbm1) :: fflux_obc
800 real(sp), intent(in ), dimension(iobcn ) :: f_obc
801 real(sp), intent(in ) :: deltat
802 real(sp), intent(in ) :: alpha_nudge
803 !--local-------------------------------------------
804 real(sp) :: f2d,f2d_next,f2d_obc,xflux2d,tmp
805 integer :: i,j,k,j1,j11,j22
806 !------------------------------------------------------------------------------|
807
808 !--------------------------------------------
809 ! Set Scalar Value on Open Boundary
810 !--------------------------------------------
811 if(iobcn > 0) then
812 do i=1,iobcn
813 j=i_obc_n(i)
814 j1=next_obc(i)
815 f2d=0.0_sp
816 f2d_next=0.0_sp
817 xflux2d=0.0_sp
818 do k=1,kbm1
819 f2d=f2d+f(j,k)*dz(j,k)
820 f2d_next=f2d_next+fn(j1,k)*dz(j1,k)
821 xflux2d=xflux2d+fflux_obc(i,k)*dz(j,k)
822 end do
823
824 if(uard_obcn(i) > 0.0_sp) then
825 tmp=xflux2d+f2d*uard_obcn(i)
826 f2d_obc=(f2d*dt(j)-tmp*deltat/art1(j))/d(j)
827 do k=1,kbm1
828 fn(j,k)=fn(j1,k) !f2d_obc+(fn(j1,k)-f2d_next)
829 end do
830 else
831 do k=1,kbm1
832 fn(j,k) = f(j,k)-alpha_nudge*(f(j,k)-f_obc(i))
833 end do
834 end if
835 end do
836 endif
837
838 return
839 End Subroutine Bcond_Scal_OBC
840 !==============================================================================|
841 !==============================================================================|
842
843 Subroutine fct_sed(f,fn)
844 !==============================================================================|
845 USE ALL_VARS
846 USE MOD_UTILS
847 USE BCS
848 USE MOD_OBCS
849 IMPLICIT NONE
850 real(sp), intent(inout), dimension(0:mt,kb) :: fn
851 real(sp), intent(in), dimension(0:mt,kb) :: f
852 REAL(SP):: SMAX,SMIN
853 INTEGER :: I,J,K,K1
854 !==============================================================================|
855 IF(DBG_SET(DBG_SBR)) WRITE(IPT,*)"Start: fct_sed"
856
857 nodes: DO I=1,M
858
859 ! SKIP OPEN BOUNDARY NODES
860 IF(IOBCN > 0)THEN
861 DO J=1,IOBCN
862 IF(I == I_OBC_N(J)) CYCLE nodes
863 END DO
864 END IF
865
866 ! SKIP RIVER INFLOW POINTS
867 IF(NUMQBC > 0)THEN
868 DO J=1,NUMQBC
869 IF(RIVER_INFLOW_LOCATION == 'node')THEN
870 IF(I == INODEQ(J)) CYCLE nodes
871 END IF
872 IF(RIVER_INFLOW_LOCATION == 'edge')THEN
873 IF(I == N_ICELLQ(J,1) .OR. I == N_ICELLQ(J,2)) CYCLE nodes
874 END IF
875 END DO
876 END IF
877
878 ! SKIP GROUND WATER INFLOW POINTS
879 IF(BFWDIS(I) .GT. 0.0_SP .and. GROUNDWATER_SALT_ON) CYCLE nodes
880
881 K1 = 1
882 IF(PRECIPITATION_ON) K1 = 2
883 ! DO K=1,KBM1
884 DO K=K1,KBM1
885 SMAX = MAXVAL(f(NBSN(I,1:NTSN(I)),K))
886 SMIN = MINVAL(f(NBSN(I,1:NTSN(I)),K))
887
888 IF(K == 1)THEN
889 SMAX = MAX(SMAX,(f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ &
890 (DZ(I,K)+DZ(I,K+1)))
891 SMIN = MIN(SMIN,(f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ &
892 (DZ(I,K)+DZ(I,K+1)))
893 ELSE IF(K == KBM1)THEN
894 SMAX = MAX(SMAX,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ &
895 (DZ(I,K)+DZ(I,K-1)))
896 SMIN = MIN(SMIN,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ &
897 (DZ(I,K)+DZ(I,K-1)))
898 ELSE
899 SMAX = MAX(SMAX,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ &
900 (DZ(I,K)+DZ(I,K-1)), &
901 (f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ &
902 (DZ(I,K)+DZ(I,K+1)))
903 SMIN = MIN(SMIN,(f(I,K)*DZ(I,K-1)+f(I,K-1)*DZ(I,K))/ &
904 (DZ(I,K)+DZ(I,K-1)), &
905 (f(I,K)*DZ(I,K+1)+f(I,K+1)*DZ(I,K))/ &
906 (DZ(I,K)+DZ(I,K+1)))
907 END IF
908
909 IF(SMIN-fn(I,K) > 0.0_SP)fn(I,K) = SMIN
910 IF(fn(I,K)-SMAX > 0.0_SP)fn(I,K) = SMAX
911
912 END DO
913 END DO nodes
914
915 WHERE(fn < 0.0_SP)fn=0.0_SP
916
917 IF(DBG_SET(DBG_SBR)) WRITE(IPT,*)"End: fct_sed"
918 End Subroutine fct_sed
919
920 !==========================================================================
921 ! Calculate Fluxes for Vertical Advection Equation
922 ! n: number of cells
923 ! c: scalar variable (1:n)
924 ! w: velocity field at cell interfaces (1:n+1)
925 ! note: we dont use face normals to construct inflow/outflow
926 ! thus we add dissipation term instead of subtracting because
927 ! positive velocity is up while computational coordinates increase
928 ! down towards bottom.
929 !==========================================================================
930 Subroutine Calc_VFlux(n,c,w,flux)
931 use mod_prec
932 implicit none
933 integer , intent(in ) :: n
934 real(sp), intent(in ) :: c(n)
935 real(sp), intent(in ) :: w(n+1)
936 real(sp), intent(out) :: flux(n+1)
937 real(sp) :: conv(n+1),diss(n+1)
938 real(sp) :: cin(-1:n+2)
939 real(sp) :: dis4
940 integer :: i
941
942 !transfer to working array
943 cin(1:n) = c(1:n)
944
945 !surface bcs (no flux)
946 cin(0) = -cin(1)
947 cin(-1) = -cin(2)
948
949 !bottom bcs (no flux)
950 cin(n+1) = -cin(n)
951 cin(n+2) = -cin(n-1)
952
953 !flux computation
954 do i=1,n+1
955 dis4 = .5*abs(w(i))
956 conv(i) = w(i)*(cin(i)+cin(i-1))/2.
957 diss(i) = dis4*(cin(i)-cin(i-1)-lim(cin(i+1)-cin(i),cin(i-1)-cin(i-2)))
958 flux(i) = conv(i)+diss(i)
959 end do
960
961 End Subroutine Calc_VFlux
962
963 !==========================================================================
964 ! Calculate LED Limiter L(u,v)
965 !==========================================================================
966 Function Lim(a,b)
967 use mod_prec
968 real(sp) lim,a,b
969 real(sp) q,R
970 real(sp) eps
971 eps = epsilon(eps)
972
973 q = 0. !1st order
974 q = 1. !minmod
975 q = 2. !van leer
976
977 R = abs( (a-b)/(abs(a)+abs(b)+eps) )**q
978 lim = .5*(1-R)*(a+b)
979
980 End Function Lim
981
982
983 End Module Scalar

为了更快速的了解计算过程,自己设置了一个只有7个节点、6个单元的简单地形,如下图所示,然后通过 printf 的方法快速了解每个变量含义。

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

有限体积法离散控制方程(理论)

首先介绍 FVCOM 控制方程离散,虽然其也是按照有限体积方法思想将积分降维,但是只是在平面二维方向上使用有限体积法,垂向计算使用的是有限差分法。

控制方程

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

控制方程离散过程

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

最终更新标量值Ci的程序为: fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i))

这里deltat表示时间步长,dt为上个时间步水深,dtfa为新计算水深,这里之所以需要除以水深是因为垂向梯度项计算需要。

数值求解(结合程序分析)

首先说一下 FVCOM 选取控制体的方法,如下图所示。例如节点1所在控制体,就是由下边4条红线和上边2条黑线所组成的6面体,而节点6则是由周围12条红线组成。

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

FVCOM计算时候也不是按照控制体进行循环,而是按照控制边的个数循环,也就是说,像节点1和节点6这种相邻控制体,两条红色邻边各只计算一次,控制边的通量在节点1和6控制体内是大小相同、符号相反的。

1. 水平对流项计算

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

i1=ntrg(i) dtij(i)=dt1(i1) do k=1,kbm1 uvn(i,k) = v(i1,k)*dltxe(i) - u(i1,k)*dltye(i) end do exflux=-un*dtij(i)* ((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp+fxx+fyy

这里前面一项 -un*dtij(i)*((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp 毫无疑问就是水平对流项,((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp 表示其采用的是迎风格式,控制边上 fij1 及 fij2 计算采用泰勒公式达到2阶精度,泰勒公式中的一阶偏导计算在后面统一介绍

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

2. 水平扩散项计算

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

       txx=0.5_sp*(pfpxd(ia)+pfpxd(ib))*viscof
tyy=0.5_sp*(pfpyd(ia)+pfpyd(ib))*viscof fxx=-dtij(i)*txx*dltye(i)
fyy= dtij(i)*tyy*dltxe(i) exflux=-un*dtij(i)* &
((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp+fxx+fyy

其中 viscof 为水平扩散系数,一阶偏导采用控制边相邻两个节点平均值。 fxx 和 fyy 中还包含了水深dtij,后面会在计算流量时除去。

       exflux=-un*dtij(i)* &
((1.0_sp+sign(1.0_sp,un))*fij2+(1.0_sp-sign(1.0_sp,un))*fij1)*0.5_sp+fxx+fyy xflux(ia,k)=xflux(ia,k)+exflux
xflux(ib,k)=xflux(ib,k)-exflux fn(i,k)=(f(i,k)-xflux(i,k)/art1(i)*(deltat/dt(i)))*(dt(i)/dtfa(i))

3. 一阶偏导项计算

一阶偏导计算也采用格林公式将面积分降维化为线积分计算,但是平面积分所采用的控制体和上面不同,这里采用和节点相邻的所有三角形单元计算,对于边界点来说,只取相邻的两个单元。

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]

对应的程序如下

         pfpx(i) = pfpx(i) +ff1*(vy(i1)-vy(i2))
pfpy(i) = pfpy(i) +ff1*(vx(i2)-vx(i1))
pfpxd(i)= pfpxd(i)+ffd*(vy(i1)-vy(i2))
pfpyd(i)= pfpyd(i)+ffd*(vx(i2)-vx(i1)) …… PFPX(I)=PFPX(I)/ART2(I)
PFPY(I)=PFPY(I)/ART2(I)
PFPXD(I)=PFPXD(I)/ART2(I)
PFPYD(I)=PFPYD(I)/ART2(I)

对于水平对流项中控制边上Ci的二阶精度计算,只需按照泰勒公式计算即可

       fij1=f(ia,k)+dxa*pfpx(ia)+dya*pfpy(ia)
fij2=f(ib,k)+dxb*pfpx(ib)+dyb*pfpy(ib)
上一篇:Linux下编辑、编译、调试命令总结——gcc和gdb描述


下一篇:Linux下利用script命令录制并回放终端会话