C#,数值计算——偏微分方程,Mgfas的计算方法与源程序

 

1 文本格式

using System;
using System.Collections.Generic;

namespace Legalsoft.Truffer
{
    public class Mgfas
    {
        public int n { get; set; }
        public int ng { get; set; }
        public double[,] uj;
        public double[,] uj1 { get; set; }
        public List rho { get; set; } = new List();

        public Mgfas(double[,] u, int maxcyc)
        {
            this.n = u.GetLength(0);
            this.ng = 0;
            int nn = n;
            while ((nn >>= 1) != 0)
            {
                ng++;
            }
            if ((n - 1) != (1 << ng))
            {
                throw new Exception("n-1 must be a power of 2 in mgfas.");
            }
            nn = n;
            int ngrid = ng - 1;
            rho = new List(ng);
            //rho.resize(ng);
            rho[ngrid] = new double[nn, nn];
            rho[ngrid] = u;
            while (nn > 3)
            {
                nn = nn / 2 + 1;
                rho[--ngrid] = new double[nn, nn];

                //rstrct(ref rho[ngrid], rho[ngrid + 1]);
                double[,] tmp = rho[ngrid];
                rstrct( tmp, rho[ngrid + 1]);
                //rho[ngrid] = new double[,](tmp);
                rho[ngrid] = Globals.CopyFrom(tmp);
            }
            nn = 3;
            uj = new double[nn, nn];
            slvsm2( uj, rho[0]);
            for (int j = 1; j < ng; j++)
            {
                nn = 2 * nn - 1;
                uj1 = uj;
                uj = new double[nn, nn];
                double[,] temp = new double[nn, nn];
                interp( uj, uj1);
                uj1 = null;
                for (int jcycle = 0; jcycle < maxcyc; jcycle++)
                {
                    double trerr = 1.0;
                    mg(j, uj, temp, rho, ref trerr);
                    lop( temp, uj);
                    matsub(temp, rho[j],  temp);
                    double res = anorm2(temp);
                    if (res < trerr)
                    {
                        break;
                    }
                }
            }
            u = uj;
        }

