在Mathematica中优化插值

时间:2010-10-25 15:52:11

标签: optimization wolfram-mathematica interpolation

作为我工作的一部分,我经常需要想象复杂的三维密度。我使用的一个程序套件输出密度的径向分量,作为对数网格ri = (Rmax/Rstep)^((i-1)/(pts-1)上的一组781个点,乘以球谐波。对于低对称系统,球谐波的数量可以相当大以确保精度,例如,一个系统需要49个与lmax = 6对应的谐波。因此,要在Mathematica中使用这些数据,我将得到最多49个插值函数的总和,每个函数乘以不同的球谐波。在使用v.6并使用Interpolation并设置r = Sqrt(x^2 + y^2 + z^2)构建插值径向函数时,我会在超过一小时后停止ContourPlot3D而不显示任何内容。这包括将InterpolationOrderMaxRecursion同时减少为1。

有几种替代方案:

  1. 评估固定网格上的密度函数,并改为使用ListContourPlot
  2. 或者,线性样条化径向函数并使用Piecewise将它们拼接在一起。 (这表现了,因为我可以使用简化来帮助降低结果函数的复杂性。)
  3. 我最终使用了两者,因为InterpolatingFunction在评估中给出了明显的延迟,并且最多需要49个内插函数来评估,任何延迟都会变得明显。另外,样条曲线ContourPlot3D速度更快,但它并没有给我提高速度。

    我会自由地承认我在v.7上没有尝试Interpolation,也没有在我的升级硬件(G4诉。英特尔酷睿i5)上试过这个。但是,我正在寻找我目前计划的替代方案;最好是我可以直接使用ContourPlot3D的地方。我可以尝试使用其他形式的样条曲线,例如B-spline,并可能将其与UnitBox结合使用,而不是使用Piecewise

    编辑:为了澄清,我当前的实现涉及为每个径向部分创建一阶样条曲线,将每个样本乘以它们各自的球谐波,求和和Simplify方程式每个径向间隔,然后使用Piecewise将它们绑定到一个函数中。因此,我的实现是半分析的,因为球谐波是精确的,只有径向部分是数值。这是我希望能够使用ContourPlot3D的原因的一部分,这样我就可以利用数据的半分析性质。作为一个注意事项,径向网格足够精细,以便生成径向部分的良好表示并且可以平滑地插值。虽然这给了我一个显着的加速,但是当我编写代码时,我当时使用的硬件仍然会变慢。

    所以,不是使用ContourPlot3D,而是首先生成函数,如上所述,然后我将在80 3 笛卡尔网格上进行评估。这是我在ListContourPlot3D中使用的此步骤的数据。由于这不是一个自适应网格,在某些地方这也是过程,我缺少功能。

2 个答案:

答案 0 :(得分:4)

如果你没有Mathematica,我建议你看看Paraview(美国政府资助的FOSS,所有平台),我发现它在可视化大量数据方面优于一切。 该软件的核心是“可视化工具包”VTK,如果需要,您可以查找/编写其他前端。

VTK / Paraview几乎可以处理任何数据类型:结构化网格或随机点,多边形,时间序列数据等的标量和向量。从Mathematica我经常只将网格数据转储到VTK legacy format中那么最简单的案例就像这样

# vtk DataFile Version 2.0
Generated by mma via vtkGridDump

ASCII

DATASET STRUCTURED_POINTS
DIMENSIONS 49 25 15
SPACING 0.125 0.125 0.0625
ORIGIN 8.5 5. 0.7124999999999999

POINT_DATA 18375
SCALARS  RF_pondpot_1V1MHz1amu  double 1
LOOKUP_TABLE default

0.04709501616121583
0.04135197485227461
... <18373 more numbers> ...

HTH!

答案 1 :(得分:3)

如果确实是径向函数的插值会减慢您的速度,您可以考虑根据您对采样点的了解对该部分进行手工编码。如下所示,这提供了显着的加速:

我用你的符号来设置。 lookuprvals是一个包含100000个r值的列表,用于查找时间。

首先,将股票插值视为基准

With[{interp=Interpolation[N@Transpose@{rvals,yvals}]},
  Timing[interp[lookuprvals]][[1]]]
Out[259]= 2.28466

切换到0阶插值已经快了一个数量级(第一阶几乎是相同的速度):

With[{interp=Interpolation[N@Transpose@{rvals,yvals},InterpolationOrder->0]},
  Timing[interp[lookuprvals]][[1]]]
Out[271]= 0.146486

我们可以通过直接计算指数来获得另外1.5个数量级:

Module[{avg=MovingAverage[yvals,2],idxfact=N[(pts-1) /Log[Rmax/Rstep]]},
  Timing[res=Part[avg,Ceiling[idxfact Log[lookuprvals]]]][[1]]]
Out[272]= 0.006067

作为中间地带,手动进行对数线性插值。这比上面的解决方案慢,但仍然比股票插值快得多:

Module[{diffs=Differences[yvals],
  idxfact=N[(pts-1) /Log[Rmax/Rstep]]},
  Timing[Block[{idxraw,idxfloor,idxrel},
    idxraw=1+idxfact Log[lookuprvals];
    idxfloor=Floor[idxraw];
    idxrel=idxraw-idxfloor;
    res=Part[yvals,idxfloor]+Part[diffs,idxfloor]idxrel  
  ]][[1]]]
Out[276]= 0.026557

如果你有记忆,我会在整个网格上缓存球面谐波和半径(甚至半径索引)。然后展平网格缓存,以便您可以执行

 Sum[ interpolate[yvals[lm],gridrvals] gridylmvals[lm], {lm,lmvals} ]

并按照here的说明重新创建网格。