I want to numerically integrate an integral with infinite limit. Does anyone have any idea how should I do that?
int(x* exp (v*x + (1-exp(v*x))/v),x, o , inf) does not work.
Note that I will have values for v.
%n=10;
kappa=.5;
delta0=.5;
Vmax=500;
Vdep=2.2;
l=2.2;
kbT=4.1;
%xb=.4;
fb=10;
k=1;
V0=5;
e1=(fb*l/kbT)*(kappa/delta0);
e2=Vmax/V0;
e3=Vdep/V0;
w=zeros(1,25);
for v=1:25
w(:,v)=integral(#(x) x.*exp(v*x+((1-exp(v*x))/v)),0,inf);
end
e12=e2*exp(-e1*(1:25).*w.^2)-e3;
plot(e12);
ylim([0 25]);
hold on;
plot(0:25,0:25);
xlim([0 25]);
%hold off;
The plot is not matching the real data in the article!(for the e12 curve specially)
I need to calculate the intersection of the 2 curves (which is ~13.8 based on the paper) and then in the second part I have to add a term in e12 which contains an independent variable:
v=13.8;
w= integral(#(x) x.*exp(v*x+((1-exp(v*x))/v)),0,inf)
e4 = zeros (1,180);
fl = 1:180;
e4(:,fl)= (fl*l/kbT)*(kappa/n);
e12=e2*exp(-e1*v*w^2-e4)-e3
But again the problem is that running this code I will end with a negative value for e12 which should be just approaching zero in large values of fl (fl>160)
to show how this code is different from the expected curve you can plot these data on the same figure:
fl = [0, 1, 4, 9, 15, 20, 25, 40, 60, 80, 100, 120, 140, 160, 180];
e12 = [66, 60, 50, 40, 30, 25.5, 20, 15.5, 10.5, 8.3, 6.6, 5, 2.25, 1.1, 0.5];
which obviously does not match the curve generated by the code.
Assuming the question is about this full code:
syms x;
v = 1; % For example
int(x*exp(v*x + (1-exp(v*x))/v),x, 0, Inf)
and the issue is that it returns itself (i.e., int doesn't find an analytic solution), one can set the 'IgnoreAnalyticConstraints' option to true (more details) to get a solution:
syms x;
v = 1; % For example
int(x*exp(v*x + (1-exp(v*x))/v),x, 0, Inf, 'IgnoreAnalyticConstraints', true)
returns -ei(-1)*exp(1), where ei is the exponential integral function (see also expint for numerical calculations). For negative values of v the solution will also be in terms of eulergamma, the Euler-Mascheroni constant. And of course the integral is undefined if v is 0.
Using Mathematica 10.0.2's Integrate yields a full solution for symbolic v.
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}]
returns
ConditionalExpression[(E^(1/v) (EulerGamma + Gamma[0, 1/v] + Log[1/v]))/v, Re[v] < 0]
Applying Assumptions:
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}, Assumptions -> v > 0]
Integrate[x Exp[v x - (Exp[v x] - 1)/v], {x, 0, Infinity}, Assumptions -> v < 0]
returns
(E^(1/v) Gamma[0, 1/v])/v
and
(E^(1/v) (2 EulerGamma - 2 ExpIntegralEi[-(1/v)] + Log[1/v^2]))/(2 v)
where Gamma is the upper incomplete gamma function. These appear match up with the results from Matlab.
To evaluate these numerically in Matlab:
% For v > 0
v_inv = 1./v;
exp(v_inv).*expint(v_inv).*v_inv
or
% For v < 0
v_inv = 1./v;
exp(v_inv).*(2*double(eulergamma)+2*(expint(v_inv)+pi*1i)+log(v_inv.^2)).*v_inv/2
Numerical integration is performed by summing the function at discrete points with distance dx. The smaller dx you choose, the better approximation you get. For example integrating from x=0 to x=10 is done by:
x = 0:dx:10;
I = sum(x.* exp (v*x + (1-exp(v*x))/v))*dx;
obviously, you can't do that for x=inf. But I believe you function decays rapidly. Therefore, you can assume that x* exp (v*x + (1-exp(v*x))/v) = 0 for large enough x. Otherwise the integral is divergent. So all you have to do is set the limit on x. If you are not sure what the limit should be, you can perform a loop with a stopping condition:
I = 0;
prevI = -1;
x = 0;
while abs(I-prevI)>err
prevI = I;
I = I + x.* exp (v*x + (1-exp(v*x))/v)*dx;
x = x + dx;
end
Now, all you have to do is set the desired dx and err
You must read this:Mathwork Link
perhaps you are making a mistake in the function that you use. Also note that MATLAB syntax is case sensitive..
Related
I am trying to get the volume under a profile by using Octave. I have built a simple model for this:
function F1 = f_x(x)
F1 = x-1;
endfunction
function F2 = f_y(y)
F2 = y;
endfunction
function F3 = f_z(z)
F3 = z;
endfunction
f_xyz = inline('f_x(x).*f_y(y).*f_z(z);', 'x', 'y', 'z');
Volume = triplequad(f_xyz,0,3,0,3,0,4)
x = 1:1:2;
y = 1:1:2;
z = 1:1:2;
f_plot=f_x(x).*f_y(y).*f_z(z)';
%Lines for plotting the 3D plot
tx = linspace (0, 3, numel(x))';
ty = linspace (0, 3, numel(y))';
[xx, yy] = meshgrid (tx, ty);
tz = f_plot;
mesh (tx, ty, tz);
which gives a plot that looks like in the picture below:
I am using the triplequad function (which works also on Matlab) to get the volume under that profile, but it doesn't look like it works. The function return a volume of 54 units, which is not really true. Calculating the volume of a parallelepiped using the full dimensions gives 36 units (3 x 3 x 4), which proves that it calculates it wrongly. The questions is... what am I doing wrong here? Why doesn't "triplequad" give the right volume?
I think you might be misunderstanding the dimensionality of your problem. You're dealing with a 4D function:
f = #(x, y, z) (x-1).*y.*z;
You have a value returned by f (i.e. the dependent variable) determined by a set of 3 independent variables, thus a 4D function. You have to talk in terms of hypervolume instead of volume in this case, since volume is a 3D measurement. The triplequad function will evaluate a triple integral of f over a given set of ranges for the independent variables, giving you the hypervolume:
>> triplequad(f, 0, 3, 0, 3, 0, 4) % Integrate over 0 <= x <= 3, 0 <= y <= 3, 0 <= z <= 4
ans =
53.999999999999986 % Just shy of 54
Your visualization of a 3D surface doesn't make any sense, and is leading you astray in thinking that the result is wrong.
NOTE 1: In MATLAB, the function triplequad appears slated for deprecation in a future release, so you should use integral3 instead. It also appears to give more accurate results:
>> integral3(f, 0, 3, 0, 3, 0, 4)
ans =
54
NOTE 2: In regards to your comment, the function f(x,y,z) = 1 is constant and has no dependence on x, y, or z. A triple integral over this function is the equivalent of computing the volume of the area over which you're integrating (3*3*4 = 36) multiplied by the constant function value (which is just 1 in this case). You can confirm it like so:
>> f = #(x, y, z) ones(size(x));
>> triplequad(f, 0, 3, 0, 3, 0, 4)
ans =
36
EDIT: Regarding your follow-up problem, I actually get an error when trying to run that example in R2016b, so I'm not sure how you got it to work (although the resulting value is correct):
>> V = triplequad(h_xxyy,0,3,0,3,0,15)
Error using inline/subsref (line 14)
Too many inputs to inline function.
The problem is that triplequad is used to perform triple integrals over functions of 3 variables, but your function only has 2 inputs (x and y). When calculating the volume under a function of 2 variables, you only need to integrate over those 2 variables, so you should be using the MATLAB function integral2 instead (or dblquad in Octave):
>> f = #(x, y) x.^2.*sqrt(y);
>> V = integral2(f, 0, 3, 0, 3)
V =
31.176914536244894
Note that f has no z-dependence, so f(x, y) is constant with respect to z (i.e. for a given x and y, it always returns the same value regardless of z). As a result, if you were to perform a third integration over the z dimension it would be the same as multiplying the result by the integration range:
>> V*15
ans =
467.6537 % Same result you got from triplequad
I need to evaluate a function (say)
Fxy = 2*x.^2 +3 *y.^2;
on a ternary grid x-range (0 - 1), y-range (0-1) and 1-x-y (0 - 1).
I am unable to construct the ternary grid on which I need to evaluate the above function. Also, once evaluated I need to plot the function in a ternary contour plot. Ideally, I need the axes to go counter clockwise in the sense (x -> y--> (1-x-y)).
I have tried the function
function tg = triangle_grid ( n, t )
ng = ( ( n + 1 ) * ( n + 2 ) ) / 2;
tg = zeros ( 2, ng );
p = 0;
for i = 0 : n
for j = 0 : n - i
k = n - i - j;
p = p + 1;
tg(1:2,p) = ( i * t(1:2,1) + j * t(1:2,2) + k * t(1:2,3) ) / n;
end
end
return
end
for the number of sub intervals between the triangle edge coordinates
n = 10 (say)
and for the edge coordinates of an equilateral triangle
t = tcoord = [0.0, 0.5, 1.0;
0.0, 1.0*sqrt(3)/2, 0.0];
This generated a triangular grid with the x-axis from 0-1 but the other two are not from 0-1.
I need something like this:
... with the axes range 0-1 (0-100 would also do).
In addition, I need to know the coordinate points for all intersections within the triangular grid. Once I have this I can proceed to evaluate the function in this grid.
My final aim is to get something like this. This is a better representation of what I need to achieve (as compared to the previous plot which I have now removed)
Note that the two ternary plots have iso-value contours which are different in in magnitude. In my case the difference is an order of magnitude, two very different Fxy's.
If I can plot the two ternary plots on top of each other then and evaluate the compositions at the intersection of two iso-value contours on the ternary plane. The compositions should be as read from the ternary plot and not the rectangular grid on which triangle is defined.
Currently there are issues (as highlighted in the comments section, will update this once the problem is closer to solution).
I am the author of ternplot. As you have correctly surmised, ternpcolor does not do what you want, as it is built to grid data automatically. In retrospect, this was not a particularly wise decision, I've made a note to change the design. In the mean time this code should do what you want:
EDIT: I've changed the code to find the intersection of two curves rather than just one.
N = 10;
x = linspace(0, 1, N);
y = x;
% The grid intersections on your diagram are actually rectangularly arranged,
% so meshgrid will build the intersections for us
[xx, yy] = meshgrid(x, y);
zz = 1 - (xx + yy);
% now that we've got the intersections, we can evaluate the function
f1 = #(x, y) 2*x.^2 + 3*y.^2 + 0.1;
Fxy1 = f1(xx, yy);
Fxy1(xx + yy > 1) = nan;
f2 = #(x, y) 3*x.^2 + 2*y.^2;
Fxy2 = f2(xx, yy);
Fxy2(xx + yy > 1) = nan;
f3 = #(x, y) (3*x.^2 + 2*y.^2) * 1000; % different order of magnitude
Fxy3 = f3(xx, yy);
Fxy3(xx + yy > 1) = nan;
subplot(1, 2, 1)
% This constructs the ternary axes
ternaxes(5);
% These are the coordinates of the compositions mapped to plot coordinates
[xg, yg] = terncoords(xx, yy);
% simpletri constructs the correct triangles
tri = simpletri(N);
hold on
% and now we can plot
trisurf(tri, xg, yg, Fxy1);
trisurf(tri, xg, yg, Fxy2);
hold off
view([137.5, 30]);
subplot(1, 2, 2);
ternaxes(5)
% Here we plot the line of intersection of the two functions
contour(xg, yg, Fxy1 - Fxy2, [0 0], 'r')
axis equal
EDIT 2: If you want to find the point of intersection between two contours, you are effectively solving two simultaneous equations. This bit of extra code will solve that for you (notice I've used some anonymous functions in the code above now, as well):
f1level = 1;
f3level = 1000;
intersection = fsolve(#(v) [f1(v(1), v(2)) - f1level; f3(v(1), v(2)) - f3level], [0.5, 0.4]);
% if you don't have the optimization toolbox, this command works almost as well
intersection = fminsearch(#(v) sum([f1(v(1), v(2)) - f1level; f3(v(1), v(2)) - f3level].^2), [0.5, 0.4]);
ternaxes(5)
hold on
contour(xg, yg, Fxy1, [f1level f1level]);
contour(xg, yg, Fxy3, [f3level f3level]);
ternplot(intersection(1), intersection(2), 1 - sum(intersection), 'r.');
hold off
I have played a bit with the file exchange submission https://www.mathworks.com/matlabcentral/fileexchange/2299-alchemyst-ternplot.
if you just do this:
[x,y]=meshgrid(0:0.1:1);
Fxy = 2*x.^2 +3 *y.^2;
ternpcolor(x(:),y(:),Fxy(:))
You get:
The thirds axis is created exactly as you say (1-x-y) inside the ternpcolor function. There are lots of things to "tune" here but I hope it is enough to get you started.
Here is a solution using R and my package ggtern. I have also included the points within proximity underneath, for the purpose of comparison.
library(ggtern)
Fxy = function(x,y){ 2*x^2 + 3*y^2 }
x = y = seq(0,1,length.out = 100)
df = expand.grid(x=x,y=y);
df$z = 1 - df$x - df$y
df = subset(df,z >= 0)
df$value = Fxy(df$x,df$y)
#The Intended Breaks
breaks = pretty(df$value,n=10)
#Create subset of the data, within close proximity to the breaks
df.sub = ldply(breaks,function(b,proximity = 0.02){
s = b - abs(proximity)/2; f = b + abs(proximity)/2
subset(df,value >= s & value <= f)
})
#Plot the ternary diagram
ggtern(df,aes(x,y,z)) +
theme_bw() +
geom_point(data=df.sub,alpha=0.5,color='red',shape=21) +
geom_interpolate_tern(aes(value = value,color=..level..), size = 1, n = 200,
breaks = c(breaks,max(df$value) - 0.01,min(df$value) + 0.01),
base = 'identity',
formula = value ~ poly(x,y,degree=2)) +
labs(title = "Contour Plot on Modelled Surface", x = "Left",y="Top",z="Right")
Which produces the following:
My function is just a simple summation from -inf to inf: f(x) = sum(pi * exp(-x+2pi*j), j = -inf to in);
I tried doing this, but got error saying "A numeric or double convertible argument is expected"
x = linspace(-7, 7, 1000);
h = 10;
syms j;
v_hat = symsum(pi * exp(x + 2*pi*j),-inf, inf); %v_hat is a function of x: v_hat(x)
plot(x, v_hat);
I see nothing wrong with your code programming-wise, but there is a fatal mathematical flaw -- the sum is infinite for every x. Note that it's just sum of exp(2*pi*j) multiplied by pi*exp(x). The values exp(2*pi*j) are large when j is positive, and you try to add infinitely many of them...
When I change the formula to a series that actually converges, the code works, although it takes a long while.
x = linspace(-7, 7, 1000);
h = 10;
syms j;
v_hat = symsum(pi * exp(-abs(x+ 2*pi*j/h) ),-inf, inf);
plot(x, v_hat);
Note that the quality isn't great despite using 1000 data points. You will get better quality much faster by abandoning symbolic sum. The contribution of the terms with abs(j)>100 is tiny here, so drop them and use numeric sum over the rest.
h = 10;
x = linspace(-7,7,10000);
[X,j] = meshgrid(x, -100:100);
v_hat = sum(pi * exp(-abs(X+ 2*pi*j/h) ), 1);
plot(x, v_hat);
Also, realize that the function is periodic with period 2*pi/h. So you can plot
one or two periods of the function, and imagine the rest.
h = 10;
x = linspace(-2*pi/h, 2*pi/h, 101);
syms j;
v_hat = symsum(pi * exp(-abs(x+ 2*pi*j/h) ),-inf, inf);
plot(x, v_hat);
I have to calculate some limits:
syms x1 x2 a
x0 = [0, 1];
x_dir = [1, 0];
f = max(0,x1) + (x1^2)*abs(x2)
f_lim = (1/a) * (f(x0 + a*x_dir) - f(x0))
f_lim_left = limit(f_lim, a, 0, 'left');
f_lim_right = limit(f_lim, a, 0, 'right');
I just can't use max function on symbolic values, because I am not allowed by MATLAB. But, it's obvious what I am trying to do: to get a piece of code that's independent of variables (x0, x_dir), so I can change them easily. I've tried using double or using feval(symengine,'max',x,-y) as found on net, but no luck. Any workaround, guys?
You can define f as
f(x1,x2) = feval(symengine,'max',x1,0) + (x1^2)*abs(x2);
and then compute its directional derivative with respect to x1 by finite differences as
f_lim_x1(x1, x2) = (f(x1+a, x2)-f(x1,x2))/abs(a);
You can also look at the limit function
limit(f, x1, x0, direction)
where direction can be either 'left' or 'right'.
This post updates my question in Solve finds wrong solution?
Given the "simple" function in x:
f = (x + 3/10)^(1/2) - (9*(x + 3/10)^5)/5 - (x + 3/10)^6 + (x - 1)/(2*(x + 3/10)^(1/2));
Find the zeros by the call
solve(f,x)
This yields 3 zeros:
ans =
0.42846617518653978966562924618638
0.15249587894102346284238111155954
0.12068186494007759990714181154349
A simple look at the plot shows that the third root is nonsense:
I have a serious problem because I need to retrieve the smallest zero from the above vector. Calling min(ans) returns a wrong zero. What can I do to workaround?
This is a non-polynomial equation, and it will probably fallback to a numeric solver (non-symbolic). So there might be numerical errors, or the numeric algorithm might get stuck and report false solutions, I'm not sure...
What you can do is substitute the solutions back into the equation, and reject ones that are above some specified threshold:
% define function
syms x real
syms f(x)
xx = x+3/10;
f(x) = sqrt(xx) - 9/5*xx^5 - xx^6 + (x - 1)/(2*sqrt(xx));
pretty(f)
% find roots
sol = solve(f==0, x, 'Real',true)
% filter bad solutions
err = subs(f, x, sol)
sol = sol(abs(err) < 1e-9); % this test removes the 2nd solution
% plot
h = ezplot(f, [0.1 0.5]);
line(xlim(), [0 0], 'Color','r', 'LineStyle',':')
xlabel('x'), ylabel('f(x)')
% programmatically insert data tooltips
xd = get(h, 'XData'); yd = get(h ,'YData');
[~,idx] = min(abs(bsxfun(#minus, xd, double(sol))), [], 2);
dcm = datacursormode(gcf);
pos = [xd(idx) ; yd(idx)].';
for i=1:numel(idx)
dtip = createDatatip(dcm, h);
set(get(dtip,'DataCursor'), 'DataIndex',idx(i), 'TargetPoint',pos(i,:))
set(dtip, 'Position',pos(i,:))
end
We are left only with the two desired solutions (one is rejected by our test):
/ 3 \5
9 | x + -- |
/ 3 \ \ 10 / / 3 \6 x - 1
sqrt| x + -- | - ------------- - | x + -- | + ----------------
\ 10 / 5 \ 10 / / 3 \
2 sqrt| x + -- |
\ 10 /
sol =
0.42846617518653978966562924618638
0.12068186494007759990714181154349 % <== this one is dropped
0.15249587894102346284238111155954
err(x) =
-9.1835496157991211560057541970488e-41
-0.058517436737550288309001512815475 % <==
1.8367099231598242312011508394098e-40
I also tried using MATLAB's numeric solvers, which were able to find the two solutions given reasonable starting points:
fzero function (a derivative-free root-finding algorithm)
fsolve function (from the Optimization Toolbox)
(See this related question)
fcn = matlabFunction(f); % convert symbolic f to a regular function handle
opts = optimset('Display','off', 'TolFun',1e-9, 'TolX',1e-6);
% FZERO
sol2(1) = fzero(fcn, 0.1, opts);
sol2(2) = fzero(fcn, 0.5, opts);
disp(sol2) % [0.1525, 0.4285]
% FSOLVE
sol3(1) = fsolve(fcn, 0.0, opts);
sol3(2) = fsolve(fcn, 1.0, opts);
disp(sol3) % [0.1525, 0.4285]
For comparison, I tried solving the equation directly into MuPAD, as well as in Mathematica.
Mathematica 9.0
MuPAD (R2014a)
Of course we can always directly call MuPAD from inside MATLAB:
% f is the same symbolic function we've built above
>> sol = evalin(symengine, ['numeric::solve(' char(f) ' = 0, x, AllRealRoots)'])
sol =
[ 0.15249587894102346284238111155954, 0.42846617518653978966562924618638]
The above call is equivalent to searching the entire range x = -infinity .. infinity (which can be slow!). We should assist numeric::solve by providing a specific search ranges when possible:
>> sol = feval(symengine, 'numeric::solve', f==0, 'x = 0 .. 1', 'AllRealRoots')
sol =
[ 0.15249587894102346284238111155954, 0.42846617518653978966562924618638]
One workaround could be taking min(ans), and then checking that f(min(ans))==0. If not, then use the next-smallest value.