        public void matadd(double[,] a, double[,] b, double[,] c)
        {
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    c[i, j] = a[i, j] + b[i, j];
                }
            }
        }

        public void matsub(double[,] a, double[,] b, double[,] c)
        {
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    c[i, j] = a[i, j] - b[i, j];
                }
            }
        }

        public void slvsm2(double[,] u, double[,] rhs)
        {
            double h = 0.5;
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    u[i, j] = 0.0;
                }
            }
            double fact = 2.0 / (h * h);
            double disc = Math.Sqrt(fact * fact + rhs[1, 1]);
            u[1, 1] = -rhs[1, 1] / (fact + disc);
        }

        public void relax2(double[,] u, double[,] rhs)
        {
            int n = u.GetLength(0);
            int jsw = 1;
            double h = 1.0 / (n - 1);
            double h2i = 1.0 / (h * h);
            double foh2 = -4.0 * h2i;
            for (int ipass = 0; ipass < 2; ipass++, jsw = 3 - jsw)
            {
                int isw = jsw;
                for (int j = 1; j < n - 1; j++, isw = 3 - isw)
                {
                    for (int i = isw; i < n - 1; i += 2)
                    {
                        double res = h2i * (u[i + 1, j] + u[i - 1, j] + u[i, j + 1] + u[i, j - 1] - 4.0 * u[i, j]) + u[i, j] * u[i, j] - rhs[i, j];
                        u[i, j] -= res / (foh2 + 2.0 * u[i, j]);
                    }
                }
            }
        }

        public void rstrct(double[,] uc, double[,] uf)
        {
            int nc = uc.GetLength(0);
            int ncc = 2 * nc - 2;
            for (int jf = 2, jc = 1; jc < nc - 1; jc++, jf += 2)
            {
                for (int iif = 2, ic = 1; ic < nc - 1; ic++, iif += 2)
                {
                    uc[ic, jc] = 0.5 * uf[iif, jf] + 0.125 * (uf[iif + 1, jf] + uf[iif - 1, jf] + uf[iif, jf + 1] + uf[iif, jf - 1]);
                }
            }
            for (int jc = 0, ic = 0; ic < nc; ic++, jc += 2)
            {
                uc[ic, 0] = uf[jc, 0];
                uc[ic, nc - 1] = uf[jc, ncc];
            }
            for (int jc = 0, ic = 0; ic < nc; ic++, jc += 2)
            {
                uc[0, ic] = uf[0, jc];
                uc[nc - 1, ic] = uf[ncc, jc];
            }
        }


        public void lop(double[,] xout, double[,] u)
        {
            int n = u.GetLength(0);
            double h = 1.0 / (n - 1);
            double h2i = 1.0 / (h * h);
            for (int j = 1; j < n - 1; j++)
            {
                for (int i = 1; i < n - 1; i++)
                {
                    xout[i, j] = h2i * (u[i + 1, j] + u[i - 1, j] + u[i, j + 1] + u[i, j - 1] - 4.0 * u[i, j]) + u[i, j] * u[i, j];
                }
            }
            for (int i = 0; i < n; i++)
            {
                xout[i, 0] = xout[i, n - 1] = xout[0, i] = xout[n - 1, i] = 0.0;
            }
        }

        public void interp(double[,] uf, double[,] uc)
        {
            int nf = uf.GetLength(0);
            int nc = nf / 2 + 1;
            for (int jc = 0; jc < nc; jc++)
            {
                for (int ic = 0; ic < nc; ic++)
                {
                    uf[2 * ic, 2 * jc] = uc[ic, jc];
                }
            }
            for (int jf = 0; jf < nf; jf += 2)
            {
                for (int iif = 1; iif < nf - 1; iif += 2)
                {
                    uf[iif, jf] = 0.5 * (uf[iif + 1, jf] + uf[iif - 1, jf]);
                }
            }
            for (int jf = 1; jf < nf - 1; jf += 2)
            {
                for (int iif = 0; iif < nf; iif++)
                {
                    uf[iif, jf] = 0.5 * (uf[iif, jf + 1] + uf[iif, jf - 1]);
                }
            }
        }

        public double anorm2(double[,] a)
        {
            double sum = 0.0;
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    sum += a[i, j] * a[i, j];
                }
            }
            return Math.Sqrt(sum) / n;
        }


        public void mg(int j, double[,] u, double[,] rhs, List rho, ref double trerr)
        {
            const int NPRE = 1;
            const int NPOST = 1;
            const double ALPHA = 0.33;

            double dum = -1.0;
            int nf = u.GetLength(0);
            int nc = (nf + 1) / 2;
            double[,] temp = new double[nf, nf];
            if (j == 0)
            {
                matadd(rhs, rho[j],  temp);
                slvsm2( u, temp);
            }
            else
            {
                double[,] v = new double[nc, nc];
                double[,] ut = new double[nc, nc];
                double[,] tau = new double[nc, nc];
                double[,] tempc = new double[nc, nc];
                for (int jpre = 0; jpre < NPRE; jpre++)
                {
                    if (trerr < 0.0)
                    {
                        matadd(rhs, rho[j],  temp);
                        relax2( u, temp);
                    }
                    else
                    {
                        relax2( u, rho[j]);
                    }
                }
                rstrct( ut, u);
                v = Globals.CopyFrom(ut);
                lop( tau, ut);
                lop( temp, u);
                if (trerr < 0.0)
                {
                    matsub(temp, rhs,  temp);
                }
                rstrct( tempc, temp);
                matsub(tau, tempc,  tau);
                if (trerr > 0.0)
                {
                    trerr = ALPHA * anorm2(tau);
                }
                mg(j - 1,  v, tau, rho, ref dum);
                matsub(v, ut,  tempc);
                interp( temp, tempc);
                matadd(u, temp,  u);
                for (int jpost = 0; jpost < NPOST; jpost++)
                {
                    if (trerr < 0.0)
                    {
                        matadd(rhs, rho[j],  temp);
                        relax2( u, temp);
                    }
                    else
                    {
                        relax2( u, rho[j]);
                    }
                }
            }
        }
    }
}
 

2 代码格式

using System;
using System.Collections.Generic;

