我正在进行一些计算,我需要评估以某些节点为中心的Voronoi多边形之间的通量。为此,我需要找到多个多边形之间的公共边,例如。 V1& V2如下图所示。每个边缘只应评估一次。
要做到这一点,我把我的x-&节点的y坐标并执行Delaunay triangulation以查找邻居节点。然后我运行一个循环来确定哪些节点有共同的顶点。然后我计算Voronoi多边形并创建一个数组( istr ),其索引为' edge'数字和值是中央voronoi多边形。 ' neigh'然后,数组将索引作为' edge'数字和所有相邻的多边形值。在检查以确保我不对每个边缘重复该评估之后,我计算边缘(即,在每个多边形之间共享的顶点)。
我可以使用下面的代码计算边缘,但是用于计算 nodneigh 的for循环存在巨大的瓶颈,因为需要迭代地访问单元阵列的组件。花费更多时间的是使用单元函数计算 edge 来访问Delaunay三角剖分/ Voronoi多边形的输出。
我的问题是如何加快这两个瓶颈?虽然我很欣赏Matlab中单元阵列的灵活性,但是当我不需要它时,我觉得它真的会减慢一切。我已经尝试用NaNs填充单元阵列,将其转换为矩阵并执行行相交,但这并没有如此成功:arrayfun需要更长时间,而且我可以“似乎与GPU计算相交。
% Create dummy data
nstr = 1000; % number of particles
x = rand(nstr,1); % particle x coordinates
y = rand(nstr,1); % particle y coordinates
% Delaunay triangulation
DT = delaunayTriangulation(x,y);
% Determine node neighbors of the original nodes
nodneigh = cell(nstr,1);
numtotneigh = 0; % initialise total # of neighbors
bla = DT.vertexAttachments; % Get the particle/triangle IDs
% BOTTLENECK 1: Find out which particles/triangles are neighbours
for istr = 1:nstr
nodneigh{istr} = setdiff(unique(DT.ConnectivityList(bla{istr},:)),istr);
numtotneigh = numtotneigh+length(nodneigh{istr});
end
% Construct Thiessen polygons by Voronoi tessalation
[voro_V,voro_R] = DT.voronoiDiagram;
% Bookkeeping - create an index of edges with associated voronoi regions
cellsz = cellfun(@size,nodneigh,'uni',false);
cellsz = cell2mat(cellsz);
cellsz = cellsz(:,1);
temp = [1:nstr];
idx([cumsum([1 cellsz(cellsz>0)'])]) = 1;
istr = temp(cumsum(idx(1:find(idx,1,'last')-1)))'; % Region number
neigh = vertcat(nodneigh{:}); % Region neighbours
neigh_m = mod(neigh,nstr);
% Make sure neighbourship has not already been evaluated
idx = neigh_m == 0;
neigh_m(idx,:) = nstr;
neigh = vertcat(nodneigh{:});
% BOTTLENECK 2:
% Determine which edges are common to both central and neighbour regions
edge = cellfun(@intersect,voro_R(istr),voro_R(neigh),...
'UniformOutput',false);
edge = cell2mat(edge);
答案 0 :(得分:0)
您可以循环边缘并计算从边缘中点到所有站点的距离。然后按升序对距离进行排序,对于内部voronoi多边形,选择第一个和第二个。对于外多边形,选择第一个。基本上边缘分开/分割2个多边形。
它应该更快(瓶颈#2)。您不需要计算(全部)voronoi图的三角测量的邻居。当你走遍所有三角形边缘并检查重影(双边)(瓶颈#1)时它会起作用。
答案 1 :(得分:-1)
好的,终于得到了我很满意的东西。通过利用DelaunayTriangulation类的 edge 方法,我可以解决第一个瓶颈。我认为现在的计算略有不同,但我猜他们现在有点严谨了。我已经设法通过将单元阵列移动到矩阵然后循环遍历这个来加速第二个瓶颈。我使用ismember而不是相交,部分是因为我发现this helpful post关于如何在matlab中使用intersect和setdiff提高性能。
% Create dummy data
nstr = 1000; % number of particles
x = rand(nstr,1); % particle x coordinates
y = rand(nstr,1); % particle y coordinates
% Delaunay triangulation
DT = delaunayTriangulation(x,y);
% construct Thiessen polygons by Voronoi tessalation
[voro_V,voro_R] = DT.voronoiDiagram;
dt_ed = DT.edges;
istr = dt_ed(dt_ed(:,1)<=nstr,1);
neigh = dt_ed(dt_ed(:,1)<=nstr,2);
% Determine cross-sectional area and Dtrans of all nodes
neigh_m = mod(neigh,nstr);
% if neigh_m == 0, neigh_m = nstr; end
% if the index of the neighboring streamline is smaller than
% that of the current streamline, the relationship has already
% been evaluated
idx = neigh_m == 0;
neigh_m(idx,:) = nstr;
temp_is = nan(numel(istr),40);
temp_ne = nan(numel(istr),40);
edge = nan(numel(istr),2);
for index = 1:numel(istr)
temp_len1 = length(voro_R{istr(index)});
temp_len2 = length(voro_R{neigh(index)});
temp_is(index,1:temp_len1) = voro_R{istr(index)};
temp_ne(index,1:temp_len2) = voro_R{neigh(index)};
edge(index,:) = temp_is(index,ismember(temp_is(index,:),temp_ne(index,:)));
end
这些更改使我的代码运行速度比原始代码快3-4倍。如果有人有任何更好的想法(也许基于GPU的东西会有帮助吗?)我愿意接受更好的答案。