Schwarz-Christoffel Mapping

时间:2015-12-25 16:41:08

标签: c# math complex-numbers integral

我已经编写了一些代码来试验Schwarz-Christoffel Mapping。

Schwarz-Christoffel Mapping的基础知识可以在维基百科here找到。

namespace Conformal
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Numerics;

    // There is still some bugs, but not sure what is that ...
    internal static class Program
    {
        private static Complex Integrand(Complex input)
        {
            // [(w - 50)(w + 50)]^(-2/3)
            Complex inside = (input - 50) * (input + 50);
            return Complex.Pow(inside, -2.0 / 3.0);
            // Experiment, let integrate w = z instead and see if the output make sense
            // The good thing about trapezoidal rule is that its result is *exact* for linear function, so we can check if the answer make sense
            // Experiment passed, it does indeed give us what we wanted
            // return input;
        }

        private static IEnumerable<Tuple<Complex, Complex>> TrapezoidReal(Complex integrateSrc, Complex integrateDst, int numIntervals, Func<Complex, Complex> f)
        {
            yield return Tuple.Create(integrateSrc, (Complex)0);
            double N = (double)numIntervals;
            double range = integrateDst.Real - integrateSrc.Real;
            double delta = range / N;

            Complex sum = f(integrateSrc) * 0.5 * delta;
            for (int n = 1; n <= numIntervals; n++)
            {
                Complex current = new Complex(integrateSrc.Real + (n / N) * range, integrateSrc.Imaginary);
                Complex eval = f(current);
                sum += eval * 0.5 * delta;
                yield return Tuple.Create(current, sum);
                sum += eval * 0.5 * delta;
            }
        }

        private static IEnumerable<Tuple<Complex, Complex>> TrapezoidImag(Complex integrateSrc, Complex integrateDst, int numIntervals, Func<Complex, Complex> f)
        {
            yield return Tuple.Create(integrateSrc, (Complex)0);
            double N = (double)numIntervals;
            double range = integrateDst.Imaginary - integrateSrc.Imaginary;
            double delta = range / N;

            Complex sum = f(integrateSrc) * new Complex(0, 0.5 * delta);
            for (int n = 1; n <= numIntervals; n++)
            {
                Complex current = new Complex(integrateSrc.Real, integrateSrc.Imaginary + (n / N) * range);
                Complex eval = f(current);
                sum += eval * new Complex(0, 0.5 * delta);
                yield return Tuple.Create(current, sum);
                sum += eval * new Complex(0, 0.5 * delta);
            }
        }

        private static void Main(string[] args)
        {
            // This avoid evaluating the integrand at the poles
            double shift = 0.1;

            // The program implements the Schwarz-Christoffel Mapping
            // The function build a conformal mapping that maps the upper 
            // half plane to a triangle

            // The base for the integration is (-100, 0)
            // We create a grid with real = (-100, 100), imag = (0, 200)
            // The grid is divided into 10 lines for simplicity
            // The numerical integration is done using trapezoidal rule

            Complex point_o = new Complex(-100 + shift, 0 + shift);
            Complex point_x = new Complex(100 + shift, 0 + shift);
            Complex point_y = new Complex(-100 + shift, 200 + shift);

            // First, build the X and Y axis
            var xAxis = TrapezoidReal(point_o, point_x, 10000, Integrand);
            var yAxis = TrapezoidImag(point_o, point_y, 10000, Integrand);

            // Sample every 1,000 elements for the marks
            var xMarks = Sample(xAxis, 1000);
            var yMarks = Sample(yAxis, 1000);

            //PrintPoints(xAxis);
            //PrintPoints(yAxis);

            // Build the horizontal grid lines
            foreach (var yMark in yMarks)
            {
                var imag = yMark.Item1.Imaginary;
                var gridPoints = Sample(TrapezoidReal(new Complex(-100 + shift, imag), new Complex(100 + shift, imag), 10000, Integrand).Select(t => Tuple.Create(t.Item1, t.Item2 + yMark.Item2)), 100);
                PrintPoints(gridPoints);
            }

            // Build the vertical grid lines
            foreach (var xMark in xMarks)
            {
                var real = xMark.Item1.Real;
                var gridPoints = Sample(TrapezoidImag(new Complex(real, 0 + shift), new Complex(real, 200 + shift), 10000, Integrand).Select(t => Tuple.Create(t.Item1, t.Item2 + xMark.Item2)), 100);
                PrintPoints(gridPoints);
            }
        }

        private static IEnumerable<Tuple<Complex, Complex>> Sample(IEnumerable<Tuple<Complex, Complex>> xAxis, int every)
        {
            return xAxis.Where((t, i) => i % every == 0);
        }

        private static void PrintPoints(IEnumerable<Tuple<Complex, Complex>> gridPoints)
        {
            foreach (var gridPoint in gridPoints)
            {
                Console.WriteLine("{0},{1},{2},{3}", gridPoint.Item1.Real, gridPoint.Item1.Imaginary, gridPoint.Item2.Real, gridPoint.Item2.Imaginary);
            }
        }
    }
}

完整的源代码可以在GitHub上找到here

代码基本上是应用于积分的梯形方法的简化实现。我将左下角的积分基于(-100,0),构建了两个轴,然后向前和向前行进以获得网格线并打印出坐标。

生成的图形应如下所示:

enter image description here

但实际上,它看起来像这样:

enter image description here

我还能做些什么来诊断出现了什么问题?

1 个答案:

答案 0 :(得分:1)

我通过更仔细地查看生成点的顺序来找到我自己问题的答案。

缩短调试故事,问题的症结在于我犯了一个非常愚蠢的错误:公式应该是(w - 50)^( - 2/3)w ^( - 2/3)(w + 50)^( - 2/3)而不是((w - 50)(w + 50))^( - 2/3)

修好后,我有正确的情节如下:

enter image description here

注意角度!它现在是从上半平面到三角形的共形映射!

代码也在GitHub上更新。