namespace Legalsoft.Truffer
{
    public class Mgfas
    {
        public int n { get; set; }
        public int ng { get; set; }
        public double[,] uj;
        public double[,] uj1 { get; set; }
        public List rho { get; set; } = new List();

        public Mgfas(double[,] u, int maxcyc)
        {
            this.n = u.GetLength(0);
            this.ng = 0;
            int nn = n;
            while ((nn >>= 1) != 0)
            {
                ng++;
            }
            if ((n - 1) != (1 << ng))
            {
                throw new Exception("n-1 must be a power of 2 in mgfas.");
            }
            nn = n;
            int ngrid = ng - 1;
            rho = new List(ng);
            //rho.resize(ng);
            rho[ngrid] = new double[nn, nn];
            rho[ngrid] = u;
            while (nn > 3)
            {
                nn = nn / 2 + 1;
                rho[--ngrid] = new double[nn, nn];

                //rstrct(ref rho[ngrid], rho[ngrid + 1]);
                double[,] tmp = rho[ngrid];
                rstrct( tmp, rho[ngrid + 1]);
                //rho[ngrid] = new double[,](tmp);
                rho[ngrid] = Globals.CopyFrom(tmp);
            }
            nn = 3;
            uj = new double[nn, nn];
            slvsm2( uj, rho[0]);
            for (int j = 1; j < ng; j++)
            {
                nn = 2 * nn - 1;
                uj1 = uj;
                uj = new double[nn, nn];
                double[,] temp = new double[nn, nn];
                interp( uj, uj1);
                uj1 = null;
                for (int jcycle = 0; jcycle < maxcyc; jcycle++)
                {
                    double trerr = 1.0;
                    mg(j, uj, temp, rho, ref trerr);
                    lop( temp, uj);
                    matsub(temp, rho[j],  temp);
                    double res = anorm2(temp);
                    if (res < trerr)
                    {
                        break;
                    }
                }
            }
            u = uj;
        }

