How to integrate over a triangle in MATLAB? - matlab

let's consider a two dimensional fonction f(x,y)
and tree points A,B,C with ABC a triangle
and i want to integrate the function f over the triangle ABC,
is there a way to do that in matlab?
thank you.

You can create a new function h(x,y), that returns f(x,y) if (x,y) is inside the polygon, and 0 otherwise.
For instance:
A = [0, 0];
B = [0, 5];
C = [5, 0];
triangleX = [A(1) B(1) C(1)];
triangleY = [A(2) B(2) C(2)];
f = #(x,y) (1);
h = #(x,y) (inpolygon(x, y, triangleX, triangleY) .* f(x,y));
q = integral2(h, min(triangleX), max(triangleX), min(triangleY), max(triangleY)
'Method', 'iterated')
Outputs (which may be close enough for you):
q =
12.500070877352647
And another function:
f = #(x,y) (x .* y);
q = integral2(#foo, min(triangleX), max(triangleX), min(triangleY), max(triangleY),
'Method', 'iterated')
q =
26.042038561947592
Notice that the integral2 documentation states:
When integrating over nonrectangular regions, the best performance and
accuracy occurs when ymin, ymax, (or both) are function handles. Avoid
setting integrand function values to zero to integrate over a
nonrectangular region. If you must do this, specify 'iterated' method.
So it'll be better if instead of using the above solution, you write two functions that given an x coordinate, give you the minimal and maximal y coordinates of the polygon (triangle).

I found the correct answer,
thanks to this https://math.stackexchange.com/questions/954409/double-integral-over-an-arbitrary-triangle
function r = intm2(f, t)
% f: function
% t: three points of a triangle
% r: integration of f over t
a = t(1,:);
b = t(2,:);
c = t(3,:);
jg = abs((b(1)-a(1))*(c(2)-a(2))-(c(1)-a(1))*(b(2)-a(2)));
ftilda = #(u,v) f(a(1)+u*(b(1)-a(1))+v*(c(1)-a(1)), a(2)+u*(b(2)-a(2))+v*(c(2)- a(2)));
fy = #(x) 1-x;
r = jg * integral2(ftilda, 0,1, 0,fy);
end

Related

How to plot and define with Matlab a function defined on different subintervals, which enters an ODE

I am trying to plot and then to use it with Matlab
in an ODE as coefficient, the function
f : [2,500] -> [0,1],
But I don't know how to write the code for the definition of the function, since it is given on different subintervals.
Below is an example that uses anonymous functions/function handles. It uses each region/condition and evaluates the boundaries numerically and stores them into variables Bounds_1 and Bounds_2. These boundaries are then used to truncate each signal by multiplying each section of the piecewise function by its corresponding condition which is a logical array. It's also good to note that this plot will almost be seen as an impulse since the bounds are really small. Alternatively, you can probably achieve the same results using the built-in piecewise() function but I think this method gives a little more insight. As i increases you'll see a plot that resembles more and more of an impulse. To plot this for multiple values or i this can be run in a for-loop.
clc;
i = 3;
Bounds_1 = [i - (1/i^2),i];
Bounds_2 = [i,i + (1/i^2)];
Bounds = [Bounds_1 Bounds_2];
Min = min(Bounds);
Max = max(Bounds);
f1 = #(x) (i^2.*x - i^3 + 1).*(Bounds_1(1) < x & x <= Bounds_1(2));
f2 = #(x) (-i^2.*x + i^3 + 1).*(Bounds_2(1) < x & x <= Bounds_2(2));
f = #(x) f1(x) + f2(x);
fplot(f);
xlim([Min-2 Max+2]);
ylim([0 1.1]);
Here is another solution. You can specify the steps along the x-axis withxstep. With xlower and xupper you can specify the range of the x-axis:
figure ; hold on;
xlabel('x'); ylabel('f(x)');
for i= 2:500
[f,x] = myfunction(0.5,i);
plot (x,f,'DisplayName',sprintf('%i',i));
end
% legend
function [f,x]=myfunction(xstep,i)
%xstep: specifies steps for the x values
% specify max range x \in = [xlower -> xupper]
xlower = -10;
xupper = 600;
x2 = (i-1/i^2): xstep: i;
f2 = i^2*x2 - i^3 + 1;
x3 = i+xstep:xstep:(1+1/i^2);
f3 = -i^2*x3 + i^3 +1;
x1 = xlower:xstep:(i-1/i^2);
f1 = 0*x1;
x4 = (i+1/i^2):xstep:xupper;
f4 = 0*x4;
f = [f1,f2,f3,f4];
x = [x1,x2,x3,x4];
end
Here is what I get
Besides, I am not exactly sure what you mean with ODE (ordinary differential equation) in f(x). For me it seems like an algebraic equation.

