1 |
function [psi,mskG,ylat] = calcEulerPsiCube(varargin); |
2 |
|
3 |
% [psi,mskG,ylat] = calcEulerPsiCube(d,g,flu,rstar,blkFile,[optional]); |
4 |
% |
5 |
% Input arguements: |
6 |
% d [Field data] Velocity field (Mass-weighted if rstar=1) |
7 |
% g [Grid data ] drF,dxG,dyG,HFacW,HFacS |
8 |
% flu (str) 'O' or 'A' for ocean or atmosphere |
9 |
% rstar (int) 0 or 1 if you are using r* coordinates or not |
10 |
% blkFile (str) Broken line file ('isoLat_cs32_59.mat') |
11 |
% The incoming field data (d) and grid data (g) must be in a |
12 |
% structured array format |
13 |
% Optional parameters: |
14 |
% mask (struct) mask (structured array including maskW and maskS) |
15 |
% |
16 |
% Output fields: |
17 |
% psi Overturning (eg [61,6,nt]) |
18 |
% mskG Land mask (eg [60,5]) |
19 |
% ylat Latitude coordinate of psi (eg [61,1]) |
20 |
% |
21 |
% Description: |
22 |
% Caculates overturning stream function (psi). For the atmosphere, data |
23 |
% is must be in p-coordinates and the output is the mass transport psi |
24 |
% [10^9 kg/s]. For the ocean, data should be in z-coordinates and the |
25 |
% output is the volume transport psi [10^6 m^3/s = Sv]. If the rstar |
26 |
% parameters is on, hu and hv are used, if off, the hfacw*.u and hfacs*.v |
27 |
% are used (the multiplication being done inside the function). |
28 |
% |
29 |
% 'psi' is tabulated on broken lines at the interface between cells in |
30 |
% the vertical. 'mskG' is for the area between broken lines and between |
31 |
% the cell interfaces in the vertical. |
32 |
% |
33 |
|
34 |
% Defaults that can be overriden. |
35 |
grav = 9.81; |
36 |
masking=0; |
37 |
|
38 |
% Read input parameters. |
39 |
d = varargin{1}; |
40 |
g = varargin{2}; |
41 |
flu = varargin{3}; |
42 |
rstar = varargin{4}; |
43 |
blkFile = varargin{5}; |
44 |
if length(varargin) == 6 |
45 |
mask = varargin{6}; |
46 |
masking = 1; |
47 |
end |
48 |
|
49 |
|
50 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
51 |
% Prepare / reform incoming data % |
52 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
53 |
|
54 |
nc = size(g.XC,2); |
55 |
nr = length(g.drF); |
56 |
|
57 |
delM = g.drF; |
58 |
dxg = reshape(g.dxG(1:6*nc,1:nc),[6*nc*nc,1]); |
59 |
dyg = reshape(g.dyG(1:6*nc,1:nc),[6*nc*nc,1]); |
60 |
if rstar |
61 |
nt = size(d.UVELMASS,4); |
62 |
hu = reshape(d.UVELMASS(1:6*nc,1:nc,1:nr,1:nt),[6*nc*nc,nr,nt]); |
63 |
hv = reshape(d.VVELMASS(1:6*nc,1:nc,1:nr,1:nt),[6*nc*nc,nr,nt]); |
64 |
else |
65 |
nt = size(d.UVEL,4); |
66 |
hw = reshape(g.HFacW(1:6*nc,1:nc,1:nr),[6*nc*nc,nr]); |
67 |
hs = reshape(g.HFacS(1:6*nc,1:nc,1:nr),[6*nc*nc,nr]); |
68 |
hu = reshape(d.UVEL(1:6*nc,1:nc,1:nr,1:nt),[6*nc*nc,nr,nt]); |
69 |
hv = reshape(d.VVEL(1:6*nc,1:nc,1:nr,1:nt),[6*nc*nc,nr,nt]); |
70 |
for it = 1:nt |
71 |
hu(:,:,it) = hw.*hu(:,:,it); |
72 |
hv(:,:,it) = hs.*hv(:,:,it); |
73 |
end |
74 |
end |
75 |
|
76 |
mskWloc = ones(6*nc*nc,1); |
77 |
mskSloc = ones(6*nc*nc,1); |
78 |
|
79 |
if masking == 1 |
80 |
mskWloc=reshape(mask.maskW(:,:,1),6*nc*nc,1); |
81 |
mskSloc=reshape(mask.maskS(:,:,1),6*nc*nc,1); |
82 |
%hu = repmat(reshape(mask.maskW,6*nc*nc,1),[1 nr nt]) .* hu; |
83 |
%hv = repmat(reshape(mask.maskS,6*nc*nc,1),[1 nr nt]) .* hv; |
84 |
end |
85 |
|
86 |
% Load broken information. |
87 |
% I looked at calc_psiH_CS.m, and did not find it very clear. |
88 |
% May be you can try to see what is in |
89 |
% MITgcm/utils/matlab/cs_grid/bk_line/use_psiLine.m |
90 |
% it s shorter, and slightly better. |
91 |
load(blkFile); |
92 |
ydim = length(bkl_Ylat); |
93 |
ylat = [-90,bkl_Ylat,90]; |
94 |
|
95 |
% kMsep=1; |
96 |
% if (nargin < 6), kfac=0; |
97 |
% else kfac=1; end; |
98 |
nBas=0; |
99 |
|
100 |
% Prepare arrays. |
101 |
psi = zeros(ydim+2,nr+1,1+nBas,nt); |
102 |
mskZ = zeros(ydim+2,nr+1,1+nBas); % Mask of psi |
103 |
mskV = zeros(ydim+2,nr,1+nBas); % Mask of the merid. transport |
104 |
mskG = zeros(ydim+1,nr,1+nBas); % Mask of the ground |
105 |
|
106 |
% The variable "bkl_Flg" is -1/1 if edge (on a given broken) has a u point |
107 |
% and -2/2 if it has a v point. Positive/negative values contribute |
108 |
% positively/negatively to northward heat transport (this depends on the |
109 |
% oreientation of the cell). A zero value indicates an end of edges that |
110 |
% contribute to a broken line. The u and v information is parced into two |
111 |
% seperate fields, ufac and vfac (-2/2 are reduced to -1/1 for vfac). |
112 |
ufac = zeros([size(bkl_Flg),1+nBas]); |
113 |
vfac = zeros([size(bkl_Flg),1+nBas]); |
114 |
ufac(:,:,1) = rem(bkl_Flg,2); |
115 |
vfac(:,:,1) = fix(bkl_Flg/2); |
116 |
% for jl=1:ydim, |
117 |
% ie=bkl_Npts(jl); |
118 |
% for b=1:nBas, |
119 |
% ufac(1:ie,jl,1+b)=mskBw(bkl_IJuv(1:ie,jl),b).*ufac(1:ie,jl,1); |
120 |
% vfac(1:ie,jl,1+b)=mskBs(bkl_IJuv(1:ie,jl),b).*vfac(1:ie,jl,1); |
121 |
% end; |
122 |
% end; |
123 |
|
124 |
|
125 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
126 |
% Compute mass/volume stream function % |
127 |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
128 |
|
129 |
% Compute volume transport through broken lines a hence psi. ut/vt is the |
130 |
% velocity times the edge length it is passing through. The sum of this |
131 |
% quantity along a broken line (vz) times the cell height is the volume |
132 |
% transport through broken line at one layer (delM(k)*vz). psi is then |
133 |
% the value of the volume transport through the level above subtracted |
134 |
% from the value of psi above. |
135 |
for it = 1:nt |
136 |
for k = nr:-1:1 |
137 |
ut = dyg.*hu(:,k,it).*mskWloc; |
138 |
vt = dxg.*hv(:,k,it).*mskSloc; |
139 |
for jl = 1:ydim |
140 |
ie = bkl_Npts(jl); |
141 |
for b = 1:1+nBas |
142 |
vz = sum( ufac(1:ie,jl,b).*ut(bkl_IJuv(1:ie,jl)) ... |
143 |
+ vfac(1:ie,jl,b).*vt(bkl_IJuv(1:ie,jl)) ); |
144 |
psi(jl+1,k,b,it) = psi(jl+1,k+1,b,it) - delM(k)*vz; |
145 |
end |
146 |
end |
147 |
end |
148 |
end |
149 |
|
150 |
psi = squeeze(psi); |
151 |
|
152 |
%% For Ocean, result in Sv (10^6 m3/s) |
153 |
%% For Atmos, results in 10^9 kg/s |
154 |
if isequal(flu,'O'), psi = 1e-6*squeeze(psi); end |
155 |
if isequal(flu,'A'), psi =-1e-9/grav*squeeze(psi); end |
156 |
|
157 |
|
158 |
|
159 |
% % Compute the mask : |
160 |
% if kfac == 1, |
161 |
% ufac=abs(ufac) ; vfac=abs(vfac); |
162 |
% for jl=1:ydim, |
163 |
% ie=bkl_Npts(jl); |
164 |
% hw=zeros(ie,nr); hs=zeros(ie,nr); |
165 |
% hw=hw(bkl_IJuv(1:ie,jl),:); % Would need correction! |
166 |
% hs=hs(bkl_IJuv(1:ie,jl),:); |
167 |
% for b=1:1+nBas, |
168 |
% for k=1:nr, |
169 |
% % for ii=1:bkl_Npts(jl); |
170 |
% % ij=bkl_IJuv(ii,jl); |
171 |
% % mskV(jl+1,k,b)=mskV(jl+1,k,b)+ufac(ii,jl,b)*hw(ij,k)+vfac(ii,jl,b)*hs(ij,k); |
172 |
% % end ; |
173 |
% tmpv=ufac(1:ie,jl,b).*hw(:,k)+vfac(1:ie,jl,b).*hs(:,k); |
174 |
% mskV(jl+1,k,b)=mskV(jl+1,k,b)+max(tmpv); |
175 |
% end |
176 |
% end |
177 |
% end |
178 |
% mskV=ceil(mskV); mskV=min(1,mskV); |
179 |
% %- build the real mask (=mskG, ground) used to draw the continent with "surf": |
180 |
% % position=centered , dim= ydim+1 x nr |
181 |
% mskG=mskV(1:ydim+1,:,:)+mskV(2:ydim+2,:,:); mskG=min(1,mskG); |
182 |
% |
183 |
% if kMsep & nBas > 0, |
184 |
% mskW=1+min(1,ceil(hw)); |
185 |
% mskS=1+min(1,ceil(hs)); |
186 |
% for b=1:nBas, |
187 |
% bs=b; b1=1+bs; b2=2+rem(bs,nBas); |
188 |
% if nBas == 2, bs=b+b-1; b1=2; b2=3 ; end |
189 |
% for j=1:ydim+1, |
190 |
% for i=1:np_Sep(bs,j), |
191 |
% ij=ij_Sep(bs,j,i); typ=abs(tp_Sep(bs,j,i)); |
192 |
% if typ == 1, |
193 |
% mskG(j,:,b1)=mskG(j,:,b1).*mskW(ij,:); |
194 |
% mskG(j,:,b2)=mskG(j,:,b2).*mskW(ij,:); |
195 |
% elseif typ == 2, |
196 |
% mskG(j,:,b1)=mskG(j,:,b1).*mskS(ij,:); |
197 |
% mskG(j,:,b2)=mskG(j,:,b2).*mskS(ij,:); |
198 |
% end |
199 |
% end |
200 |
% end |
201 |
% end |
202 |
% mskG=min(2,mskG); |
203 |
% end |
204 |
% |
205 |
% %- to keep psi=0 on top & bottom |
206 |
% mskZ(:,[2:nr+1],:)=mskV; |
207 |
% mskZ(:,[1:nr],:)=mskZ(:,[1:nr],:)+mskV; |
208 |
% %- to keep psi=0 on lateral boundaries : |
209 |
% mskZ([1:ydim],:,:)=mskZ([1:ydim],:,:)+mskZ([2:ydim+1],:,:); |
210 |
% mskZ([2:ydim+1],:,:)=mskZ([2:ydim+1],:,:)+mskZ([3:ydim+2],:,:); |
211 |
% mskZ=ceil(mskZ); mskZ=min(1,mskZ); |
212 |
% if kMsep & nBas > 0, |
213 |
% mskM=zeros(ydim+2,nr,1+nBas); mskM(2:ydim+2,:,:)=min(2-mskG,1); |
214 |
% mskM(1:ydim+1,:,:)=mskM(1:ydim+1,:,:)+mskM(2:ydim+2,:,:); |
215 |
% mskZ(:,1:nr,:)=min(mskZ(:,1:nr,:),mskM); |
216 |
% end |
217 |
% %- apply the mask (and remove dim = 1) : |
218 |
% if nt == 1, |
219 |
% psi=squeeze(psi); mskV=squeeze(mskV); mskZ=squeeze(mskZ); |
220 |
% psi( find(mskZ==0) )=NaN ; |
221 |
% else |
222 |
% for nt=1:nt, |
223 |
% psi1=psi(:,:,:,nt); psi1( find(mskZ==0) )=NaN ; psi(:,:,:,nt)=psi1; |
224 |
% end |
225 |
% if nBas < 1, psi=squeeze(psi); mskV=squeeze(mskV); mskZ=squeeze(mskZ); end |
226 |
% end |
227 |
% else |
228 |
% if nBas < 1 | nt == 1, psi=squeeze(psi); end |
229 |
% end |