How can I assign geometry using descg for a MATLAB PDE - matlab

I'm trying to create the geometry for a PDE, axisymmetric so I only need 1/2 of the geometry I'm creating. However, when I try to assign this geometry using descg( gd, ns, sf), I'm told
Error using decsg (line 1250)
Incorrect use of '=' operator. Assign a value to a variable using '=' and compare
values for equality using '=='.
Error in root_geom_V1 (line 25)
dl = decsg(gd,sf,ns);
This is baffling me. I've pulled from the following example and tried to follow it exactly, then ran some other more detailed code, also using descg and it worked perfectly. It just doesn't want to play here?
https://uk.mathworks.com/help/pde/ug/create-geometry-at-the-command-line.html
model = createpde(1);
% First rectangle, containing modelled parts
R1 = [3;4;0;1;1;0;-1;-1;0;0];
% Second rectangle for substraction
R2 = [3;4;0;-1;-1;0;-1;-1;0;0];
% First circle (outer root circumference)
C1 = [1;0;-0.5;0.5];
% Make contain same row of columns
C1 = [C1;zeros(length(R1) - length(C1),1)];
% Second circle (Inner root)
C2 = [1;0;-0.5;0.3];
% Make contain same row of columns
C2 = [C2;zeros(length(R1) - length(C2),1)];
% Combine into geom
gd = [R1,C1,C2,R2];
ns = char('R1', 'C1', 'C2', 'R2')';
ns = ns';
sf = 'R1+C1+C2-R2';
dl = decsg(gd,sf,ns);
geometryFromEdges(model, dl);
figure(1)
pdegplot(model,'EdgeLabels','on','FaceLabels','on')
If anyone could help illuminate me I'd be very grateful, I'm normally an R user so a tad out of the usual wheelhouse. Just why doesn't the flippin geometry assign using the = sign? Thank you!

Related

Exporting face-vertex mesh to STL

