-
Notifications
You must be signed in to change notification settings - Fork 3
/
mcouplings.m
132 lines (115 loc) · 3.7 KB
/
mcouplings.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
function M=mcouplings(L,Lmax,approx,appL)
% M=mcouplings(L,Lmax,approx,appL)
%
% Calculates the mode-coupling matrix for eigenvalue-weighted multitaper
% analysis of arbitrary regions. Its shape depends only on bandwidth L.
% Dahlen and Simons (2008) eq. (145).
%
% INPUT
%
% L Bandwidth (maximum angular degree) of the taper
% Lmax Bandwidth (maximum angular degree) of the spectrum
% approx 0 No approximations are made, the whole thing is calculated
% 1 When the second index exceeds appL, the rows are copied down
% appL From where on is the approximation invoked [default: 3*L]
% Note: will need to calculate (appL+L) Wigner 0j coefficients
%
% OUTPUT:
%
% M Coupling matrix (the eigenvalue-weighted sum of the
% individual-taper coupling matrices MG from MCOUPLING)
%
% See also: MCOUPLING
%
% Last modified by fjsimons-at-alum.mit.edu, 04/02/2007
% Maybe later modify to do only certain rows
defval('L',18)
defval('xver',0)
defval('Lmax',100)
defval('approx',0)
if approx==1
defval('appL',3*L)
if appL+L>=Lmax
% It's not an approximation now anymore is it
approx=0;
appL=0;
disp('You''re getting an exact result')
end
else
appL=0;
end
if approx~=0 & approx~=1
error('Specify valid option approx')
end
fname=fullfile(getenv('IFILES'),'MCOUPLINGS',...
sprintf('MCOUPLINGS-%i-%i-%i-%i.mat',...
L,Lmax,approx,appL));
if exist(fname)==2
disp(sprintf('load %s',fname))
load(fname)
else
tic
% Initialize matrix with zeros
M=repmat(0,[Lmax+1 Lmax+1]);
h=waitbar(0,'MCOUPLINGS: Doing the sums, be patient');
LmaxT=Lmax;
if approx==1
Lmax=appL;
end
% Best to get all of the Wigner 0-j symbols at once
% This is always faster than computing unsaved 0j's on the fly
[jk,C0,S0]=zeroj(0,0,0,Lmax+L*(approx==1));
% Do the lower triangular half of the coupling matrix
for l=0:Lmax
% Know this is a BANDLIMITED kernel so just stop at the right time
% This cuts the computation time dramatically
for lp=max(0,l-L):l+L*(approx==1)
% Calculate the arrays of Wigner 0j symbols
%FJS WAG=zeroj([0:L],repmat(l,1,L+1),repmat(lp,1,L+1),...
WAG=zeroj([0:L],l,lp,...
Lmax+L*(approx==1),[],C0,S0).^2*(2*[0:L]+1)';
if xver==1
% This is the old way where you compute these on the fly
WAG=wigner0j(L,l,lp).^2*(2*[0:L]+1)';
difer(WAG-WAG2,[],[],'MCOUPLINGS Check passed')
%disp('Another excessive test passed')
end
% Fill the elements
M(l+1,lp+1)=WAG;
end
waitbar(lp/(Lmax+1),h)
end
if approx==0
% Symmetrize this portion appropriately in one line
M=[M-diag(diag(M))]+[M-diag(diag(M))]'+diag(diag(M));
% How about: M=M+tril(M',-1);
end
% Don't forget about the (2l'+1) for the column dimensions
% M=M.*repmat(2*[0:LmaxT]+1,LmaxT+1,1)/(L+1)^2;
% This is the same thing, perhaps a bit more elegantly
% Remember it's constant diagonal AFTER the asymmetry
M=M*diag(2*[0:LmaxT]+1)/(L+1)^2;
if approx==1
% Use an approximation
% The row index of the last row
i=Lmax+1;
% The column index of the last row
j=Lmax-L+1;
% Extract the nonzero elements from the last row and copy it down
s=repmat(M(i,j:j+2*L),LmaxT-Lmax,1);
% Make column indices that repeat
j=pauli(j+1:LmaxT+1+L,2*L+1);
i=repmat([i+1:LmaxT+1]',1,2*L+1);
% This is the continuation of the lower triangular part
S=sparse(i,j,s);
M=M+S(:,1:LmaxT+1);
end
% Save for future reference
eval(sprintf('save %s M L Lmax LmaxT',fname))
toc
close(h)
end
% Check we're dealing with the right normalization etc.
difer(sum(M(1:LmaxT-L+1,:),2)-1,9,[],...
sprintf('MCOUPLINGS: Row sum equals %5.3f check passed',...
mean(sum(M(1:LmaxT-L+1,:),2))))