How do you use the numjac function in MATLAB?

The documentation online for this particular function is poor, and I was looking for an example on how to use it. It seems to take in 9+ arguments, but I'm not entirely sure what they even are. I am working on implementing function using the trapezoidal rule, however, I am missing the functions that compute the partial derivatives with respect to y and t. I believe that calculating one for t in MATLAB is another case, but here, I'm just trying to use MATLAB to compute it for y.
I'm using the following input initially:
func = #(t,y)(y.^2+y+t);
interval = [0 1];
y0 = 0;
[steps, derivY, derivJ, W, inverseW] = getTrapezoidalODEValues(func, interval, y0)
I set up the function like this:
function [h,J,T,W,iW] = getTrapezoidalODEValues(odefun,tspan,y0,options)
if (nargin==3)
options = odeset();
end
h = NaN; J(0) = NaN; T(0) = NaN; W(0) = NaN; iW = NaN;
[t,yy] = ode(odefun,tspan,y0,options);
[nstep,ndim] = size(yy);
d = 1/(2+sqrt(2));
for j=2:nsteps
h = t(j)-t(j-1);
I = eye(???,???); % identity matrix
quadpoly = ???; % the quadratic polynomial
J(j-1) = numjac(???); % <--partial derivative of odefun with respect to y
T(j-1) = ???; % partial derivative of odefun with respect to t
W(j-1) = I - h .* d .* J;
iW(j-1) = inv(W(j-1));
end
end

Matlab 3d plot custom function

