最近接到一个任务,就是解决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 的方法快速了解每个变量含义。

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

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

控制方程

控制方程离散过程

最终更新标量值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条红线组成。

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

1. 水平对流项计算

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阶精度,泰勒公式中的一阶偏导计算在后面统一介绍

2. 水平扩散项计算

       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. 一阶偏导项计算

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

对应的程序如下

         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)

SUNTANS 及 FVCOM 对流扩散方程求解简介[TBC]的更多相关文章

  1. LibTorch | 使用神经网络求解一维稳态对流扩散方程

    0. 写在前面 本文将使用基于LibTorch(PyTorch C++接口)的神经网络求解器,对一维稳态对流扩散方程进行求解.研究问题参考自教科书\(^{[1]}\)示例 8.3. 目录 0. 写在前 ...

  2. FESTUNG模型介绍—1.对流方程求解

    FESTUNG模型介绍-1.对流方程求解 1. 控制方程 对流问题中,控制方程表达式为 \[\partial_t C + \partial_x (u^1 C) + \partial_y (u^2 C) ...

  3. [saiku] 源码整合[maven整合]

    saiku源码的整合分为[普通web项目整合]和[maven整合]两种 本节主要是讲解如何整合为maven项目 转载自:http://blog.csdn.net/gsying1474/article/ ...

  4. [terry笔记]Oracle会话追踪(二):TKPROF

    接上一笔记[terry笔记]Oracle会话追踪(一):SQL_TRACE&EVENT 10046 http://www.cnblogs.com/kkterry/p/3279282.html ...

  5. [terry笔记]Oracle会话追踪(一):SQL_TRACE&EVENT 10046

      SQL_TRACE/10046 事件是 Oracle 提供的用于进行 SQL 跟踪的手段,在日常的数据库问题诊断和解决中是非常常用的方法.但其生成的trace文件需要tkprof工具生成一个可供人 ...

  6. [ Bubble Sort ]& block

    [ Bubble Sort ] 冒泡排序!“预处理.block.预编译”!<环境:Terminal的gcc编译器> 简述:冒泡排序就是把小的元素往前调或者把大的元素往后调.比较是相邻的两个 ...

  7. 洛谷 P1120 小木棍 [数据加强版]解题报告

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...

  8. 洛谷——P1120 小木棍 [数据加强版]

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过5050. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍 ...

  9. 洛谷 P1120 小木棍 [数据加强版]

    P1120 小木棍 [数据加强版] 题目描述 乔治有一些同样长的小木棍,他把这些木棍随意砍成几段,直到每段的长都不超过50. 现在,他想把小木棍拼接成原来的样子,但是却忘记了自己开始时有多少根木棍和它 ...

随机推荐

  1. 【UE4】 补丁Patch 与 DLC

    概述 UE4 中主要使用 Project Launcher 来进行补丁和DLC的制作 补丁与 DLC 都需要基于某个版本而制作 补丁 与 DLC 最后以 Pak 形式表现, 补丁的 pak 可以重命名 ...

  2. eclipse javase版安装插件开发web项目

    最近学习开发javaweb,但是安装的却是java se版的eclipse,但其无法新建web项目,即找不到Dynamic Web.所以需要下载相应插件.以下为操作过程. 1. 在联网的情况下,打开e ...

  3. 混合开发框架Flutter

    Flutter开发简介与其他的混合开发的对比 为什么要使用Flutter? 跨平台技术简介 Hybrid技术简介 QT简介 Flutter简介 为什么要使用Flutter? Flutter有什么优势? ...

  4. OO第四单元UML作业总结暨OO课程总结

    目录 目录一.第四单元UML两次作业架构设计第一次作业第二次作业二.架构设计总结与OO方法理解演进三.测试理解与实践演进四.课程收获总结五.课程改进建议六.尾声 一.第四单元UML两次作业架构设计 第 ...

  5. 软件案例分析——VS和VS Code

    软件案例分析--VS和VS Code 项目 内容 这个作业属于哪个课程/ 2020年春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里? 软件案例分析 我在这个课程的目标是? 提高代码水平,熟 ...

  6. 集合先从ArrayList开始

    本篇文章非常建议直接从经典Demo开始哦~ 一.ArrayList简介 ArrayList 的底层是数组队列,相当于动态数组.与 Java 中的数组相比,它的容量能动态增长.在添加大量元素前,应用程序 ...

  7. 攻防世界 杂项 6.pure_color

    图片隐写 工具 使用StegSolve一把梭 另一种解法 右击图片编辑,画图工具打开,属性设置黑白.

  8. 到底能不能用 join

    互联网上一直流传着各大公司的 MySQL 军规,其中关于 join 的描述,有些公司不推荐使用 join,而有些公司则规定有条件的使用 join, 它们都是教条式的规定,也没有详细说其中的原因,这就很 ...

  9. Linux题目学习

    一.填空题: 1. 在Linux系统中,以 文件 方式访问设备 . 2. Linux内核引导时,从文件/etc/fstab 中读取要加载的文件系统. 3. Linux文件系统中每个文件用 i节点来标识 ...

  10. Linux使用ssh测试端口

    在windows上可以使用telnet客户端测试,在linux如果不方便安装telnet客户端的时候可以通关ssh来测试端口 具体命令如下 ssh -v -p 8080 root@59.207.252 ...