From 62af03665ac29ba2e747a41df2d6f7645c815e09 Mon Sep 17 00:00:00 2001 From: Manas Rachh Date: Sat, 24 Aug 2024 22:05:14 -0400 Subject: [PATCH 1/2] adding support smooth chunkers in chunkgraph --- chunkie/@chunker/onesmat.m | 6 +- chunkie/@chunkgraph/build_v2emat.m | 30 +- chunkie/@chunkgraph/chunkgraph.m | 294 ++++++++---------- chunkie/@chunkgraph/findregions.m | 128 +++++++- chunkie/@chunkgraph/max.m | 20 ++ chunkie/@chunkgraph/min.m | 20 ++ chunkie/@chunkgraph/move.m | 53 ++++ chunkie/@chunkgraph/normonesmat.m | 34 ++ chunkie/@chunkgraph/onesmat.m | 31 ++ chunkie/@chunkgraph/plot_regions.m | 14 +- chunkie/@chunkgraph/signed_curvature.m | 12 + chunkie/@chunkgraph/tangents.m | 24 ++ devtools/test/axissymkernTest.m | 3 +- devtools/test/chunkermatapplyTest.m | 4 - devtools/test/chunkgrphrcipTest.m | 10 - devtools/test/chunkgrphrcipTransmissionTest.m | 4 - devtools/test/chunkgrphregionTest.m | 65 ++-- devtools/test/chunkrgrphOpdimTest.m | 9 - devtools/test/mixedbcTest.m | 4 - 19 files changed, 498 insertions(+), 267 deletions(-) create mode 100644 chunkie/@chunkgraph/max.m create mode 100644 chunkie/@chunkgraph/min.m create mode 100644 chunkie/@chunkgraph/move.m create mode 100644 chunkie/@chunkgraph/normonesmat.m create mode 100644 chunkie/@chunkgraph/onesmat.m create mode 100644 chunkie/@chunkgraph/signed_curvature.m create mode 100644 chunkie/@chunkgraph/tangents.m diff --git a/chunkie/@chunker/onesmat.m b/chunkie/@chunker/onesmat.m index 9dd2263..85b6a6c 100644 --- a/chunkie/@chunker/onesmat.m +++ b/chunkie/@chunker/onesmat.m @@ -14,12 +14,12 @@ % % Output: % mat - the matrix discretization of the operator W above. mat is -% (2*chnkr.npt) x (2*chnkr.npt) +% (chnkr.npt) x (chnkr.npt) % % Examples: -% mat = normonesmat(chnkr) +% mat = onesmat(chnkr) % -% see also ONESMAT +% see also NORMONESMAT % author: Travis Askham (askhamwhat@gmail.com) diff --git a/chunkie/@chunkgraph/build_v2emat.m b/chunkie/@chunkgraph/build_v2emat.m index 0357754..8336147 100644 --- a/chunkie/@chunkgraph/build_v2emat.m +++ b/chunkie/@chunkgraph/build_v2emat.m @@ -21,20 +21,22 @@ for i = 1:nedges j1 = obj.edgesendverts(1,i); j2 = obj.edgesendverts(2,i); - if j1 == j2 - nf = nf + 1; - ii(nf) = i; - jj(nf) = j1; - vv(nf) = 2; - else - nf = nf + 1; - ii(nf) = i; - jj(nf) = j1; - vv(nf) = -1; - nf = nf + 1; - ii(nf) = i; - jj(nf) = j2; - vv(nf) = 1; + if ~isnan(j1) && ~isnan(j2) + if j1 == j2 + nf = nf + 1; + ii(nf) = i; + jj(nf) = j1; + vv(nf) = 2; + else + nf = nf + 1; + ii(nf) = i; + jj(nf) = j1; + vv(nf) = -1; + nf = nf + 1; + ii(nf) = i; + jj(nf) = j2; + vv(nf) = 1; + end end end diff --git a/chunkie/@chunkgraph/chunkgraph.m b/chunkie/@chunkgraph/chunkgraph.m index a1ea9d4..a481e97 100644 --- a/chunkie/@chunkgraph/chunkgraph.m +++ b/chunkie/@chunkgraph/chunkgraph.m @@ -1,11 +1,58 @@ classdef chunkgraph -%CHUNKGRAPH chunk graph class which describes a domain using "graph" -% terminology. Singular points of the geometry (or of the +%CHUNKGRAPH class which describes a domain using "graph" +% of chunkers. Singular points of the geometry (or of the % boundary value problem) are the vertices of the graph. Smooth, regular -% curves are the edges of the graph. A vertex must be the end point of at -% least one edge. The interiors of distinct edges should not intersect. For -% such domains, a vertex should be introduced at the point of intersection -% and the curves broken so that they do not intersect. +% curves are the edges of the graph. The interiors of distinct edges should +% not intersect. For such domains, a vertex should be introduced at the +% point of intersection and the curves broken so that they do not intersect. +% +% chunkgraph properties: +% +% verts - 2 x nverts array of vertex locations +% edgesendverts - 2 x nedges array of starting and ending vertices for +% each edge +% echnks - nedge x 1 array of chunker objects discretizing each edge curve +% regions - nregions x 1 cell array specifying region information for the +% given graph structure. A region is a connected subset of R^2 +% specified by its bounding edges. If the jth region is simply +% connected then abs(regions{j}{1}) is the list of edges which +% comprise the boundary of region j. The sign of the edges indicate +% the direction of traversal for that edge. The edges are ordered +% according to an orientation based on nesting. The boundary of the +% outermost (unbounded) region is traversed clockwise. +% vstruc - nverts x 1 cell array. vstruc{j}{1} gives a list of edges which +% are incident to a vertex. vstruc{j}{2} is a list of the same length +% consisting of +1 and -1. If +1 then the corresponding edge ends at +% the vertex, if -1 it begins at the vertex. +% v2emat - sparse nedge x nverts matrix, akin to a connectivity matrix. +% the entry v2emat(i,j) is 1 if edge i ends at vertex j, it is -1 if +% edge i starts at vertex j, and it is 2 if edge i starts and ends at +% vertex j. +% +% chunkgraph methods: +% plot(obj, varargin) - plot the chunkgraph +% quiver(obj, varargin) - quiver plot of chunkgraph points and normals +% plot_regions(obj, iflabel) - plot the chunkgraph with region and +% and edge labels +% obj = refine(obj,varargin) - refine the curve +% wts = weights(obj) - scaled integration weights on curve +% rn = normals(obj) - recompute normal vectors +% obj = obj.move(r0,r1,trotat,scale) - translate, rotate, etc +% rmin = min(obj) - minimum of coordinate values +% rmax = max(obj) - maximum of coordinate values +% onesmat = onesmat(obj) - matrix that corresponds to integration of a +% density on the chunkgraph +% rnormonesmat = normonesmat(obj) - matrix that corresponds to +% integration of dot product of normal with vector density on +% the chunkgraph +% tau = tangents(obj) - unit tangents to curve +% kappa = signed_curvature(obj) - get signed curvature along curve +% +% To add: +% scatter +% make data rows +% datares +% % % Syntax: % @@ -38,39 +85,15 @@ % if no function handle is specified, then echnks(j) will be the % straight line connecting the given vertices. % -% Class properties: -% -% verts = 2 x nverts array of vertex locations -% edgesendverts = 2 x nedges array of starting and ending vertices for -% each edge -% echnks = nedge x 1 array of chunker objects discretizing each edge curve -% regions = nregions x 1 cell array specifying region information for the -% given graph structure. A region is a connected subset of R^2 -% specified by its bounding edges. If the jth region is simply -% connected then abs(regions{j}{1}) is the list of edges which -% comprise the boundary of region j. The sign of the edges indicate -% the direction of traversal for that edge. The edges are ordered -% according to an orientation based on nesting. The boundary of the -% outermost (unbounded) region is traversed clockwise. -% vstruc = nverts x 1 cell array. vstruc{j}{1} gives a list of edges which -% are incident to a vertex. vstruc{j}{2} is a list of the same length -% consisting of +1 and -1. If +1 then the corresponding edge ends at -% the vertex, if -1 it begins at the vertex. -% v2emat = sparse nedge x nverts matrix, akin to a connectivity matrix. -% the entry v2emat(i,j) is 1 if edge i ends at vertex j, it is -1 if -% edge i starts at vertex j, and it is 2 if edge i starts and ends at -% vertex j. % - properties(SetAccess=public) + properties(SetAccess = public) verts edgesendverts echnks regions vstruc v2emat - end - - properties(SetAccess=public) + r d d2 @@ -78,7 +101,15 @@ wts adj sourceinfo + + data + end + + properties(Dependent, SetAccess=private) npt + k + dim + datadim end methods @@ -111,8 +142,8 @@ end obj.edgesendverts = edgesendverts; - obj.v2emat = build_v2emat(obj); - obj.echnks = chunker.empty; + obj.v2emat = build_v2emat(obj); + obj.echnks = chunker.empty; if nargin < 3 fchnks = []; @@ -133,7 +164,9 @@ assert(isempty(cparams) || isstruct(cparams) || (iscell(cparams) && length(cparams) == nedge),msg); if nargin < 5 - pref = []; + pref = chunkerpref(); + else + pref = chunkerpref(pref); end echnks = chunker.empty(); @@ -164,6 +197,14 @@ "may have unexpected behavior"; warning(msg); end + + if (isnan(i1) || isnan(i2)) + msg = "CHUNKGRAPH:CONSTRUCTOR: cannot create a " + ... + "smooth curve without a function handle." + ... + " fchnks{iedge} must be provided if either" + ... + "vertex of edge end is NaN"; + error(msg); + end v1 = verts(:,i1); v2 = verts(:,i2); fcurve = @(t) chnk.curves.linefunc(t,v1,v2); @@ -202,30 +243,32 @@ chnkr = sort(chnkr); i1 = edgesendverts(1,i); i2 = edgesendverts(2,i); - if i1 ~= i2 - vfin0 = verts(:,i1); - vfin1 = verts(:,i2); - r0 = vs(:,1); - r1 = vfin0; - scale = norm(vfin1-vfin0,'fro')/norm(vs(:,2)-vs(:,1),'fro'); - xdfin = vfin1(1)-vfin0(1); - ydfin = vfin1(2)-vfin0(2); - tfin = atan2(ydfin,xdfin); - xdini = vs(1,2)-vs(1,1); - ydini = vs(2,2)-vs(2,1); - tini = atan2(ydini,xdini); - trotat = tfin - tini; - chnkr = move(chnkr,r0,r1,trotat,scale); - else - vfin = verts(:,i1); - if norm(vs(:,1)-vs(:,2))/max(abs(chnkr.r(:))) > 1e-14 - msg = "chunkgraph constructor: edge " + ... - num2str(i) + " is defined as a loop but " + ... - "curve defining the edge does not reconnect " + ... - "to high precision"; - warning(msg); + if ~isnan(i1) && ~isnan(i2) + if i1 ~= i2 + vfin0 = verts(:,i1); + vfin1 = verts(:,i2); + r0 = vs(:,1); + r1 = vfin0; + scale = norm(vfin1-vfin0,'fro')/norm(vs(:,2)-vs(:,1),'fro'); + xdfin = vfin1(1)-vfin0(1); + ydfin = vfin1(2)-vfin0(2); + tfin = atan2(ydfin,xdfin); + xdini = vs(1,2)-vs(1,1); + ydini = vs(2,2)-vs(2,1); + tini = atan2(ydini,xdini); + trotat = tfin - tini; + chnkr = move(chnkr,r0,r1,trotat,scale); + else + vfin = verts(:,i1); + if norm(vs(:,1)-vs(:,2))/max(abs(chnkr.r(:))) > 1e-14 + msg = "chunkgraph constructor: edge " + ... + num2str(i) + " is defined as a loop but " + ... + "curve defining the edge does not reconnect " + ... + "to high precision"; + warning(msg); + end + chnkr = move(chnkr,zeros(size(vs(:,1))),vfin-vs(:,1),0,1); end - chnkr = move(chnkr,zeros(size(vs(:,1))),vfin-vs(:,1),0,1); end echnks(i) = chnkr; @@ -234,90 +277,9 @@ obj.echnks = echnks; obj.vstruc = procverts(obj); obj.wts = weights(obj); - %[regions] = findregions(obj); - %obj.regions = regions; - g = graph(edgesendverts(1,:),edgesendverts(2,:)); - ccomp = conncomp(g); - - chnkcomp = {}; - regions = {}; - for i=1:max(ccomp) - inds = find(ccomp==i); - chnkcomp{i} = inds; - [region_comp] = findregions(obj,inds); - [region_comp] = findunbounded(obj,region_comp); - regions{i} = region_comp; - end - - gmat = zeros(numel(regions)); - - for ii=1:numel(regions) - rgna = regions{ii}; - ilist = []; - for jj=1:numel(regions) - if (ii ~=jj) - rgnb = regions{jj}; - [inc] = regioninside(obj,rgnb,rgna); - if (inc) - ilist = [ilist,jj]; - end - end - gmat(ii,ilist) = 1; - gmat(ilist,ii) = 1; - end - imin = min(ilist); - end - - ccomp_reg = conncomp(graph(gmat)); - [s,inds] = sort(ccomp_reg); - regions = regions(inds); - - for ii = 1:numel(s) - si = s(ii); - for jj=1:(numel(s)-1) - sj = s(jj); - if (si == sj) - rgna = regions{jj}; - rgnb = regions{jj+1}; - [inc] = regioninside(obj,rgna,rgnb); - if (inc) - regions([jj,jj+1])= regions([jj+1,jj]); - end - end - end - end - - - rgns = regions; - rgnso= {}; - - for ii=1:max(s) - inds = find(s==ii); - rgnout = rgns{inds(1)}; - for jj=2:numel(inds) - indj = inds(jj); - [rgnout] = mergeregions(obj,rgnout,rgns{indj}); - end - rgnso{ii} = rgnout; - end - - regions = rgnso; - rgns = regions; - rgnout = rgns{1}; - if (numel(rgns)>1) - rgn2 = rgns{2}; - [rgnout] = mergeregions(obj,rgnout,rgn2); - for ii=3:numel(rgns) - rgn2 = rgns{ii}; - [rgnout] = mergeregions(obj,rgnout,rgn2); - end - end - - regions = rgnout; - - obj.regions = regions; + obj.regions = findregions(obj); obj = balance(obj); end @@ -370,28 +332,26 @@ npt = n + npt; end end + function k = get.k(obj) + k = size(obj.r,2); + end + function dim = get.dim(obj) + dim = size(obj.r,1); + end + function datadim = get.datadim(obj) + datadim = size(obj.data,1); + end + function sourceinfo = get.sourceinfo(obj) sourceinfo = []; - ntot = obj.npt; - rs = zeros(2,ntot); - ds = zeros(2,ntot); - d2s= zeros(2,ntot); - ws = zeros(ntot,1); - ind = 0; - for iedge = 1:numel(obj.echnks) - chnk = obj.echnks(iedge); - n = chnk.npt; - w = chnk.wts; - ws(ind+(1:n)) = w; - rs(:,ind+(1:n)) = chnk.r(:,:); - ds(:,ind+(1:n)) = chnk.d(:,:); - d2s(:,ind+(1:n)) = chnk.d2(:,:); - ind = ind + n; - end - sourceinfo.r = rs; - sourceinfo.d = ds; - sourceinfo.d2= d2s; - sourceinfo.w = ws; + chnkrtotal = merge(obj.echnks); + + sourceinfo.r = chnkrtotal.r(:,:); + sourceinfo.n = chnkrtotal.n(:,:); + sourceinfo.d = chnkrtotal.d(:,:); + sourceinfo.d2 = chnkrtotal.d2(:,:); + sourceinfo.w = chnkrtotal.wts(:); + end function inds = edgeinds(obj,edgelist) ladr = cumsum([1,obj.echnks.npt]); @@ -406,6 +366,20 @@ spmat = build_v2emat(obj) obj = refine(obj,opts) obj = balance(obj) + obj = move(obj,r0,r1,trotat,scale) + rmin = min(obj) + rmax = max(obj) + plot(obj,varargin) + quiver(obj,varargin) + plot_regions(obj, iflabel) + wts = weights(obj) + rnorm = normals(obj) + onesmat = onesmat(obj) + rnormonesmat = normonesmat(obj) + tau = tangents(obj) + kappa = signed_curvature(obj) + + end methods(Static) diff --git a/chunkie/@chunkgraph/findregions.m b/chunkie/@chunkgraph/findregions.m index 4c87942..fe93c8f 100644 --- a/chunkie/@chunkgraph/findregions.m +++ b/chunkie/@chunkgraph/findregions.m @@ -1,11 +1,130 @@ -function [regions] = findregions(obj,iverts) -%FINDREGIONS a relatively crude method for determining the regions of +function [regions] = findregions(obj_in) +%FINDREGIONS determins the regions of a chunkgraph. This routine handles +% the situations involving nested chunkers inside the chunkgraph +% +% Syntax: [regions] = findregions(obj, iverts); +% +% Input: +% obj_in - a chunkgraph object +% iverts(optional) - the indices of the subset of vertices for which regions +% are to be found. +% +% Output: +% regions - a cell array of length nregions (the number of regions +% found). Each region is specified by a vector of +% indices of edges which traverse the boundary. + +% author: Jeremy Hoskins + + obj = obj_in; + [~, c] = find(isnan(obj.edgesendverts)); + c = unique(c); + nnew = length(c); + [~, nv] = size(obj.verts); + nvnew = nv + nnew; + verts_new = zeros(2,nvnew); + verts_new(:,1:nv) = obj.verts; + + for i = 1:nnew + verts_new(:,nv+i) = obj.echnks(c(i)).r(:,1); + obj.edgesendverts(:, c(i)) = nv + i; + end + obj.verts = verts_new; + obj.v2emat = build_v2emat(obj); + obj.vstruc = procverts(obj); + + g = graph(obj.edgesendverts(1,:),obj.edgesendverts(2,:)); + ccomp = conncomp(g); + + chnkcomp = {}; + regions = {}; + + for i=1:max(ccomp) + inds = find(ccomp==i); + chnkcomp{i} = inds; + [region_comp] = findregions_verts(obj,inds); + [region_comp] = findunbounded(obj,region_comp); + regions{i} = region_comp; + end + + gmat = zeros(numel(regions), numel(regions)); + + for ii=1:numel(regions) + rgna = regions{ii}; + ilist = []; + for jj=1:numel(regions) + if (ii ~=jj) + rgnb = regions{jj}; + [inc] = regioninside(obj,rgnb,rgna); + if (inc) + ilist = [ilist,jj]; + end + end + gmat(ii,ilist) = 1; + gmat(ilist,ii) = 1; + end + imin = min(ilist); + end + + ccomp_reg = conncomp(graph(gmat)); + [s,inds] = sort(ccomp_reg); + regions = regions(inds); + + for ii = 1:numel(s) + si = s(ii); + for jj=1:(numel(s)-1) + sj = s(jj); + if (si == sj) + rgna = regions{jj}; + rgnb = regions{jj+1}; + [inc] = regioninside(obj,rgna,rgnb); + if (inc) + regions([jj,jj+1])= regions([jj+1,jj]); + end + end + end + end + + + rgns = regions; + rgnso= {}; + + for ii=1:max(s) + inds = find(s==ii); + rgnout = rgns{inds(1)}; + for jj=2:numel(inds) + indj = inds(jj); + [rgnout] = mergeregions(obj,rgnout,rgns{indj}); + end + rgnso{ii} = rgnout; + end + + regions = rgnso; + rgns = regions; + rgnout = rgns{1}; + if (numel(rgns)>1) + rgn2 = rgns{2}; + [rgnout] = mergeregions(obj,rgnout,rgn2); + for ii=3:numel(rgns) + rgn2 = rgns{ii}; + [rgnout] = mergeregions(obj,rgnout,rgn2); + end + end + + regions = rgnout; + + +end + + +function [regions] = findregions_verts(obj, iverts) +%FINDREGIONS_VERTS a relatively crude method for determining the regions of % a chunkgraph associated with the subset of its vertices stored in iverts. % NOTE: if iverts is not provided then all vertices will be considered. The % Matlab routine conncomp can be used to provide subsets of vertices which % will define meaningful subregions. % -% Syntax: [regions] = findregions(obj,iverts); +% Syntax: [regions] = findregions_verts(obj, iverts); % % Input: % obj - a chunkgraph object @@ -16,9 +135,6 @@ % regions - a cell array of length nregions (the number of regions % found). Each region is specified by a vector of % indices of edges which traverse the boundary. -% -% -% % author: Jeremy Hoskins diff --git a/chunkie/@chunkgraph/max.m b/chunkie/@chunkgraph/max.m new file mode 100644 index 0000000..e4db7dd --- /dev/null +++ b/chunkie/@chunkgraph/max.m @@ -0,0 +1,20 @@ +function rmax = max(obj) +%MAX maximum value of each coordinate over chunkgraph nodes +% +% This is *not* the maximum extent of the curve +% +% Syntax: rmax = max(chnkr) +% +% Input: +% chnkr - chunker object +% +% Output: +% rmax - chnkr.dim length vector of maximum node value in each direction +% +% Examples: +% rmax = max(chnkr); +% + +% author: Travis Askham (askhamwhat@gmail.com) + +rmax = max(real(reshape(obj.r,obj.dim,obj.npt)),[],2); \ No newline at end of file diff --git a/chunkie/@chunkgraph/min.m b/chunkie/@chunkgraph/min.m new file mode 100644 index 0000000..cdd1ce8 --- /dev/null +++ b/chunkie/@chunkgraph/min.m @@ -0,0 +1,20 @@ +function rmin = min(obj) +%MIN minimum value of each coordinate over chunkgraph nodes +% +% This is *not* the minimum extent of the curve +% +% Syntax: rmin = min(chnkr) +% +% Input: +% chnkr - chunker object +% +% Output: +% rmin - chnkr.dim length vector of minimum node value in each direction +% +% Examples: +% rmin = min(chnkr); +% + +% author: Travis Askham (askhamwhat@gmail.com) + +rmin = min(real(reshape(obj.r,obj.dim,obj.npt)),[],2); \ No newline at end of file diff --git a/chunkie/@chunkgraph/move.m b/chunkie/@chunkgraph/move.m new file mode 100644 index 0000000..cfc7df2 --- /dev/null +++ b/chunkie/@chunkgraph/move.m @@ -0,0 +1,53 @@ +function obj = move(obj, r0, r1, trotat, scale) +%MOVE update the position of chunkers in the chunkgraph by +% translation, rotation, and scaling. +% +% Syntax +% chnkgraph = chnkgraph.move(r0,r1,trotat,scale) +% +% will shift the chunker geometry by -r0, rotate it by angle trotat, +% scale the points by the factor scale, and shift back by +r1, i.e. the +% coordinates will be changed by +% +% r <- s*M*(r-r0) + r1 +% +% where M is the rotation matrix for trotat radians and s is the scale +% +% Input: +% r0 - length 2 array, center of rotation. if empty, r0=[0;0] +% r1 - length 2 array, new center. if empty, r1=[0;0] +% trotat - float, angle of rotation in radians. if empty, trotat=0 +% scale - float, scaling factor. ifempty, scale = 1 +% +% Output: +% chnkr - chunker object with positions, derivatives, normals etc updated +% according to the formula above. +% + +if nargin < 2 || isempty(r0) + r0 = [0;0]; +end +if nargin < 3 || isempty(r1) + r1 = [0;0]; +end +if nargin < 4 || isempty(trotat) + trotat = 0; +end +if nargin < 5 || isempty(scale) + scale = 1; +end + +for i = 1:length(obj.echnks) + obj.echnks(i) = move(obj.echnks(i), r0,r1,trotat,scale); +end + +vsize = size(obj.verts); + +rotmat = [cos(trotat),-sin(trotat);sin(trotat),cos(trotat)]; + +vertsnew = scale*rotmat*(obj.verts(:,:)-r0) + r1; +obj.verts = reshape(vertsnew, vsize); + + + +end diff --git a/chunkie/@chunkgraph/normonesmat.m b/chunkie/@chunkgraph/normonesmat.m new file mode 100644 index 0000000..4c3457f --- /dev/null +++ b/chunkie/@chunkgraph/normonesmat.m @@ -0,0 +1,34 @@ +function mat = normonesmat(cgrph) +%NORMONESMAT for 2D curves. Forms the matrix for the operator +% +% W[\mu](x) = n(x) \int n(y)\cdot \mu(y) \, dl +% +% which project a vector density (\mu) on the chunker onto the normal +% vector along the chunker. This is a common operator in mechanics for +% removing nullspaces +% +% Syntax: mat = normonesmat(chnkr) +% +% Input: +% cgrph - chunkgraph object +% +% Output: +% mat - the matrix discretization of the operator W above. mat is +% (2*chnkr.npt) x (2*chnkr.npt) +% +% Examples: +% mat = normonesmat(cgrph) +% +% see also ONESMAT + +% author: Travis Askham (askhamwhat@gmail.com) + +wts = cgrph.wts; +rnorms = cgrph.n; +wts = wts(:); +wts2 = repmat(wts.',2,1); +wts2 = wts2(:).*rnorms(:); + +mat = bsxfun(@times,rnorms(:),wts2.'); + +end diff --git a/chunkie/@chunkgraph/onesmat.m b/chunkie/@chunkgraph/onesmat.m new file mode 100644 index 0000000..5aefa86 --- /dev/null +++ b/chunkie/@chunkgraph/onesmat.m @@ -0,0 +1,31 @@ +function mat = onesmat(cgrph) +%ONESMAT Forms the matrix for the operator +% +% W[\mu](x) = \int \mu(y) dl +% +% which projects a scalar density (\mu) on the chunker onto the constant +% vector along the chunker. This is a common operator for removing +% nullspaces +% +% Syntax: mat = onesmat(chnkr) +% +% Input: +% cgrph - chunkgraph object +% +% Output: +% mat - the matrix discretization of the operator W above. mat is +% (cgrph.npt) x (cgrph.npt) +% +% Examples: +% mat = onesmat(chnkr) +% +% see also NORMONESMAT + +% author: Travis Askham (askhamwhat@gmail.com) + +wts = cgrph.wts; +wts = wts(:); +temp = ones(size(wts)); +mat = bsxfun(@times,temp,wts.'); + +end diff --git a/chunkie/@chunkgraph/plot_regions.m b/chunkie/@chunkgraph/plot_regions.m index 70620da..691a9b4 100644 --- a/chunkie/@chunkgraph/plot_regions.m +++ b/chunkie/@chunkgraph/plot_regions.m @@ -42,9 +42,9 @@ function plot_regions(obj,iflabel) if (enum<0) rchnk = fliplr(rchnk); end - rs = [rs,rchnk]; + rs = [rs, rchnk]; end - plyrgn = polyshape(rs.','Simplify',false); + plyrgn = polyshape(rs.', 'Simplify', false); for jj=2:numel(regions{ii}) @@ -60,8 +60,8 @@ function plot_regions(obj,iflabel) rs = [rs,rchnk]; end - plyrgnsub = polyshape(rs','Simplify',false); - plyrgn = subtract(plyrgn,plyrgnsub); + plyrgnsub = polyshape(rs', 'Simplify', false); + plyrgn = subtract(plyrgn, plyrgnsub); end end @@ -76,10 +76,10 @@ function plot_regions(obj,iflabel) plot(obj,'k-'); if iflabel > 1 - rmin = min(obj.r(:,:),[],2); - diam = max(obj.r(:,:)-rmin,[],2); + rmin = min(obj.r(:,:), [], 2); + diam = max(obj.r(:,:)-rmin, [], 2); rmin = rmin-0.1*diam; - text(rmin(1),rmin(2),'region 1'); + text(rmin(1), rmin(2), 'region 1'); nedge = length(obj.echnks); for j = 1:nedge diff --git a/chunkie/@chunkgraph/signed_curvature.m b/chunkie/@chunkgraph/signed_curvature.m new file mode 100644 index 0000000..f34768f --- /dev/null +++ b/chunkie/@chunkgraph/signed_curvature.m @@ -0,0 +1,12 @@ +function kappa = signed_curvature(cgrph) +%CURVATURE returns the signed curvature at each node +% +% (x'y'' - y'x'')/(x'^2+y'^2)^(3/2) +% + +assert(size(cgrph.r,1) == 2,'signed curvature only defined in 2D'); +kappa = (cgrph.d(1,:).*cgrph.d2(2,:)- ... + cgrph.d(2,:).*cgrph.d2(1,:))./(sqrt(sum(cgrph.d(:,:).^2,1)).^3); +nch = sum(horzcat(cgrph.echnks.nch)); +kappa = reshape(kappa,cgrph.k,nch); +end \ No newline at end of file diff --git a/chunkie/@chunkgraph/tangents.m b/chunkie/@chunkgraph/tangents.m new file mode 100644 index 0000000..0f6c26a --- /dev/null +++ b/chunkie/@chunkgraph/tangents.m @@ -0,0 +1,24 @@ +function ts = tangents(cgrph) +%TANGENTS return unit tangent vectors along the chunkers in the chunkgraph +% +% Syntax: ts = tangents(cgrph) +% +% Input: +% cgrph - chunkgraph object +% +% Output: +% ts - unit tangent vector along curve +% +% Examples: +% ts = tangents(chnkr); +% + +% author: Travis Askham (askhamwhat@gmail.com) + +d = cgrph.d; + +dd = sqrt(sum(abs(d).^2,1)); +ts = bsxfun(@rdivide,cgrph.d,dd); + +end + diff --git a/devtools/test/axissymkernTest.m b/devtools/test/axissymkernTest.m index 4658df4..35e0041 100644 --- a/devtools/test/axissymkernTest.m +++ b/devtools/test/axissymkernTest.m @@ -10,6 +10,7 @@ cparams.maxchunklen = 0.5; cparams.ta = -pi/2; cparams.tb = pi/2; +cparams.ifclosed = false; start = tic; chnkr = chunkerfunc(@(t) starfish(t,narms,amp),cparams,pref); t1 = toc(start); @@ -75,7 +76,7 @@ submat = K.shifted_eval(srcinfo, targinfo, origin_new); t1 = toc(start); -fprintf('First call to axissymhelm2d.kern time%d\n',t1); +fprintf('First call to axissymhelm2d.kern time: %d\n',t1); srcinfo.r(1,:) = srcinfo.r(1,:) + origin_new(1); diff --git a/devtools/test/chunkermatapplyTest.m b/devtools/test/chunkermatapplyTest.m index bbb2f6e..e32f0db 100644 --- a/devtools/test/chunkermatapplyTest.m +++ b/devtools/test/chunkermatapplyTest.m @@ -140,10 +140,6 @@ cparams.nover = 2; [cgrph] = chunkgraph(verts,edge2verts,fchnks,cparams); -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); - % scalar chunkgraph test fkern = -2*kernel('lap','d'); diff --git a/devtools/test/chunkgrphrcipTest.m b/devtools/test/chunkgrphrcipTest.m index d12372f..c8a7601 100644 --- a/devtools/test/chunkgrphrcipTest.m +++ b/devtools/test/chunkgrphrcipTest.m @@ -63,11 +63,6 @@ % prefs.chsmall = 1d-4; [cgrph] = chunkgraph(verts,edge2verts,fchnks); -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); - - ncurve = 1; @@ -111,11 +106,6 @@ % prefs.chsmall = 1d-4; [cgrph] = chunkgraph(verts,edge2verts,fchnks,prefs); -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); - - zk = 1.0; fkern = @(s,t) -2*chnk.helm2d.kern(zk,s,t,'d'); diff --git a/devtools/test/chunkgrphrcipTransmissionTest.m b/devtools/test/chunkgrphrcipTransmissionTest.m index 5bae51c..8fc60b3 100644 --- a/devtools/test/chunkgrphrcipTransmissionTest.m +++ b/devtools/test/chunkgrphrcipTransmissionTest.m @@ -58,10 +58,6 @@ [cgrph] = chunkgraph(verts,edge2verts,fchnks,cparams); - -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); plot(cgrph); hold on; quiver(cgrph); diff --git a/devtools/test/chunkgrphregionTest.m b/devtools/test/chunkgrphregionTest.m index 480366a..843a82c 100644 --- a/devtools/test/chunkgrphregionTest.m +++ b/devtools/test/chunkgrphregionTest.m @@ -41,56 +41,31 @@ evert = [1.1;0]; verts = [vertc,vertd,vertb,verta,evert]; v2e = [1,-1,0,0;0,1,-1,0;0,0,1,-1;-1,0,0,1]; -edge2verts = zeros(18,size(verts,2)); -edge2verts(1:16,1:16) = kron(eye(4),v2e); -edge2verts(17,11) = 1; -edge2verts(17,17)=-1; -edge2verts(18,12) = 1; -edge2verts(18,17)= -1; -fchnks = []; +edgesendverts = [2, 3, 4, 1, 6, 7, 8, 5, 10, 11, 12, 9, 14, 15, 16, 13, 17, 17, NaN; + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 11, 12, NaN]; +% edgesendverts = [2, 3, 4, 1, 6, 7, 8, 5, 10, 11, 12, 9, 14, 15, 16, 13, 17, 17; +% 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 11, 12]; -[cgrph] = chunkgraph(verts,edge2verts,fchnks); +[~, nedges] = size(edgesendverts); -vstruc = procverts(cgrph); -cgrph = balance(cgrph); +fchnks = cell(nedges,1); +cparams = cell(nedges,1); +for i = 1:nedges + fchnks{i} = []; + cparams{i} = []; +end -% rgns = cgrph.regions; -% rgn1 = rgns{1}; -% rgn2 = rgns{2}; -% -% r2ub = rgn2{1}; -% -% e2 = rgn2{1}{1}(1); -% v2 = find(cgrph.edge2verts(:,abs(e2))==1); -% v2 = verts(:,v2); -% -% irgn = 0; -% for ii=1:numel(rgn1) -% nin = pointinregion(cgrph,rgn1{ii},v2); -% if (nin > 0 && mod(nin,2)==1) -% if (irgn ~= 0) -% display("Warning: an unsupported geometry error has occurred"); -% end -% irgn = ii; -% end -% end -% -% if (irgn == 0) -% -% end -% -% rgnout = rgns{1}; -% if (numel(rgns)>1) -% rgn2 = rgns{2}; -% [rgnout] = mergeregions(cgrph,rgnout,rgn2); -% for ii=3:numel(rgns) -% rgn2 = rgns{ii}; -% [rgnout] = mergeregions(cgrph,rgnout,rgn2); -% end -% end -%%%% [in] = inpolygon(xquery,yquery,xverts,yverts) +if nedges == 19 + narms = 3; + amp = 0.3; + fchnks{19} = @(t) starfish(t,narms,amp, [12;0], 0, 0.3); + cparams{19}.ta = 0; + cparams{19}.tb = 2*pi; +end + +[cgrph] = chunkgraph(verts,edgesendverts,fchnks,cparams); diff --git a/devtools/test/chunkrgrphOpdimTest.m b/devtools/test/chunkrgrphOpdimTest.m index 38911c5..95957d6 100644 --- a/devtools/test/chunkrgrphOpdimTest.m +++ b/devtools/test/chunkrgrphOpdimTest.m @@ -21,15 +21,6 @@ prefs = struct('maxchunklen',0.5); [cgrph] = chunkgraph(verts, edge2verts, fchnks, prefs); -% figure(1); clf; hold on; axis equal; axis off; -% plot(cgrph); -% quiver(cgrph); -% hold off; - -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); - % kerns zk0 = 1; % exterior diff --git a/devtools/test/mixedbcTest.m b/devtools/test/mixedbcTest.m index 1b6249a..666bd30 100644 --- a/devtools/test/mixedbcTest.m +++ b/devtools/test/mixedbcTest.m @@ -32,10 +32,6 @@ cparams.nover = 2; [cgrph] = chunkgraph(verts,edgesendverts,fchnks,cparams); -vstruc = procverts(cgrph); -rgns = findregions(cgrph); -cgrph = balance(cgrph); - % dirichlet and neumann test zk = 30; From 7511883de7cd80b2eb55ce4b750188fa77b21be5 Mon Sep 17 00:00:00 2001 From: Manas Rachh Date: Tue, 27 Aug 2024 10:22:37 -0400 Subject: [PATCH 2/2] adding more chunkgraph routs --- chunkie/@chunkgraph/chunkgraph.m | 64 +++++++--- chunkie/@chunkgraph/datares.m | 113 ++++++++++++++++++ chunkie/@chunkgraph/findregions.m | 2 +- chunkie/@chunkgraph/flagnear.m | 29 +++++ chunkie/@chunkgraph/flagnear_rectangle.m | 32 +++++ chunkie/@chunkgraph/flagnear_rectangle_grid.m | 34 ++++++ chunkie/@chunkgraph/makedatarows.m | 28 +++++ chunkie/@chunkgraph/scatter.m | 26 ++++ 8 files changed, 309 insertions(+), 19 deletions(-) create mode 100644 chunkie/@chunkgraph/datares.m create mode 100644 chunkie/@chunkgraph/flagnear.m create mode 100644 chunkie/@chunkgraph/flagnear_rectangle.m create mode 100644 chunkie/@chunkgraph/flagnear_rectangle_grid.m create mode 100644 chunkie/@chunkgraph/makedatarows.m create mode 100644 chunkie/@chunkgraph/scatter.m diff --git a/chunkie/@chunkgraph/chunkgraph.m b/chunkie/@chunkgraph/chunkgraph.m index a481e97..bba0f0c 100644 --- a/chunkie/@chunkgraph/chunkgraph.m +++ b/chunkie/@chunkgraph/chunkgraph.m @@ -8,11 +8,12 @@ % % chunkgraph properties: % -% verts - 2 x nverts array of vertex locations -% edgesendverts - 2 x nedges array of starting and ending vertices for -% each edge -% echnks - nedge x 1 array of chunker objects discretizing each edge curve -% regions - nregions x 1 cell array specifying region information for the +% verts - 2 x nverts array of vertex locations +% edgesendverts - 2 x nedges array of starting and ending vertices for +% each edge. edgesendverts(:,i) should be NaNs for closed loops, +% and a corresponding function handle must be provided +% echnks - nedge x 1 array of chunker objects discretizing each edge curve +% regions - nregions x 1 cell array specifying region information for the % given graph structure. A region is a connected subset of R^2 % specified by its bounding edges. If the jth region is simply % connected then abs(regions{j}{1}) is the list of edges which @@ -20,20 +21,40 @@ % the direction of traversal for that edge. The edges are ordered % according to an orientation based on nesting. The boundary of the % outermost (unbounded) region is traversed clockwise. -% vstruc - nverts x 1 cell array. vstruc{j}{1} gives a list of edges which +% vstruc - nverts x 1 cell array. vstruc{j}{1} gives a list of edges which % are incident to a vertex. vstruc{j}{2} is a list of the same length % consisting of +1 and -1. If +1 then the corresponding edge ends at % the vertex, if -1 it begins at the vertex. -% v2emat - sparse nedge x nverts matrix, akin to a connectivity matrix. +% v2emat - sparse nedge x nverts matrix, akin to a connectivity matrix. % the entry v2emat(i,j) is 1 if edge i ends at vertex j, it is -1 if % edge i starts at vertex j, and it is 2 if edge i starts and ends at % vertex j. +% k - integer, number of Legendre nodes on each chunk +% dim - integer, dimension of the ambient space in which the curve is +% embedded +% In the rest, nch = \sum_{j} chunkgraph.echnks(j).nch; +% npt - returns k*nch, the total number of points on the curve +% r - dim x k x nch array, r(:,i,j) gives the coordinates of the ith +% node on the jth chunk of the chunkgraph +% d - dim x k x nch array, d(:,i,j) gives the time derivative of the +% coordinate at the ith node on the jth chunk of the chunkgraph +% d2 - dim x k x nch array, d(:,i,j) gives the 2nd time derivative of the +% coordinate at the ith node on the jth chunk of the chunkgraph +% n - dim x k x nch array of normals to the curve +% data - datadim x k x nch array of data attached to chunkgraph points +% this data will be refined along with the chunkgraph +% adj - 2 x nch integer array. adj(1,j) is i.d. of the chunk that +% precedes chunk j in parameter space. adj(2,j) is the i.d. of the +% chunk which follows. If adj(i,j) is 0 then that end of the chunk +% is a free end. if adj(i,j) is negative than that end of the chunk +% meets with other chunk ends in a vertex. % % chunkgraph methods: % plot(obj, varargin) - plot the chunkgraph % quiver(obj, varargin) - quiver plot of chunkgraph points and normals % plot_regions(obj, iflabel) - plot the chunkgraph with region and % and edge labels +% scatter(obj,varargin) - scatter plot of the chunkgraph nodes % obj = refine(obj,varargin) - refine the curve % wts = weights(obj) - scaled integration weights on curve % rn = normals(obj) - recompute normal vectors @@ -47,12 +68,11 @@ % the chunkgraph % tau = tangents(obj) - unit tangents to curve % kappa = signed_curvature(obj) - get signed curvature along curve +% obj = makedatarows(obj,nrows) - add nrows rows to the data storage. +% rflag = datares(obj,opts) - check if data in data rows is resolved % % To add: -% scatter -% make data rows -% datares -% +% flagnear % % Syntax: % @@ -220,6 +240,13 @@ end % set cploc.ifclosed in a way that makes sense cploc.ifclosed = false; + i1 = edgesendverts(1,i); + i2 = edgesendverts(2,i); + + if isnan(i1) || isnan(i2) + cploc.ifclosed = true; + end + % chunkgraph edges need at least 4 chunks if isfield(cploc,'nchmin') cploc.nchmin = max(4,cploc.nchmin); @@ -239,10 +266,8 @@ cploc.tb = tb; end vs =fchnks{i}([ta,tb]); - chnkr = chunkerfunc(fchnks{i},cploc,pref); + chnkr = chunkerfunc(fchnks{i}, cploc, pref); chnkr = sort(chnkr); - i1 = edgesendverts(1,i); - i2 = edgesendverts(2,i); if ~isnan(i1) && ~isnan(i2) if i1 ~= i2 vfin0 = verts(:,i1); @@ -364,13 +389,13 @@ % defined in other files spmat = build_v2emat(obj) - obj = refine(obj,opts) + obj = refine(obj, opts) obj = balance(obj) - obj = move(obj,r0,r1,trotat,scale) + obj = move(obj, r0, r1, trotat, scale) rmin = min(obj) rmax = max(obj) - plot(obj,varargin) - quiver(obj,varargin) + plot(obj, varargin) + quiver(obj, varargin) plot_regions(obj, iflabel) wts = weights(obj) rnorm = normals(obj) @@ -378,6 +403,9 @@ rnormonesmat = normonesmat(obj) tau = tangents(obj) kappa = signed_curvature(obj) + obj = makedatarows(obj, nrows) + scatter(obj, varargin) + rres = datares(obj, opts) end diff --git a/chunkie/@chunkgraph/datares.m b/chunkie/@chunkgraph/datares.m new file mode 100644 index 0000000..fcadb61 --- /dev/null +++ b/chunkie/@chunkgraph/datares.m @@ -0,0 +1,113 @@ +function [res_flag] = datares(obj,opts) +%DATARES check if the data in the specified data rows are resolved +% By default, the data in a row on a chunk are resolved if the +% 1-norm of the last chnkr.k/2 coefficients of the Legendre coefficients +% for that data row is less than the tolerance (1e-6). +% +% Let c(i,j) denote the jth Legendre coefficient of the idata(i) data +% row on chunk l. Then, setting v(i) = \|c(i,chnkr.k/2+1:end)\|_1 +% we have +% +% res_flag(i,l) = v(i) < 1e-6 +% +% Variants of most of these options are available. +% +% Syntax: res_flag = datares(chnkr,opts) +% +% Input: +% obj - chunkgraph object +% opts - options data structure. +% opts.idata - the data rows to check resolution on +% (default all rows, i.e. 1:chunkgraph.datadim) +% opts.ncoeff = number of final coeffs to take the norm of +% opts.pleg = integer or Inf indicating what norm to apply to +% the Legendre coefficients (default 1) +% opts.tol = tolerance (default 1e-6) +% opts.pscale = integer, scale tolerance by +% 1/(length of chunk)^pscale for each chunk +% (default 0) +% opts.rel = boolean, scale the tolerance by same norm applied to +% the other coefficients, i.e. the first k-ncoeff (false) +% Output: +% res_flag(i,l) - for each chunk l and data row idata(i) is true if +% resolved, false otherwise +% +% Examples: +% opts = []; opts.idata = 2:3; % checks resolution of 2nd and 3rd data +% % rows +% res_flag = datares(chunkgraph, opts); +% +% see also REFINE + +% author: Travis Askham (askhamwhat@gmail.com) + +chnkrtotal = merge(obj.echnks); +lens = chunklen(chnkrtotal); + +idata = 1:obj.datadim; +ncoeff = floor((obj.k+0.1)/2); +pleg = 1; +tol = 1e-6; +pscale = 0; +rel = false; + +if nargin < 2 + opts = []; +end + +if isfield(opts,'idata') + idata = opts.idata; +end +if isfield(opts,'ncoeff') + ncoeff = opts.ncoeff; +end +if isfield(opts,'pleg') + pleg = opts.pleg; +end +if isfield(opts,'tol') + tol = opts.tol; +end +if isfield(opts,'pscale') + pscale = opts.pscale; +end +if isfield(opts,'rel') + rel = opts.rel; +end + +nch = chnkrtotal.nch; +k = obj.k; + +[~,~,u] = lege.exps(k); + +data = obj.data(idata,:,:); +icoeff1 = (k-ncoeff+1):k; +icoeff2 = 1:(k-ncoeff); + +res_flag = false(length(idata),nch); + +if ~rel + u1 = u(icoeff1,:); + + for i=1:nch + datai = data(:,:,i); + cf1 = u1*(datai.'); + cf1n = vecnorm(cf1,pleg,1); cf1n = cf1n(:); + + res_flag(:,i) = cf1n*lens(i)^pscale < tol; + end +else + u1 = u(icoeff1,:); + u2 = u(icoeff2,:); + + for i=1:nch + datai = data(:,:,i); + cf1 = u1*(datai.'); + cf2 = u2*(datai.'); + cf1n = vecnorm(cf1,pleg,1); cf1n = cf1n(:); + cf2n = vecnorm(cf2,pleg,1); cf2n = cf2n(:); + + res_flag(:,i) = cf1n*lens(i)^pscale < tol*cf2n; + end + +end + diff --git a/chunkie/@chunkgraph/findregions.m b/chunkie/@chunkgraph/findregions.m index fe93c8f..3f86225 100644 --- a/chunkie/@chunkgraph/findregions.m +++ b/chunkie/@chunkgraph/findregions.m @@ -2,7 +2,7 @@ %FINDREGIONS determins the regions of a chunkgraph. This routine handles % the situations involving nested chunkers inside the chunkgraph % -% Syntax: [regions] = findregions(obj, iverts); +% Syntax: [regions] = findregions(obj_in, iverts); % % Input: % obj_in - a chunkgraph object diff --git a/chunkie/@chunkgraph/flagnear.m b/chunkie/@chunkgraph/flagnear.m new file mode 100644 index 0000000..910f4b5 --- /dev/null +++ b/chunkie/@chunkgraph/flagnear.m @@ -0,0 +1,29 @@ +function flag = flagnear(obj,pts,opts) +%FLAGNEAR flag points which are within a chunklength (or given factor of +% a chunklength) of any point on each chunk. on return is a sparse +% logical array. If the (i,j) entry is non zero then pts(:,i) is close +% to chunk j in chunkgraph. +% +% Syntax: flag = flagnear(obj,pts,opts) +% +% Input: +% obj - chunkgraph object describing curve +% pts - (obj.dim,nt) array of point coordinates +% +% Optional input: +% opts - options structure +% opts.fac = factor of chunklength to check distance against (1.0) +% +% Output: +% flag - (nt,nch) sparse array. a non zero entry (i,j) means +% that the distance from pts(:,i) to at least one node on +% chunk j is less than opts.fac*length of chunk j. +% where nch is thte total number of chunks int he chunkgraph +% + +% author: Travis Askham (askhawhat@gmail.com) + +chnkrtotal = merge(obj.echnks); +flag = chnkrtotal.flagnear(pts, opts); + +end \ No newline at end of file diff --git a/chunkie/@chunkgraph/flagnear_rectangle.m b/chunkie/@chunkgraph/flagnear_rectangle.m new file mode 100644 index 0000000..707d93c --- /dev/null +++ b/chunkie/@chunkgraph/flagnear_rectangle.m @@ -0,0 +1,32 @@ +function flag = flagnear_rectangle(obj,pts,opts) +%FLAGNEAR_RECTANGLE flag points which require special quadrature +% (or given factor of a chunklength) of any point on each chunk. +% On return is a sparse +% logical array. If the (i,j) entry is non zero then pts(:,i) is close +% to chunk j in chnkr. +% +% Syntax: flag = flagnear(obj,pts,opts) +% +% Input: +% obj - chunkgraph object describing curve +% pts - (obj.dim,nt) array of point coordinates +% +% Optional input: +% opts - options structure +% opts.rho = Bernstein ellipse parameter (default=1.8) +% +% Output: +% flag - (nt,nch) sparse array. a non zero entry (i,j) means +% that the distance from pts(:,i) to at least one node on +% chunk j is less than opts.fac*length of chunk j. +% +% Here nch is the total number of chunks in the chunkgraph +% + + +% author: Travis Askham (askhawhat@gmail.com) + +chnkrtotal = merge(obj.echnks); +flag = chnkrtotal.flagnear_rectangle(pts, opts); + +end diff --git a/chunkie/@chunkgraph/flagnear_rectangle_grid.m b/chunkie/@chunkgraph/flagnear_rectangle_grid.m new file mode 100644 index 0000000..e460d66 --- /dev/null +++ b/chunkie/@chunkgraph/flagnear_rectangle_grid.m @@ -0,0 +1,34 @@ +function flag = flagnear_rectangle_grid(obj,x,y,opts) +%FLAGNEAR_RECTANGLE_GRID flag points which require special quadrature +% (or given factor of a chunklength) of any point on each chunk. +% On return is a sparse logical array. If the (i,j) entry is non zero +% then pts(:,i) is close to chunk j in chnkr. +% +% Syntax: flag = flagnear(obj,pts,opts) +% +% Input: +% obj - chunkgraph object describing curve +% x - nx array of x coordinates for tensor product grid +% y - ny array of y coordinates for tensor product grid +% +% Grid points are interpreted in the order returned by +% MATLAB's meshgrid function [xx,yy] = meshgrid(x,y). +% +% Optional input: +% opts - options structure +% opts.rho = Bernstein ellipse parameter (default=1.8) +% +% Output: +% flag - (nx*ny, nch) sparse array. a non zero entry (i,j) means +% that the distance from pts(:,i) to at least one node on +% chunk j is less than opts.fac*length of chunk j. +% +% Here nch is the total number of chunks on the chunkgraph +% + +% author: Travis Askham (askhawhat@gmail.com) + +chnkrtotal = merge(obj.echnks); +flag = chnkrtotal.flagnear_rectangle_grid(x, y, opts); + +end \ No newline at end of file diff --git a/chunkie/@chunkgraph/makedatarows.m b/chunkie/@chunkgraph/makedatarows.m new file mode 100644 index 0000000..761df43 --- /dev/null +++ b/chunkie/@chunkgraph/makedatarows.m @@ -0,0 +1,28 @@ +function obj = makedatarows(obj,nrows) +%MAKEDATAROWS add new data rows to chunkgraph object +% +% +% Syntax: obj = makedatarow(obj, nrows); +% +% Input: +% obj - a chunkgraph object +% nrows - number of rows to be added +% +% Output: +% obj - output chunkgraph object with additional data rows + +% +% + if (nrows > 0) + datatemp = obj.data; + datadimold = obj.datadim; + nch = sum(horzcat(obj.echnks.nch)); + obj.data = zeros(datadimold+nrows,obj.k,nch); + obj.data(1:datadimold,:) = datatemp(:,:); + obj.hasdata = true; + else + if (nrows < 0) + warning('attempted to add negative rows, doing nothing'); + end + end +end diff --git a/chunkie/@chunkgraph/scatter.m b/chunkie/@chunkgraph/scatter.m new file mode 100644 index 0000000..28d57c0 --- /dev/null +++ b/chunkie/@chunkgraph/scatter.m @@ -0,0 +1,26 @@ +function scatter(obj,varargin) +%SCATTER scatter plot of the coordinates of the chunkgraph object. +% Must be a 2D chunkgraph. Faster than plot --> no sorting required +% Uses standard scatter commands +% +% Syntax: scatter(obj,varargin) +% +% Input: +% obj - chunkgraph object +% varargin - any of the scatter commands +% +% Output: +% none +% +% Examples: +% scatter(obj,'ro') % scatter plot of chunkgraph points as red circles +% +% see also PLOT + +% author: Travis Askham (askhamwhat@gmail.com) + +assert(obj.dim == 2,'for scatter plot must be 2D chunkgraph'); +xs = obj.r(1,:,:); xs = xs(:); +ys = obj.r(2,:,:); ys = ys(:); + +scatter(xs,ys,varargin{:}); \ No newline at end of file