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