我有一组定义3D轮廓的3D点。我想要做的是获得与此轮廓(see Minimal Surfaces in Wikipedia)对应的最小曲面表示。基本上这需要求解非线性偏微分方程。
在Matlab中,使用pdenonlin
函数(see Matlab's documentation)几乎可以直截了当。可以在此处找到用于解决最小表面问题的示例:Minimal Surface Problem on the Unit Disk。
我需要在Python中进行这样的实现,但我知道我还没有找到任何有关如何实现这一目标的网络资源。
有人能指出这种实施的任何资源/例子吗?
谢谢, 米格尔。
更新
我想要找到的3D表面(理想情况下是三角形网格表示)受这组3D点的限制(如图所示,这些点位于最佳拟合平面中):
好的,做一些研究我发现这个最小的表面问题与Biharmonic Equation的解决方案有关,我还发现Thin-plate spline是这个等式的基本解决方案。
所以我认为这种方法是尝试使用薄板样条拟合表面的稀疏表示(由点的3D轮廓给出)。我发现this example in scipy.interpolate使用薄板样条插入散射数据(x,y,z格式),以获得均匀网格(XI,YI)上的ZI坐标。
出现两个问题: (1)薄板样条插值是否是从3D轮廓点集计算表面问题的正确方法? (2)如果是这样,如何使用NON-UNIFORM网格在scipy上执行薄板插值?
再次感谢! 米格尔
更新:在MATLAB中实现(但它不适用于SCIPY PYTHON)
我使用Matlab的tpaps
函数跟踪this example,并在均匀网格上获得了适合我轮廓的最小曲面。这是Matlab的结果(看起来很棒!):
但是我需要在Python中实现它,所以我使用了包scipy.interpolate.Rbf和thin-plate
函数。这是python中的代码(XYZ
包含轮廓中每个点的3D坐标):
GRID_POINTS = 25
x_min = XYZ[:,0].min()
x_max = XYZ[:,0].max()
y_min = XYZ[:,1].min()
y_max = XYZ[:,1].max()
xi = np.linspace(x_min, x_max, GRID_POINTS)
yi = np.linspace(y_min, y_max, GRID_POINTS)
XI, YI = np.meshgrid(xi, yi)
from scipy.interpolate import Rbf
rbf = Rbf(XYZ[:,0],XYZ[:,1],XYZ[:,2],function='thin-plate',smooth=0.0)
ZI = rbf(XI,YI)
然而,这是结果(与Matlab中获得的结果完全不同):
很明显,scipy的结果与最小的表面不对应。
scipy.interpolate.Rbf + thin-plate是否按预期运行,为什么它与Matlab的结果不同?
答案 0 :(得分:1)
问题表明我们需要求解非线性偏微分方程。然而,维基百科指出“它们很难研究:几乎没有适用于所有这些方程的通用技术,通常每个单独的方程都必须作为一个单独的问题进行研究。”但是,你没有给出等式! Matlab有时会使用遗传算法到达其表面吗?也就是说,它是否使用经验法则进行最佳猜测,然后在组件正方形中尝试小变化,直到找不到更小的表面。实现这种解决方案将是费力的,但在概念上并不困难(假设你喜欢那种东西)。还要记住,连续函数的微积分只是函数的所有线性近似的微积分的一种特殊情况(增量设置为零而不是某些有限值)。通过阅读J L Bell关于平滑无穷小分析的书籍,我明白了这一点 - 只需使用有限增量的代数,并将结果因子留在推导中而不是“忽略”它们。
答案 1 :(得分:0)
显然,Matlab和SciPy以不同的方式理解TPS。 Matlab实现看起来是正确的。 SciPy以与其他RBF相同的方式处理TPS,因此您可以自己在Python中正确实现它 - 只需形成相关线性方程组的矩阵并解决它以接收TPS'系数。
答案 2 :(得分:0)
您可以使用FEniCS:
from fenics import (
UnitSquareMesh,
FunctionSpace,
Expression,
interpolate,
assemble,
sqrt,
inner,
grad,
dx,
TrialFunction,
TestFunction,
Function,
solve,
DirichletBC,
DomainBoundary,
MPI,
XDMFFile,
)
# Create mesh and define function space
mesh = UnitSquareMesh(100, 100)
V = FunctionSpace(mesh, "Lagrange", 2)
# initial guess (its boundary values specify the Dirichlet boundary conditions)
# (larger coefficient in front of the sin term makes the problem "more nonlinear")
u0 = Expression("a*sin(2.5*pi*x[1])*x[0]", a=0.2, degree=5)
u = interpolate(u0, V)
print(
"initial surface area: {}".format(assemble(sqrt(1 + inner(grad(u), grad(u))) * dx))
)
# Define the linearized weak formulation for the Newton iteration
du = TrialFunction(V)
v = TestFunction(V)
q = (1 + inner(grad(u), grad(u))) ** (-0.5)
a = (
q * inner(grad(du), grad(v)) * dx
- q ** 3 * inner(grad(u), grad(du)) * inner(grad(u), grad(v)) * dx
)
L = -q * inner(grad(u), grad(v)) * dx
du = Function(V)
# Newton iteration
tol = 1.0e-5
maxiter = 30
for iter in range(maxiter):
# compute the Newton increment by solving the linearized problem;
# note that the increment has *homogeneous* Dirichlet boundary conditions
solve(a == L, du, DirichletBC(V, 0.0, DomainBoundary()))
u.vector()[:] += du.vector() # update the solution
eps = sqrt(
abs(assemble(inner(grad(du), grad(du)) * dx))
) # check increment size as convergence test
area = assemble(sqrt(1 + inner(grad(u), grad(u))) * dx)
print(
f"iteration{iter + 1:3d} H1 seminorm of delta: {eps:10.2e} area: {area:13.5e}"
)
if eps < tol:
break
if eps > tol:
print("no convergence after {} Newton iterations".format(iter + 1))
else:
print("convergence after {} Newton iterations".format(iter + 1))
with XDMFFile(MPI.comm_world, "out.xdmf") as xdmf_file:
xdmf_file.write(u)
(从http://www-users.math.umn.edu/~arnold/8445/programs/minimalsurf-newton.py修改。)