Skip to main content

numerical integration - NIntegrating within an Ellipsoid


I need to numerically integrate an expensive positive-definite function over a 2D domain. I know by other ways that the function is basically zero for values outside the following ellipse:


Ellipsoid[center,Sqrt[Eigenvalues[matrix]], Eigenvectors[matrix]]


How do I tell Mathematica to integrate only within the ellipsoid?




Here is what I got using your nice suggestions (timings are normalized to the slowest):


100 sec - integration over the rectangle circumscribing the ellipse



55 sec - using Boole to integrate only over ellipse (@b.gatessucks)


47 sec - directly limiting the domain to the ellipse (@whuber)


41 sec - mapping the ellipse to a unit circle (@Jens)



Answer



Why not use elliptical coordinates? That's what they are there for.


For example, if your function is f[x_,y_], then you define the coordinate transformation


x[u_, v_]:= Cos[v] Cosh[u];
y[u_, v_]:= Sin[v] Sinh[u];

The Jacobian is Sin[v]^2 + Sinh[u]^2, so you simply do the integral like this:



NIntegrate[
f[x[u, v], y[u, v]] (Sin[v]^2 + Sinh[u]^2), {u, 0, 1}, {v, 0, 2 Pi}]

That's the basic idea. You can always rotate and scale your function arguments to fit within this particular ellipse which has axis lengths of Cosh[1] and Sinh[1], respectively. You can also adjust the integration limit in {u, 0, 1} to something other than 1 depending on the eccentricity of the ellipse. These steps are easy once you understand the coordinate system.


You can also do all this using the VectorAnalysis package, but I'd say that is overkill for this relatively simple problem.


Rescaling to a circle in 2D


In fact, you may also want to look into just rescaling your x and y coordinates to fit into a circle and use polar coordinates... (that also generalizes more easily to higher dimensions).


There isn't exactly one built-in function to do the rescaling, but you can probably find all you need by starting at this post. I'll just describe the logic:


Assume you have already figured out the semimajor and -minor axes (vec1 and vec2) as well as the center (in a variable center) of the ellipse. Then you can figure out the rotation angle required to make vec1 the x-axis, leading to a rotation R. The scale transformation T that you need is given by the lengths of vec1 and vec2, resp.


Now compose your function f[x,y] with these transformations. This transformation introduces a Jacobian given by the product Norm[vec] * Norm[vec2].



The final step is to go to polar coordinates which introduces an additional factor r (the radial coordinate).


Polar coordinates are probably best in this case, unless you plan on doing other manipulations with your function that go beyond integration.


Edit


Turns out it's almost more difficult to describe the transformations in words than it is to do it in Mathematica. So I'm adding the code now:


rescaling = Composition[TranslationTransform[center], 
RotationTransform[{{1, 0}, vec1}],
ScalingTransform[{Norm[vec1], Norm[vec2]}]]

This is now used in the integral of your function which I assume to be defined as


f[{x_, y_}] := ...


(note that the argument is a single list representing the point). With this, it only remains to write the integral


integrand = Composition[f, rescaling];
polarIntegrand[r_?NumericQ, a_?NumericQ] :=
integrand[{r Cos[a], r Sin[a]}] r;
NIntegrate[
polarIntegrand[r,a],
{r, 0, 1}, {a, 0, 2 Pi}] Norm[vec1] Norm[vec2]

Here, I've tweaked the integrand a little to make sure we don't get slowed down by Mathematica attempting to symbolically simplify it. The ?NumericQ rules that out. That should be all you need.



Comments

Popular posts from this blog

front end - keyboard shortcut to invoke Insert new matrix

I frequently need to type in some matrices, and the menu command Insert > Table/Matrix > New... allows matrices with lines drawn between columns and rows, which is very helpful. I would like to make a keyboard shortcut for it, but cannot find the relevant frontend token command (4209405) for it. Since the FullForm[] and InputForm[] of matrices with lines drawn between rows and columns is the same as those without lines, it's hard to do this via 3rd party system-wide text expanders (e.g. autohotkey or atext on mac). How does one assign a keyboard shortcut for the menu item Insert > Table/Matrix > New... , preferably using only mathematica? Thanks! Answer In the MenuSetup.tr (for linux located in the $InstallationDirectory/SystemFiles/FrontEnd/TextResources/X/ directory), I changed the line MenuItem["&New...", "CreateGridBoxDialog"] to read MenuItem["&New...", "CreateGridBoxDialog", MenuKey["m", Modifiers-...

How to thread a list

I have data in format data = {{a1, a2}, {b1, b2}, {c1, c2}, {d1, d2}} Tableform: I want to thread it to : tdata = {{{a1, b1}, {a2, b2}}, {{a1, c1}, {a2, c2}}, {{a1, d1}, {a2, d2}}} Tableform: And I would like to do better then pseudofunction[n_] := Transpose[{data2[[1]], data2[[n]]}]; SetAttributes[pseudofunction, Listable]; Range[2, 4] // pseudofunction Here is my benchmark data, where data3 is normal sample of real data. data3 = Drop[ExcelWorkBook[[Column1 ;; Column4]], None, 1]; data2 = {a #, b #, c #, d #} & /@ Range[1, 10^5]; data = RandomReal[{0, 1}, {10^6, 4}]; Here is my benchmark code kptnw[list_] := Transpose[{Table[First@#, {Length@# - 1}], Rest@#}, {3, 1, 2}] &@list kptnw2[list_] := Transpose[{ConstantArray[First@#, Length@# - 1], Rest@#}, {3, 1, 2}] &@list OleksandrR[list_] := Flatten[Outer[List, List@First[list], Rest[list], 1], {{2}, {1, 4}}] paradox2[list_] := Partition[Riffle[list[[1]], #], 2] & /@ Drop[list, 1] RM[list_] := FoldList[Transpose[{First@li...

plotting - How to draw lines between specified dots on ListPlot?

I would like to create a plot where I have unconnected dots and some connected. So far, I have figured out how to draw the dots. My code is the following: ListPlot[{{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4,13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full] I have thought using ListLinePlot command, but I don't know how to specify to the command to draw only selected lines between the dots. Do have any suggestions/hints on how to do that? Thank you. Answer One possibility would be to use Epilog with Line : ListPlot[ {{1, 1}, {2, 2}, {3, 3}, {4, 4}, {1, 4}, {2, 5}, {3, 6}, {4, 7}, {1, 7}, {2, 8}, {3, 9}, {4, 10}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {2.5, 7}}, Ticks -> {{1, 2, 3, 4}, None}, AxesStyle -> Thin, TicksStyle -> Directive[Black, Bold, 12], Mesh -> Full, Epilog -> { Line[ ...