        public void matadd(double[,] a, double[,] b, double[,] c)
        {
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    c[i, j] = a[i, j] + b[i, j];
                }
            }
        }

        public void matsub(double[,] a, double[,] b, double[,] c)
        {
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    c[i, j] = a[i, j] - b[i, j];
                }
            }
        }

        public void slvsm2(double[,] u, double[,] rhs)
        {
            double h = 0.5;
            for (int i = 0; i < 3; i++)
            {
                for (int j = 0; j < 3; j++)
                {
                    u[i, j] = 0.0;
                }
            }
            double fact = 2.0 / (h * h);
            double disc = Math.Sqrt(fact * fact + rhs[1, 1]);
            u[1, 1] = -rhs[1, 1] / (fact + disc);
        }

        public void relax2(double[,] u, double[,] rhs)
        {
            int n = u.GetLength(0);
            int jsw = 1;
            double h = 1.0 / (n - 1);
            double h2i = 1.0 / (h * h);
            double foh2 = -4.0 * h2i;
            for (int ipass = 0; ipass < 2; ipass++, jsw = 3 - jsw)
            {
                int isw = jsw;
                for (int j = 1; j < n - 1; j++, isw = 3 - isw)
                {
                    for (int i = isw; i < n - 1; i += 2)
                    {
                        double res = h2i * (u[i + 1, j] + u[i - 1, j] + u[i, j + 1] + u[i, j - 1] - 4.0 * u[i, j]) + u[i, j] * u[i, j] - rhs[i, j];
                        u[i, j] -= res / (foh2 + 2.0 * u[i, j]);
                    }
                }
            }
        }

        public void rstrct(double[,] uc, double[,] uf)
        {
            int nc = uc.GetLength(0);
            int ncc = 2 * nc - 2;
            for (int jf = 2, jc = 1; jc < nc - 1; jc++, jf += 2)
            {
                for (int iif = 2, ic = 1; ic < nc - 1; ic++, iif += 2)
                {
                    uc[ic, jc] = 0.5 * uf[iif, jf] + 0.125 * (uf[iif + 1, jf] + uf[iif - 1, jf] + uf[iif, jf + 1] + uf[iif, jf - 1]);
                }
            }
            for (int jc = 0, ic = 0; ic < nc; ic++, jc += 2)
            {
                uc[ic, 0] = uf[jc, 0];
                uc[ic, nc - 1] = uf[jc, ncc];
            }
            for (int jc = 0, ic = 0; ic < nc; ic++, jc += 2)
            {
                uc[0, ic] = uf[0, jc];
                uc[nc - 1, ic] = uf[ncc, jc];
            }
        }


        public void lop(double[,] xout, double[,] u)
        {
            int n = u.GetLength(0);
            double h = 1.0 / (n - 1);
            double h2i = 1.0 / (h * h);
            for (int j = 1; j < n - 1; j++)
            {
                for (int i = 1; i < n - 1; i++)
                {
                    xout[i, j] = h2i * (u[i + 1, j] + u[i - 1, j] + u[i, j + 1] + u[i, j - 1] - 4.0 * u[i, j]) + u[i, j] * u[i, j];
                }
            }
            for (int i = 0; i < n; i++)
            {
                xout[i, 0] = xout[i, n - 1] = xout[0, i] = xout[n - 1, i] = 0.0;
            }
        }

        public void interp(double[,] uf, double[,] uc)
        {
            int nf = uf.GetLength(0);
            int nc = nf / 2 + 1;
            for (int jc = 0; jc < nc; jc++)
            {
                for (int ic = 0; ic < nc; ic++)
                {
                    uf[2 * ic, 2 * jc] = uc[ic, jc];
                }
            }
            for (int jf = 0; jf < nf; jf += 2)
            {
                for (int iif = 1; iif < nf - 1; iif += 2)
                {
                    uf[iif, jf] = 0.5 * (uf[iif + 1, jf] + uf[iif - 1, jf]);
                }
            }
            for (int jf = 1; jf < nf - 1; jf += 2)
            {
                for (int iif = 0; iif < nf; iif++)
                {
                    uf[iif, jf] = 0.5 * (uf[iif, jf + 1] + uf[iif, jf - 1]);
                }
            }
        }

        public double anorm2(double[,] a)
        {
            double sum = 0.0;
            int n = a.GetLength(0);
            for (int j = 0; j < n; j++)
            {
                for (int i = 0; i < n; i++)
                {
                    sum += a[i, j] * a[i, j];
                }
            }
            return Math.Sqrt(sum) / n;
        }


        public void mg(int j, double[,] u, double[,] rhs, List rho, ref double trerr)
        {
            const int NPRE = 1;
            const int NPOST = 1;
            const double ALPHA = 0.33;

            double dum = -1.0;
            int nf = u.GetLength(0);
            int nc = (nf + 1) / 2;
            double[,] temp = new double[nf, nf];
            if (j == 0)
            {
                matadd(rhs, rho[j],  temp);
                slvsm2( u, temp);
            }
            else
            {
                double[,] v = new double[nc, nc];
                double[,] ut = new double[nc, nc];
                double[,] tau = new double[nc, nc];
                double[,] tempc = new double[nc, nc];
                for (int jpre = 0; jpre < NPRE; jpre++)
                {
                    if (trerr < 0.0)
                    {
                        matadd(rhs, rho[j],  temp);
                        relax2( u, temp);
                    }
                    else
                    {
                        relax2( u, rho[j]);
                    }
                }
                rstrct( ut, u);
                v = Globals.CopyFrom(ut);
                lop( tau, ut);
                lop( temp, u);
                if (trerr < 0.0)
                {
                    matsub(temp, rhs,  temp);
                }
                rstrct( tempc, temp);
                matsub(tau, tempc,  tau);
                if (trerr > 0.0)
                {
                    trerr = ALPHA * anorm2(tau);
                }
                mg(j - 1,  v, tau, rho, ref dum);
                matsub(v, ut,  tempc);
                interp( temp, tempc);
                matadd(u, temp,  u);
                for (int jpost = 0; jpost < NPOST; jpost++)
                {
                    if (trerr < 0.0)
                    {
                        matadd(rhs, rho[j],  temp);
                        relax2( u, temp);
                    }
                    else
                    {
                        relax2( u, rho[j]);
                    }
                }
            }
        }
    }
}

你可能感兴趣的:(C#数值计算,Numerical,Recipes,c#,算法,开发语言,人工智能,数值计算)