Python Numerical Integration for Volume of Region

好久不见. 提交于 2019-12-05 05:10:48

As the others have already noted, finding the volume of domain that's given by a Boolean function is hard. You could used pygalmesh (a small project of mine) which sits on top of CGAL and gives you back a tetrahedral mesh. This

import numpy
import pygalmesh
import meshplex


class Custom(pygalmesh.DomainBase):
    def __init__(self):
        super(Custom, self).__init__()
        return

    def eval(self, x):
        return (x[0]**2 + x[1]**2 + x[2]**2) - 1.0

    def get_bounding_sphere_squared_radius(self):
        return 2.0


mesh = pygalmesh.generate_mesh(Custom(), cell_size=1.0e-1)

gives you

From there on out, you can use a variety of packages for extracting the volume. One possibility: meshplex (another one out of my zoo):

import meshplex
mp = meshplex.MeshTetra(mesh.points, mesh.cells["tetra"])
print(numpy.sum(mp.cell_volumes))

gives

4.161777

which is close enough to the true value 4/3 pi = 4.18879020478.... If want more precision, decrease the cell_size in the mesh generation above.

Your function is not a continuous function, I think it's difficult to do the integration.

How about:

import numpy as np

def sphere(x,y,z):
    return x**2 + y**2 + z**2 <= 1

x, y, z = np.random.uniform(-2, 2, (3, 2000000))

sphere(x, y, z).mean() * (4**3), 4/3.0*np.pi

output:

(4.1930560000000003, 4.1887902047863905)

Or VTK:

from tvtk.api import tvtk

n = 151
r = 2.0
x0, x1 = -r, r
y0, y1 = -r, r
z0, z1 = -r, r
X,Y,Z = np.mgrid[x0:x1:n*1j, y0:y1:n*1j, z0:z1:n*1j]
s = sphere(X, Y, Z)

img = tvtk.ImageData(spacing=((x1-x0)/(n-1), (y1-y0)/(n-1), (z1-z0)/(n-1)), 
                     origin=(x0, y0, z0), dimensions=(n, n, n))

img.point_data.scalars = s.astype(float).ravel()

blur = tvtk.ImageGaussianSmooth(input=img) 
blur.set_standard_deviation(1)
contours = tvtk.ContourFilter(input = blur.output) 

contours.set_value(0, 0.5)
mp = tvtk.MassProperties(input = contours.output)
mp.volume, mp.surface_area

output:

4.186006622559839, 12.621690438955586

It seems to be very difficult without giving a little hint on the boundary:

import numpy as np
from scipy.integrate import *

def integrand(z,y,x):
    return 1. if x**2 + y**2 + z**2 <= 1. else 0.

g=lambda x: -2
h=lambda x: 2
q=lambda x,y: -np.sqrt(max(0, 1-x**2-y**2))
r=lambda x,y: np.sqrt(max(0, 1-x**2-y**2))
I=tplquad(integrand,-2.,2.,g,h,q,r)

print I
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!