I'm trying to add thickness to a gyroid mesh and export this to STL. I can successfully plot the thickened gyroid mesh as shown below, but this is because I wrote a function to remove undesirable faces, namely, faces which have edges longer than a certain limit. I should also mention that all faces are triangular, so both the vertices and faces matrices are in N x 3 form.
Here's the code which checks for edge lengths and removes those which are too_long:
function [F] = remove_bad_faces(F,V,too_long)
%% Initiate various counters/storage matrices
bad_face_count = 0; % Number of bad faces
bad_faces = []; % Matrix of bad faces
bad_vertices = []; % Matrix of bad vertices
bad_face_indexes = []; % Matrix of bad face row indices. I know that the plural of index is not indexes.
%% Find all bad faces
for i=1:size(F,1)
face = F(i,:);
v1 = V(face(1),:);
v2 = V(face(2),:);
v3 = V(face(3),:);
if norm(v1-v2) >= too_long || norm(v2-v3) >= too_long || norm(v1-v3) >= too_long
bad_face_count = bad_face_count + 1;
bad_faces = [bad_faces; face];
bad_vertices = [bad_vertices;v1;v2;v3];
bad_face_indexes = [bad_face_indexes,i];
end
end
%% Remove bad faces
for j=1:size(bad_face_indexes,2)
index = bad_face_indexes(j);
F(index,:) = nan;
end
end
As you can see, I'm replacing "bad faces" (i.e. rows of the F matrix) with NaN, but this only works for visualisation. When I try to pass the resultant faces and vertices to an STL generating function (see here), I get the following error:
Index in position 2 is invalid. Array indices must be positive integers or logical values.
Error in stlwrite (line 76)
facets = reshape(facets(:,faces'), 3, 3, []);
Error in Gyroid_Mesh_Script (line 60)
stlwrite('gyroid_test.stl', F, V)
So clearly the NaN is the problem, and I've tried swapping it with [] and 0, but neither has worked. Any help is much appreciated, thanks in advance!
Edit:
When I use [] instead of NaN, I can export to STL, but it includes these "bad faces", shown below (zoomed-in view):
Thanks to #benJephunneh's response! That fixed everything. I'm posting the updated function which removes faces whose edges are too_long:
function [F] = remove_bad_faces(F,V,too_long)
%% Initiate various counters/storage matrices
bad_faces = []; % Matrix of bad faces
bad_vertices = []; % Matrix of bad vertices
bad_face_indexes = []; % Matrix of bad face row indices. I know that the plural of index is not indexes.
%% Find all bad faces
for i=1:size(F,1)
face = F(i,:);
v1 = V(face(1),:);
v2 = V(face(2),:);
v3 = V(face(3),:);
if norm(v1-v2) >= too_long || norm(v2-v3) >= too_long || norm(v1-v3) >= too_long
bad_faces = [bad_faces; face];
bad_vertices = [bad_vertices;v1;v2;v3];
bad_face_indexes = [bad_face_indexes,i];
end
end
bad_face_count = numel(bad_face_indexes);
%% Remove bad faces
F(bad_face_indexes,:) = [];
end
It also successfully exports to STL using stlwrite('gyroid_test.stl', F, V)

Loop function in Matlab Programming

I am trying to make a loop as below description in Matlab programming.
It likes two trees exploration.
Problem1:
I create a function with two input variables and output with four vars.
From originCoord(x,y,z) it creates two new coordinates R(x,y,z), L(x,y,z); (R means Right, L: left)
next R(x,y,z) -> new R1(x1,y1,z1) & L1(x1,y1,z1)
and L(x,y,z) -> new L2(x2,y2,z2) & R2(x2,y2,z2)
then to be continued
.....
loop will stop when one of the newCcoordinates() == targetCoordinates(xtarget, ytarget).
%from initial 3D point (x y z) using treeExploreation fuction to create two
%new3D points with coordinates (x1,y1,z1) and (x2,y2,z2)
%then from these new point, using this function two create new four 3D_Points...
%x y z are scala
rightPoint = [x1,y1,z1];
leftPoint = [x2,y2,z2];
targetPoint = [xtarget, ytarget, ztarget];
%store twop 3D points into coordExplore
coordExplore = [rightPoint,leftPoint];
temp = [];
flag = 0;
while (~flag)
for i=1:length(coordExplore)
[newrightPoint,newleftPoint]=treeExploration(coordExplore(i)); %help me at here !!!!
%this function with input (x,y,z) output two new coordinates i.e.
% newrightPoint(x3,y3,z3) and newleftPoint(x4,y4,z4)
if (newrightPoint==targetPoint) || (newleftPoint==targetPoint)
%this condition is to compare the output coordinates whether the same as
%the targetPoint
flag=1;
break;
else
temp =[newrightPoint,newleftPoint];
end
end
coordExplore = temp;
temp = [];
end
I got stuck when the output always greater than input. I cannot use all the output for the next loop.
Please help me to comment on how to make a loop for this case. Thanks.
Updated problems:
*I wish coordExplore(1) = rightPoint (x1 y1 z1)
and coordExplore(2) = leftPoint (x2 y2 z2)
BUT with index i=1, coordExplore(1) = x1; i=2 -> coordExplore(2) = y1;
I use the loop with coordExplore(i) in order to work from point-to-point within each point has its own coordinates(x y z). How can I do that?*
Problem2:
when one of the newCcoordinates() == targetCoordinates(xtarget, ytarget), how can I know which varibales in which direction from origin loop to last loop generating the result? (like which brands of the tree achieving the target).
In C++, I can use stack to save but in Matlab I do not know how can I save the variable for each loop.
Problem 1:
If I have understood what you want to achieve correctly, something like this should do the job.
reached_target = False;
coord = [x, y];
while ~reached_target
number_of_nodes = size(coord, 1)
new_coord = zeros(2*number_of_nodes)
for ii = 1:number_of_nodes
new_coord(ii*2-1, :) = doRightRunning(coord(ii, 1);
new_coord(ii*2, :) = doLeftRunning(coord(ii, 2);
end
target_ind = new_coord(:, 1) == x_target && new_coord(:, 2) == y_target;
if any(target_ind)
reached_target = True;
disp(find(target_ind));
end
end
However, the code you've shown doesn't match your explanations, so it's not clear if the next layer of the tree is 2 times or 4 times the size of the previous layer.
The code here basically calculates all the left and right runs for the current coordinates until the target is reached.
I haven't tested it yet, so look for bugs.
Problem 2:
It is not necessary to save the trail for knowing the turns it has made to reach the target. When a matching coordinate is found, its place in the list of coordinates reveal its trail. All you need to do is convert its index to binary and interpret 0 as right turn and 1 as left turn (since in the code, the right turn is placed on top, and the left turn on the bottom).
Example: Let's say we are in the 3rd layer of the tree with 8 coordinates and let's say the 6th coordinate matches the target. So starting from index 0, we have found a match at index which is 101 in binary format. It reveals that the turns to reach this coordinate are Left-Right-Left.

Matlab Plotting with Labels

I'm trying to plot a knn result from my data, which has 3 columns: x, y , label. There are 3 classes and for each of them I would like to used a different symbol. Here's the way I'm plotting now:
t1 = data(:,3) == 1;
t2 = data(:,3) == 2;
t3 = data(:,3) == 3;
train1 = data(t1,:);
train2 = data(t2,:);
train3 = data(t3,:);
figure(1);
plot(train1(:,1),train1(:,2),'#',train2(:,1),train2(:,2),'*',train3(:,1),train3(:,2),'o');
I want to know if there's a more concise way of doing this. Thanks
Here's the most concise (and working) way to plot your data:
figure(1);
hold all
plot(train1(:,1),train1(:,2),'o')
plot(train2(:,1),train2(:,2),'x')
plot(train3(:,1),train3(:,2),'s')
Here's an example that does what you want in a robust and modular manner. You can easily add classes or modify the figure output.
data = [0.53,0.17,2;0.78,0.60,3;0.93,0.26,1;0.13,0.65,2;0.57,0.69,1;...
0.47,0.75,3;0.010,0.45,1;0.34,0.080,3;0.16,0.23,3;0.79,0.91,3;...
0.31,0.15,1;0.53,0.83,2];
categories = [1,2,3];
symbols = {'s','<','o','d','v','+','x','*'};
figure;
hold all
for loopj = 1:length(categories)
t = data(:,3) == categories(loopj);
train = data(t,:);
label = strcat('Class ',num2str(categories(loopj)));
plot(train(:,1),train(:,2),symbols{loopj},'DisplayName',label,'LineWidth',1.3)
end
lg = legend('show');
lg.Location = 'best';
Use hold all to write on the figure without erasing the previous axi and let Matlab pick line colors.
In any case, you need to manually define the different symbols and each plot command comes with one unique type of line and markers.

How do I get the Matlab data point labels correct?

I've created some Matlab code which anyone helping can run and see the problem.
When I run the following code, for each data point on my plot I seem to get all 15 labels instead of only 1 specific label.
So how do I get the Matlab data point labels correct for the following code?
Based on the the suggestions, I did the following:
I replaced these two lines of code:
labels = num2str(test_vector_label,'F%d');
labels_cell = cellstr(labels);
With this line of code as suggested:
labels_cell = strread(num2str(test_vector_label),'%s');
Now there are two follow-up questions:
1) A warning appears stating that I should use textscan instead of strread:
labels_cell = textscan(num2str(test_vector_label),'%s');
Then when I use textscan as in the above line of code above, I get an error?
"Error using text
Cell array of strings may only contain string and numeric
matrices"
"Error in Code_Test (line 46)
text(x_val,y_val,labels_cell,'horizontal','left',
'vertical','bottom')"
2) How do I put a letter in front of the number labels? For example, in the original code I had put letter F followed by a number?
%--------------Randomly select training and testing data.-----------
num_data = 35;
data_idx = 1:35;
train_data_idx_tmp = randsample(num_data,20)
train_dataRand_idx = sort(train_data_idx_tmp)
% Lia = ismember(A,B) returns an array the same size as A, containing 1 (true)
% where the elements of A are found in B, and 0 (false) elsewhere.
test_data_idx_tmp = ismember(data_idx,train_dataRand_idx)
test_dataRand_idx = data_idx(~test_data_idx_tmp)'
% Check to see if training and test data index are exclusive.
check_train_test_idx = ismember(train_dataRand_idx,test_dataRand_idx)
%--------------------------------------------------------------------------
% Testing stage.
test_vector = test_dataRand_idx; %Select randomly obtained testing data.
% Training stage.
train_vector = train_dataRand_idx; %Select randomly obtained training
x_val = [1:15];
y_val = 2*[1:15];
plot(x_val,y_val,'or','MarkerFaceColor','r')
grid on
%Put specific data point labels on plots.
test_vector_label = test_vector';
labels = num2str(test_vector_label,'F%d');
labels_cell = cellstr(labels);
text(x_val,y_val,labels_cell,'horizontal','left', 'vertical','bottom')
Your variable labels_cell is a 1x1 string cell not an array of strings. Replace
labels = num2str(test_vector_label,'F%d');
labels_cell = cellstr(labels);
with
labels_cell = strread(num2str(test_vector_label),'%s');

Using a colon for indexing in matrices of unknown dimensions

When indexing matrices in MATLAB, can I specify only the first or last n dimensions, and have all others dimensions "selected automatically"?
For example, I am writing a function which takes in an image, and displays it with imshow, which can either display a 3-D color image (e.g 1024×768×3) or a 2-D monochrome array (e.g 1024x768).
My function does not care about how many color channels the image has, imshow will take care of that. All I want to do is pass parameters to select a single region:
imshow(frame(x1:x2, y1:y2, :))
What do I put in place of the last colon to say "include all the others dimensions"?
You can use comma-separated-list expansion together with the ':' indexing.
Suppose your input is:
A = rand([7,4,2,3]);
To retrieve only first 2:
cln = {':', ':'};
A(cln{:})
To retrieve the last 3:
cln = {1, ':', ':', ':'};
A(cln{:})
Which can be generalized with:
sten = 2:3; % Which dims to retrieve
cln(1:ndims(A)) = {1};
cln(sten) = {':'};
A(cln{:})
Following from Oleg's answer, here is a function that will work if you are selecting from several of the first dimensions. If other dimensions are needed, I think you can see how to modify.
function [dat] = getblock2(dat, varargin)
%[dat] = getblock(dat, varargin) select subarray and retain all others
% unchanged
%dat2 = getblock(dat, [1,2], [3,5]) is equivalent to
% dat2 = dat(1:2, 3:5, :, :, :) etc.
%Peter Burns 4 June 2013
arg1(1:ndims(dat)) = {':,'};
v = cell2mat(varargin);
nv = length(v)/2;
v = reshape(v,2,nv)';
for ii=1:nv
arg1{ii} = [num2str(v(ii,1)),':',num2str(v(ii,2)),','];
end
arg2 = cell2mat(arg1);
arg2 = ['dat(',arg2(1:end-1),')'];
dat = eval(arg2);