1% Form the inverse of the background error covariance matrix. 2% 3% s = divand_background(mask,pmn,Labs,alpha,moddim) 4% 5% Form the inverse of the background error covariance matrix with 6% finite-difference operators on a curvilinear grid 7% 8% Input: 9% mask: binary mask delimiting the domain. 1 is inside and 0 outside. 10% For oceanographic application, this is the land-sea mask. 11% 12% pmn: scale factor of the grid. 13% 14% Labs: correlation length 15% 16% alpha: a dimensional coefficients for norm, gradient, laplacian,... 17% alpha is usually [1 2 1]. 18% 19% 20% Output: 21% s: stucture containing 22% s.iB: inverse of the background error covariance 23% s.L: spatial average correlation length 24% s.n: number of dimenions 25% s.coeff: scaling coefficient such that the background variance 26% diag(inv(iB)) is one far away from the boundary. 27 28function s = divand_background(mask,pmn,Labs,alpha,moddim,mapindex) 29 30sz = size(mask); 31% number of dimensions 32pmn = cat_cell_array(pmn); 33n = size(pmn,ndims(pmn)); 34 35if isempty(moddim) 36 moddim = zeros(1,n); 37end 38 39if nargin == 5 40 mapindex = []; 41end 42 43iscyclic = moddim > 0; 44 45 46if isscalar(Labs) 47 Labs = Labs * ones([size(mask) n]); 48elseif iscell(Labs) 49 for i=1:n 50 if isscalar(Labs{i}) 51 Labs{i} = Labs{i} * ones(size(mask)); 52 else 53 if ~isequal(size(mask),size(Labs{i})) 54 error('mask (%s) and correlation length (%s) have incompatible size',... 55 formatsize(size(mask)),formatsize(size(Labs{i}))); 56 end 57 end 58 end 59 60 Labs = cat_cell_array(Labs); 61else 62 if ~isequal(size(mask),size(Labs)) 63 error('mask (%s) and correlation length (%s) have incompatible size',... 64 formatsize(size(mask)),formatsize(size(Labs))); 65 end 66 67 Labs = repmat(Labs,[ones(1,ndims(mask)) n]); 68end 69 70if isempty(alpha) 71 % kernel should has be continuous derivative 72 73 % highest derivative in cost function 74 m = ceil(1+n/2); 75 76 % alpha is the (m+1)th row of the Pascal triangle: 77 % m=0 1 78 % m=1 1 1 79 % m=1 1 2 1 80 % m=2 1 3 3 1 81 % ... 82 83 alpha = arrayfun (@(k) nchoosek(m,k), 0:m); 84end 85 86%if ~isequal([size(mask) n],size(pmn)) 87% error('mask (%s) and metric (%s) have incompatible size',formatsize(size(mask)),formatsize(size(pmn))); 88%end 89 90s = divand_operators(mask,pmn,Labs.^2,iscyclic,mapindex); 91D = s.D; % laplacian (a dimensional, since nu = Labs.^2) 92sv = s.sv; 93n = s.n; 94 95 96% Labsp: 1st index represents the dimensions 97Labsp = permute(Labs,[n+1 1:n]); 98pmnp = permute(pmn,[n+1 1:n]); 99 100% must handle the case when Labs is zero in some dimension 101% thus reducing the effective dimension 102 103% mean correlation length in every dimension 104Ld = mean(reshape(Labsp,[n sv.numels_all]),2); 105neff = sum(Ld > 0); 106%L = mean(Ld(Ld > 0)); 107 108% geometric mean 109L = geomean(Ld(Ld > 0)); 110 111 112% norm taking only dimension into account with non-zero correlation 113% WE: units length^(neff/2) 114d = prod(pmnp(find(Ld > 0),:),1)'; 115WE = sparse_diag(statevector_pack(sv,1./sqrt(d))); 116 117 118% scale iB such that the diagonal of inv(iB) is 1 far from 119% the boundary 120% we use the effective dimension neff to take into account that the 121% correlation length-scale might be zero in some directions 122 123Ln = prod(Ld(Ld > 0)); 124 125if any(Ld <= 0) 126 pmnd = mean(reshape(pmnp,[n sv.numels_all]),2); 127 %Ln = Ln * prod(pmnd(Ld <= 0)); 128end 129 130 131try 132 coeff = divand_kernel(neff,alpha) * Ln; % units length^n 133catch ME 134 if strcmp(ME.identifier, 'divand:divand_kernel:unsupported_alpha') 135 warning('divand:divand_background:noscaling','no scaling'); 136 coeff = 1; 137 else 138 rethrow(ME); 139 end 140end 141 142pmnv = reshape(pmn,numel(mask),n); 143pmnv(:,Ld == 0) = 1; 144 145% staggered version of norm 146 147for i=1:n 148 S = sparse_stagger(sz,i,iscyclic(i)); 149 ma = (S * mask(:) == 1); 150 d = sparse_pack(ma) * prod(S * pmnv,2); 151 d = 1./d; 152 s.WEs{i} = sparse_diag(sqrt(d)); 153end 154 155% staggered version of norm scaled by length-scale 156 157s.WEss = cell(n,1); 158s.Dxs = cell(n,1); 159for i=1:n 160 Li2 = Labsp(i,:).^2; 161 162 S = sparse_stagger(sz,i,iscyclic(i)); 163 % mask for staggered variable 164 m = (S * mask(:) == 1); 165 166 tmp = sparse_pack(m) * sqrt(S*Li2(:)); 167 168 s.WEss{i} = sparse_diag(tmp) * s.WEs{i}; 169% s.Dxs{i} = sparse_diag(sqrt(tmp)) * s.Dx{i}; 170end 171 172% adjust weight of halo points 173if ~isempty(mapindex) 174 % ignore halo points at the center of the cell 175 176 WE = sparse_diag(s.isinterior) * WE; 177 178 % divide weight be two at the edged of halo-interior cell 179 % weight of the grid points between halo and interior points 180 % are 1/2 (as there are two) and interior points are 1 181 for i=1:n 182 s.WEs{i} = sparse_diag(sqrt(s.isinterior_stag{i})) * s.WEs{i}; 183 end 184end 185 186s.WE = WE; 187s.coeff = coeff; 188% number of dimensions 189s.n = n; 190 191[iB_,iB] = divand_background_components(s,alpha); 192 193if 0 194iB_ = cell(length(alpha),1); 195 196% constrain of total norm 197 198iB_{1} = (1/coeff) * (WE'*WE); 199 200 201% loop over all derivatives 202 203for j=2:length(alpha) 204 % exponent of laplacian 205 k = floor((j-2)/2); 206 207 if mod(j,2) == 0 208 % constrain of derivative with uneven order (j-1) 209 % (gradient, gradient*laplacian,...) 210 % normalized by surface 211 212 iB_{j} = sparse(size(D,1),size(D,1)); 213 214 for i=1:n 215 Dx = s.WEss{i} * s.Dx{i} * D^k; 216 217 iB_{j} = iB_{j} + Dx'*Dx; 218 end 219 else 220 % constrain of derivative with even order (j-1) 221 % (laplacian, biharmonic,...) 222 223 % normalize by surface of each cell 224 % such that inner produces (i.e. WE'*WE) 225 % become integrals 226 % WD: units length^(n/2) 227 228 WD = WE * D^(k+1); 229 iB_{j} = WD'*WD; 230 end 231 232 iB_{j} = iB_{j}/coeff; 233end 234 235 236% sum all terms of iB 237% iB is adimentional 238iB = alpha(1) * iB_{1}; 239for j=2:length(alpha) 240 iB = iB + alpha(j) * iB_{j}; 241end 242 243s.coeff = coeff; 244end 245 246% inverse of background covariance matrix 247s.iB = iB; 248 249% individual terms of background covariance matrix (corresponding alpha) 250s.iB_ = iB_; 251 252s.L = L; 253s.Ln = Ln; 254 255s.moddim = moddim; 256s.iscyclic = iscyclic; 257 258s.alpha = alpha; 259s.neff = neff; 260s.WE = WE; % units length^(n/2) 261 262% Copyright (C) 2014 Alexander Barth <a.barth@ulg.ac.be> 263% 264% This program is free software; you can redistribute it and/or modify it under 265% the terms of the GNU General Public License as published by the Free Software 266% Foundation; either version 2 of the License, or (at your option) any later 267% version. 268% 269% This program is distributed in the hope that it will be useful, but WITHOUT 270% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 271% FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 272% details. 273% 274% You should have received a copy of the GNU General Public License along with 275% this program; if not, see <http://www.gnu.org/licenses/>. 276