|
a |
|
b/Cobiveco/functions/solveTrajectDist.m |
|
|
1 |
function d = solveTrajectDist(G, T, boundaryIds, boundaryVal, tol, maxit) |
|
|
2 |
% Computes the solution d of the "trajectory distance" equation dot(G*d,T) = 1 |
|
|
3 |
% with boundary conditions u(boundaryIds) = boundaryVal |
|
|
4 |
% (see https://doi.org/10.1109/TMI.2003.817775, equation 3, where L0 = d). |
|
|
5 |
% |
|
|
6 |
% d = solveTrajectDist(G, T, boundaryIds, boundaryVal, tol, maxit) |
|
|
7 |
% |
|
|
8 |
% Inputs: |
|
|
9 |
% G: gradient operator matrix computed with grad() of gptoolbox [3*numCells x numPoints] |
|
|
10 |
% T: normalized tangent field defining the course of trajectories [numCells x 3] |
|
|
11 |
% boundaryIds: point IDs for Dirichlet boundary conditions [numBoundaryPoints x 1] |
|
|
12 |
% boundaryVal: values for Dirichlet boundary conditions [numBoundaryPoints x 1] |
|
|
13 |
% tol: tolerance for minres |
|
|
14 |
% maxit: maximum number of iterations for minres |
|
|
15 |
% |
|
|
16 |
% Outputs: |
|
|
17 |
% d: distance along trajectories (starting from boundaryIds with boundaryVal) [numPoints x 1] |
|
|
18 |
% |
|
|
19 |
% Written by Steffen Schuler, Institute of Biomedical Engineering, KIT |
|
|
20 |
|
|
|
21 |
if nargin < 6 |
|
|
22 |
maxit = 2000; |
|
|
23 |
end |
|
|
24 |
if nargin < 5 |
|
|
25 |
tol = []; |
|
|
26 |
end |
|
|
27 |
|
|
|
28 |
if numel(boundaryIds) ~= numel(unique(boundaryIds)) |
|
|
29 |
error('Duplicate entries found in boundaryIds.'); |
|
|
30 |
end |
|
|
31 |
|
|
|
32 |
[nC,nDim] = size(T); |
|
|
33 |
|
|
|
34 |
% For each cell, T_mat computes the dot product of the tangent field T |
|
|
35 |
% with another vector field defined at the cells and represented as a |
|
|
36 |
% 3*nC x 1 vector [x1; x2; ...; y1; y2; ...; z1; z2; ...] |
|
|
37 |
i = reshape(repmat(1:nC, nDim, 1), [], 1); |
|
|
38 |
j = reshape(reshape(1:nDim*nC, [], 3)', [], 1); |
|
|
39 |
v = reshape(T', [], 1); |
|
|
40 |
T_mat = sparse(i, j, v, nC, nDim*nC); |
|
|
41 |
|
|
|
42 |
% For each cell, S computes the dot product of the tangent field T |
|
|
43 |
% with the gradient of a scalar field defined at the points, |
|
|
44 |
% i.e. a nP x 1 vector |
|
|
45 |
S = T_mat * G; |
|
|
46 |
|
|
|
47 |
% As nC > nP, the linear system S*d = 1 is overdetermined, |
|
|
48 |
% so we minimize norm(S*d-1) by solving A*d = b |
|
|
49 |
A = S'*S; |
|
|
50 |
b = S'*ones(nC,1); |
|
|
51 |
|
|
|
52 |
N = length(A); |
|
|
53 |
K = numel(boundaryIds); |
|
|
54 |
boundaryIds = double(boundaryIds); |
|
|
55 |
|
|
|
56 |
% set up right-hand side |
|
|
57 |
b = b - A(:,boundaryIds)*boundaryVal(:); |
|
|
58 |
b(boundaryIds) = boundaryVal; |
|
|
59 |
|
|
|
60 |
% add boundary conditions to coefficient matrix |
|
|
61 |
A(boundaryIds,:) = sparse(1:K, boundaryIds, ones(K,1), K, N); |
|
|
62 |
A(:,boundaryIds) = sparse(boundaryIds, 1:K, ones(K,1), N, K); |
|
|
63 |
|
|
|
64 |
% apply reverse Cuthill-McKee reordering |
|
|
65 |
p = symrcm(A); |
|
|
66 |
A = A(p,p); |
|
|
67 |
b = b(p); |
|
|
68 |
|
|
|
69 |
icMat = ichol_autocomp(A); |
|
|
70 |
[x, flag, relres, iter] = minres(A, b, tol, maxit, icMat, icMat'); |
|
|
71 |
if flag |
|
|
72 |
warning('minres failed at iteration %i with flag %i and relative residual %.1e.', iter, flag, relres); |
|
|
73 |
end |
|
|
74 |
d = NaN(N,1); |
|
|
75 |
d(p) = x; |
|
|
76 |
|
|
|
77 |
end |