I am new to Matlab and i ran into this problem:
I have a function that takes 3 doubles as arguments and outputs a single double e.g.:
function l = myFunct(a,b,c)
l = a^2*b^2 + (2*(c^2 - b) / (a - sqrt(c)))
end
Now, I need to plot the result of this function for intervals:
a = b = [0.1,3], while keeping c = 2.
I managed to do this for 2d plot of a single variable, but not for 3d...
R = 0:0.01:2;
fun = #(x) myFunct(0.2, x, 3);
B = arrayfun(fun,R);
plot(R, B);
Could you please help and explain?
You can indeed use meshgrid, or ndgrid, to create the two grid arrays. A and B. Then, if your function is not vectorized you need to loop over the entries of A and B. To loop over both at the same time you can use arrayfun. Lastly, you can plot with surf or imagesc.
[A,B] = ndgrid(1.4:0.0001:1.44, -1:.01:3);
Z = arrayfun(#(a,b) myFunct(a,b,2), A, B);
surf(A,B,Z,'edgecolor','none')
I finally solved it with:
V = 2;
[X,Y] = meshgrid(0.1:0.1:3);
Z = myFunct(X,Y,X*0+V);
figure
surf(X,Y,Z);
Thanks all for the replies.

How to calculate the values of non-explicit function for all points of a meshgrid?

Let's say I have a function
f = #(x,y) g(x,y)
g is not explicit. It should be calculated numerically after inputting x and y values.
How can I calculate and save all values of this function at points
[x,y] = meshgrid(0:0.1:1,0:pi/10:2*pi);
I call f[x,y], but it doesn't work.
You have two ways to do it. Your function g should work with matrices, or you should give the values one by one
function eval_on_mesh()
f1 = #(x,y) g1(x,y);
f2 = #(x,y) g2(x,y);
[x,y] = meshgrid(0:0.1:1,0:pi/10:2*pi);
%# If your function work with matrices, you can do it like here
figure, surf(f1(x,y));
%# If your function doesnt, you should give the values one by one
sol = zeros(size(x));
for i=1:size(x,1)
for j=1:size(x,2)
sol(i,j) = f2(x(i,j),y(i,j));
end
end
figure, surf(sol);
end
function res = g1(x, y)
res = x.^2 + y.^2;
end
function res = g2(x, y)
res = x^2 + y^2;
end

Making a function in terms of a sum from 1 to n in Matlab

I'm trying to get Matlab to take this as a function of x_1 through x_n and y_1 through y_n, where k_i and r_i are all constants.
So far my idea was to take n from the user and make two 1×n vectors called x and y, and for the x_i just pull out x(i). But I don't know how to make an arbitrary sum in MATLAB.
I also need to get the gradient of this function, which I don't know how to do either. I was thinking maybe I could make a loop and add that to the function each time, but MATLAB doesn't like that.
I don't believe a loop is necessary for this calculation. MATLAB excels at vectorized operations, so would something like this work for you?
l = 10; % how large these vectors are
k = rand(l,1); % random junk values to work with
r = rand(l,1);
x = rand(l,1);
y = rand(l,1);
vals = k(1:end-1) .* (sqrt(diff(x).^2 + diff(y).^2) - r(1:end-1)).^2;
sum(vals)
EDIT: Thanks to #Amro for correcting the formula and simplifying it with diff.
You can solve for the gradient symbolically with:
n = 10;
k = sym('k',[1 n]); % Create n variables k1, k2, ..., kn
x = sym('x',[1 n]); % Create n variables x1, x2, ..., xn
y = sym('y',[1 n]); % Create n variables y1, y2, ..., yn
r = sym('r',[1 n]); % Create n variables r1, r2, ..., rn
% Symbolically sum equation
s = sum((k(1:end-1).*sqrt((x(2:end)-x(1:end-1)).^2+(y(2:end)-y(1:end-1)).^2)-r(1:end-1)).^2)
grad_x = gradient(s,x) % Gradient with respect to x vector
grad_y = gradient(s,y) % Gradient with respect to y vector
The symbolic sum and gradients can be evaluated and converted to floating point with:
% n random data values for k, x, y, and r
K = rand(1,n);
X = rand(1,n);
Y = rand(1,n);
R = rand(1,n);
% Substitute in data for symbolic variables
S = double(subs(s,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_X = double(subs(grad_x,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_Y = double(subs(grad_y,{[k,x,y,r]},{[K,X,Y,R]}))
The gradient function is the one overloaded for symbolic variables (type help sym/gradient) or see the more detailed documentation online).
Yes, you could indeed do this with a loop, considering that x, y, k, and r are already defined.
n = length(x);
s = 0;
for j = 2 : n
s = s + k(j-1) * (sqrt((x(j) - x(j-1)).^2 + (y(j) - y(j-1)).^2) - r(j-1)).^2
end
You should derive the gradient analytically and then plug in numbers. It should not be too hard to expand these terms and then find derivatives of the resulting polynomial.
Vectorized solution is something like (I wonder why do you use sqrt().^2):
is = 2:n;
result = sum( k(is - 1) .* abs((x(is) - x(is-1)).^2 + (y(is) - y(is-1)).^2 - r(is-1)));
You can either compute gradient symbolically or rewrite this code as a function and make a standard +-eps calculation. If you need a gradient to run optimization (you code looks like a fitness function) you could use algorithms that calculate them themselves, for example, fminsearch can do this