|
1 | 1 |
|
2 |
| -function gradient(fld) |
| 2 | +## gradient methods |
3 | 3 |
|
4 |
| - FLD=exchange(fld,1); |
| 4 | +function gradient(inFLD::gcmfaces) |
| 5 | +(dFLDdx, dFLDdy)=gradient(inFLD,true) |
| 6 | +return dFLDdx, dFLDdy |
| 7 | +end |
| 8 | + |
| 9 | +function gradient(inFLD::gcmfaces,doDIV::Bool) |
| 10 | + |
| 11 | +exFLD=exchange(inFLD,1) |
| 12 | +dFLDdx=gcmfaces(inFLD.nFaces,inFLD.grTopo) |
| 13 | +dFLDdy=gcmfaces(inFLD.nFaces,inFLD.grTopo) |
| 14 | + |
| 15 | +for a=1:inFLD.nFaces; |
| 16 | + (s1,s2)=fsize(exFLD,a) |
| 17 | + tmpA=view(exFLD.f[a],2:s1-1,2:s2-1) |
| 18 | + tmpB=tmpA-view(exFLD.f[a],1:s1-2,2:s2-1) |
| 19 | + tmpC=tmpA-view(exFLD.f[a],2:s1-1,1:s2-2) |
| 20 | + if doDIV |
| 21 | + dFLDdx.f[a]=tmpB./MeshArrays.DXC.f[a] |
| 22 | + dFLDdy.f[a]=tmpC./MeshArrays.DYC.f[a] |
| 23 | + else |
| 24 | + dFLDdx.f[a]=tmpB |
| 25 | + dFLDdy.f[a]=tmpC |
| 26 | + end |
| 27 | +end |
5 | 28 |
|
6 |
| - dFLDdx=gcmfaces(fld.nFaces,fld.grTopo); |
7 |
| - dFLDdy=gcmfaces(fld.nFaces,fld.grTopo); |
8 |
| - for iFace=1:FLD.nFaces; |
9 |
| - tmpA=FLD.f[iFace][2:end-1,2:end-1]; |
10 |
| - tmpB=FLD.f[iFace][1:end-2,2:end-1]; |
11 |
| - dFLDdx.f[iFace]=(tmpA-tmpB)./MeshArrays.DXC.f[iFace]; |
12 |
| - tmpA=FLD.f[iFace][2:end-1,2:end-1]; |
13 |
| - tmpB=FLD.f[iFace][2:end-1,1:end-2]; |
14 |
| - dFLDdy.f[iFace]=(tmpA-tmpB)./MeshArrays.DYC.f[iFace]; |
15 |
| - end; |
| 29 | +return dFLDdx, dFLDdy |
| 30 | +end |
| 31 | + |
| 32 | +function gradient(inFLD::gcmfaces,iDXC::gcmfaces,iDYC::gcmfaces) |
16 | 33 |
|
17 |
| - return dFLDdx, dFLDdy |
| 34 | +exFLD=exchange(inFLD,1) |
| 35 | +dFLDdx=gcmfaces(inFLD.nFaces,inFLD.grTopo) |
| 36 | +dFLDdy=gcmfaces(inFLD.nFaces,inFLD.grTopo) |
18 | 37 |
|
| 38 | +for a=1:inFLD.nFaces; |
| 39 | + (s1,s2)=fsize(exFLD,a) |
| 40 | + tmpA=view(exFLD.f[a],2:s1-1,2:s2-1) |
| 41 | + tmpB=tmpA-view(exFLD.f[a],1:s1-2,2:s2-1) |
| 42 | + tmpC=tmpA-view(exFLD.f[a],2:s1-1,1:s2-2) |
| 43 | + dFLDdx.f[a]=tmpB.*iDXC.f[a] |
| 44 | + dFLDdy.f[a]=tmpC.*iDYC.f[a] |
19 | 45 | end
|
20 | 46 |
|
21 |
| -## |
| 47 | +return dFLDdx, dFLDdy |
| 48 | +end |
| 49 | + |
| 50 | +## mask methods |
22 | 51 |
|
23 | 52 | function mask(fld::gcmfaces)
|
24 |
| - fldmsk=mask(fld,(NaN,Inf,0.),NaN) |
25 |
| - return fldmsk |
| 53 | +fldmsk=mask(fld,NaN) |
| 54 | +return fldmsk |
26 | 55 | end
|
27 | 56 |
|
28 | 57 | function mask(fld::gcmfaces, val::Number)
|
29 |
| - fldmsk=mask(fld,(NaN,Inf,0.),val) |
| 58 | + fldmsk=gcmfaces(fld.nFaces,fld.grTopo) |
| 59 | + for a=1:fld.nFaces |
| 60 | + tmp1=copy(fld.f[a]) |
| 61 | + replace!(x -> !isfinite(x) ? val : x, tmp1 ) |
| 62 | + fldmsk.f[a]=tmp1 |
| 63 | + end |
30 | 64 | return fldmsk
|
31 | 65 | end
|
32 | 66 |
|
33 |
| -function mask(fld::gcmfaces, cond::Number, val::Number) |
34 |
| - fldmsk=mask(fld,(cond,),val) |
| 67 | +function mask(fld::gcmfaces, val::Number, noval::Number) |
| 68 | + fldmsk=gcmfaces(fld.nFaces,fld.grTopo) |
| 69 | + for a=1:fld.nFaces |
| 70 | + tmp1=copy(fld.f[a]) |
| 71 | + replace!(x -> x==noval ? val : x, tmp1 ) |
| 72 | + fldmsk.f[a]=tmp1 |
| 73 | + end |
35 | 74 | return fldmsk
|
36 | 75 | end
|
37 | 76 |
|
38 |
| -function mask(fld::gcmfaces,cond::Tuple,val::Number) |
| 77 | +## convergence methods |
39 | 78 |
|
40 |
| - fldmsk=gcmfaces(fld.nFaces,fld.grTopo); |
| 79 | +function convergence(uFLD::gcmfaces,vFLD::gcmfaces); |
41 | 80 |
|
42 |
| - for iFace=1:fld.nFaces; |
43 |
| - tmp1=fld.f[iFace] |
44 |
| - for i=1:length(cond) |
45 |
| - isnan(cond[i]) ? tmp1[findall(isnan.(tmp1))] .= val : nothing |
46 |
| - isinf(cond[i]) ? tmp1[findall(isinf.(tmp1))] .= val : nothing |
47 |
| - isfinite(cond[i]) ? tmp1[findall(tmp1 .== cond[i])] .= val : nothing |
48 |
| - end |
49 |
| - fldmsk.f[iFace]=tmp1 |
50 |
| - end |
| 81 | +#important note: |
| 82 | +# Normally uFLD, vFLD should not contain any NaN; |
| 83 | +# if otherwise then something this may be needed: |
| 84 | +# uFLD=mask(uFLD,0.0); vFLD=mask(vFLD,0.0); |
51 | 85 |
|
52 |
| - return fldmsk |
| 86 | +CONV=gcmfaces(uFLD.nFaces,uFLD.grTopo) |
53 | 87 |
|
| 88 | +(tmpU,tmpV)=exch_UV(uFLD,vFLD) |
| 89 | +for a=1:tmpU.nFaces |
| 90 | + (s1,s2)=fsize(uFLD,a) |
| 91 | + tmpU1=view(tmpU.f[a],1:s1,1:s2) |
| 92 | + tmpU2=view(tmpU.f[a],2:s1+1,1:s2) |
| 93 | + tmpV1=view(tmpV.f[a],1:s1,1:s2) |
| 94 | + tmpV2=view(tmpV.f[a],1:s1,2:s2+1) |
| 95 | + CONV.f[a]=tmpU1-tmpU2+tmpV1-tmpV2 |
54 | 96 | end
|
55 | 97 |
|
56 |
| -## |
| 98 | +return CONV |
| 99 | +end |
| 100 | + |
| 101 | +## smooth function |
| 102 | + |
| 103 | +function smooth(FLD::gcmfaces,DXCsm::gcmfaces,DYCsm::gcmfaces) |
| 104 | + |
| 105 | +#important note: |
| 106 | +#input FLD should be land masked (NaN/1) by caller if needed |
57 | 107 |
|
58 |
| -function smooth(fld::gcmfaces,DXCsm::gcmfaces,DYCsm::gcmfaces) |
| 108 | +#get land masks (NaN/1): |
| 109 | +mskC=fill(1.0,FLD) + 0.0 * mask(FLD) |
| 110 | +(mskW,mskS)=gradient(FLD,false) |
| 111 | +mskW=fill(1.0,FLD) + 0.0 * mask(mskW) |
| 112 | +mskS=fill(1.0,FLD) + 0.0 * mask(mskS) |
59 | 113 |
|
60 |
| -#get land mask: |
61 |
| -msk=fill(1.,fld) + 0. * mask(fld,NaN); |
| 114 | +#replace NaN with 0. in FLD and land masks: |
| 115 | +FLD=mask(FLD,0.0) |
| 116 | +mskC=mask(mskC,0.0) |
| 117 | +mskW=mask(mskW,0.0) |
| 118 | +mskS=mask(mskS,0.0) |
| 119 | + |
| 120 | +#get inverse grid spacing: |
| 121 | +iDXC=gcmfaces(FLD.nFaces,FLD.grTopo) |
| 122 | +iDYC=gcmfaces(FLD.nFaces,FLD.grTopo) |
| 123 | +for a=1:FLD.nFaces; |
| 124 | + iDXC.f[a]=1.0./MeshArrays.DXC.f[a] |
| 125 | + iDYC.f[a]=1.0./MeshArrays.DYC.f[a] |
| 126 | +end |
62 | 127 |
|
63 | 128 | #Before scaling the diffusive operator ...
|
64 |
| -tmp0=DXCsm/MeshArrays.DXC; |
65 |
| -tmp0=mask(msk*tmp0,0.); |
| 129 | +tmp0=DXCsm*iDXC*mskW; |
66 | 130 | tmp00=maximum(tmp0);
|
67 |
| -tmp0=DYCsm/MeshArrays.DYC; |
68 |
| -tmp0=mask(msk*tmp0,0.); |
| 131 | +tmp0=DYCsm*iDYC*mskS; |
69 | 132 | tmp00=max(tmp00,maximum(tmp0));
|
70 | 133 |
|
71 | 134 | #... determine a suitable time period:
|
72 | 135 | nbt=ceil(1.1*2*tmp00^2);
|
73 | 136 | dt=1.;
|
74 | 137 | T=nbt*dt;
|
| 138 | +#println("nbt="*"$nbt") |
| 139 | + |
| 140 | +#diffusion operator times DYG / DXG: |
| 141 | +KuxFac=mskW*DXCsm*DXCsm/T/2.0*MeshArrays.DYG; |
| 142 | +KvyFac=mskS*DYCsm*DYCsm/T/2.0*MeshArrays.DXG; |
75 | 143 |
|
76 |
| -#diffusion operator: |
77 |
| -Kux=DXCsm*DXCsm/T/2; |
78 |
| -Kvy=DYCsm*DYCsm/T/2; |
| 144 | +#time steping factor: |
| 145 | +dtFac=dt*mskC/MeshArrays.RAC; |
79 | 146 |
|
80 | 147 | #loop:
|
81 | 148 | for it=1:nbt
|
82 |
| - (dTdxAtU,dTdyAtV)=gradient(fld); |
83 |
| - tmpU=dTdxAtU*Kux*MeshArrays.DYG; |
84 |
| - tmpV=dTdyAtV*Kvy*MeshArrays.DXG; |
| 149 | + (dTdxAtU,dTdyAtV)=gradient(FLD,iDXC,iDYC); |
| 150 | + tmpU=gcmfaces(FLD.nFaces,FLD.grTopo) |
| 151 | + tmpV=gcmfaces(FLD.nFaces,FLD.grTopo) |
| 152 | + for a=1:FLD.nFaces |
| 153 | + tmpU.f[a]=dTdxAtU.f[a].*KuxFac.f[a]; |
| 154 | + tmpV.f[a]=dTdyAtV.f[a].*KvyFac.f[a]; |
| 155 | + end |
85 | 156 | tmpC=convergence(tmpU,tmpV);
|
86 |
| - fld=fld-dt*msk*tmpC/MeshArrays.RAC; |
| 157 | + for a=1:FLD.nFaces |
| 158 | + FLD.f[a]=FLD.f[a]-dtFac.f[a].*tmpC.f[a]; |
| 159 | + end |
87 | 160 | end
|
88 | 161 |
|
89 |
| -return fld |
| 162 | +#Apply land mask (NaN/1) to end result: |
| 163 | +mskC=mask(mskC,NaN,0.0) |
| 164 | +FLD=mskC*FLD |
| 165 | + |
| 166 | +return FLD |
90 | 167 |
|
91 | 168 | end
|
92 | 169 |
|
93 | 170 | ##
|
94 |
| - |
95 |
| -function convergence(fldU::gcmfaces,fldV::gcmfaces); |
96 |
| - |
97 |
| - (tmpU,tmpV)=exch_UV(fldU,fldV); |
98 |
| - tmpU=mask(tmpU,NaN,0); |
99 |
| - tmpV=mask(tmpV,NaN,0); |
100 |
| - tmpC=gcmfaces(tmpU.nFaces,tmpU.grTopo); |
101 |
| - for iFace=1:tmpU.nFaces; |
102 |
| - tmp1=tmpU.f[iFace][1:end-1,:,:,:]-tmpU.f[iFace][2:end,:,:,:]; |
103 |
| - tmp2=tmpV.f[iFace][:,1:end-1,:,:]-tmpV.f[iFace][:,2:end,:,:]; |
104 |
| - tmpC.f[iFace]=dropdims(tmp1+tmp2,dims=(3,4)); |
105 |
| - end; |
106 |
| - return tmpC |
107 |
| - |
108 |
| -end |
|
0 commit comments