PDE Toolbox: Parametrize geometry function

6 visualizaciones (últimos 30 días)
Johannes
Johannes el 25 de Oct. de 2017
Comentada: Johannes el 26 de Oct. de 2017
I aim to generate geometries in a programmatic way to explore the influence of geometry shape on a PDE solution. I generate the geometry with a geometry function as outlined here: Create geometry using a geometry function . In order to specify the geometry, I would like to pass certain parameters to the function before creating the geometry. I tried using a function handle but could not get it to work. Currently I use a workaround with a global variable but would very much like to avoid this.
Here a minimal example:
>> para = rand(1,20); %random numbers as parameters
>> fun = @(bs,s)GetPolygon2(bs,s,para); %creating function handle
>> class(fun)
ans =
'function_handle'
>> pdegplot(@fun,'EdgeLabels','on')
Error: "fun" was previously used as a variable, conflicting with its use here as the name of a function or command.
See "How MATLAB Recognizes Command Syntax" in the MATLAB documentation for details.
>> pdegplot('fun','EdgeLabels','on')
Undefined function or variable 'fun'.
Error in pdeigeom (line 39)
x=dl();
Error in pdegplot>plotTwoDGeometry (line 99)
nbs=pdeigeom(g);
Error in pdegplot (line 87)
hh = plotTwoDGeometry(g, plotVertexLabels, plotEdgeLabels, plotSubLabels);
The function pdegplot works fine when I remove the additional input argument "para" from the function GetPolygon2 and use the workaround of a global variable:
>> pdegplot(@GetPolygon2,'EdgeLabels','on')
In case anybody knows a way to pass additional parameters to a geometry function that would be great. Thank you!

Respuesta aceptada

Alan Weiss
Alan Weiss el 25 de Oct. de 2017
Strangely enough, someone else asked a question about this subject at about the same time. There, this pointer gave an answer. You could also look here for a slightly different explanation of the same material.
Alan Weiss
MATLAB mathematical toolbox documentation
  3 comentarios
Alan Weiss
Alan Weiss el 25 de Oct. de 2017
Johannes, it seems to me that the anonymous function approach might be failing because the geometry function passes zero, one, or two arguments, and the function handle fun insists on having two arguments.
I suspect that you will have better luck with nested functions for passing parameters. Here is an example that I cobbled together for someone else a while back. The next paragraph is my reply to that person, which may be of interest:
This is a problem that can be addressed with global variables (yuck!), or, more subtly, with nested functions. I am including a function that has a geometry with an ellipse inside whose axes are given by variables you pass in, rr and ss. Try rr = 0.5, ss = 0.25. You see that the outer function called makegeometry1(rr,ss) has a nested geometry function called cardg4, which is a minor variant of the doc example geometry function cardg3 http://www.mathworks.com/help/pde/ug/create-geometry-using-a-geometry-function.html I didn't put any error checking, so don't use rr and ss parameters larger than about 1 or you can get an invalid geometry!
I hope this helps,
Alan
The function:
function makegeometry1(rr,ss)
model = createpde();
geometryFromEdges(model,@cardg4);
pdegplot(model,'EdgeLabels','on','SubdomainLabels','on')
axis equal
applyBoundaryCondition(model,'Edge',1:4,'u',0);
applyBoundaryCondition(model,'Edge',6:9,'g',1,'q',1);
generateMesh(model,'Hmax',0.1);
u = assempde(model,1,0,3);
figure
pdeplot(model,'xydata',u)
axis equal
function [x,y] = cardg4(bs,s)
% CARDG4 Geometry File defining the geometry of a cardioid with two % subregions and an elliptical hole.
if nargin == 0
x = 9; % 9 segments
return
end
if nargin == 1
% Outer cardioid
dl = [ 0 4 8 12
4 8 12 16
1 1 2 2 % Region 1 to the left in the upper half, 2 in the lower
0 0 0 0];
% Dividing line between top and bottom
dl2 = [0
4
1 % Region 1 to the left
2]; % Region 2 to the right
% Inner circular hole
dl3 = [ 0 pi/2 pi 3*pi/2
pi/2 pi 3*pi/2 2*pi
0 0 0 0 % To the left is empty
2 2 2 2]; % To the right is region 2
% Combine the three edge matrices
dl = [dl,dl2,dl3];
x = dl(:,bs);
return
end
x = zeros(size(s));
y = zeros(size(s));
if numel(bs) == 1 % Does bs need scalar expansion?
bs = bs*ones(size(s)); % Expand bs
end
cbs = find(bs < 3); % Upper half of cardiod
x(cbs) = s(cbs).^4/512 - 3*s(cbs).^2/16 + 4;
y(cbs) = s(cbs).*(64 - s(cbs).^2).^(3/2)/512; cbs = find(bs >= 3 & bs <= 4); % Lower half of cardioid
s(cbs) = 16 - s(cbs);
x(cbs) = s(cbs).^4/512 - 3*s(cbs).^2/16 + 4;
y(cbs) = -s(cbs).*(64 - s(cbs).^2).^(3/2)/512; cbs = find(bs == 5); % Index of straight line
x(cbs) = s(cbs);
y(cbs) = zeros(size(cbs));
cbs = find(bs > 5); % Inner ellipse center (1,-1) axes rr and ss
x(cbs) = 1 + rr*cos(s(cbs));
y(cbs) = -1 + ss*sin(s(cbs));
end
end
Johannes
Johannes el 26 de Oct. de 2017
Alan, thank you for your help. I got my code to work using a nested function as you suggested.
In principal I prefer to use a function handle and have the function to which I want to pass parameters in a separate m-file. I guess I might have to use the same nested function a second time in a separate file.

Iniciar sesión para comentar.

Más respuestas (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by