예제 #1
0
        public void ElementBasedMesh()
        {
            SpatialMesh mesh = CreateMesh(false);

            SpatialMeshWrapper wrapper = new SpatialMeshWrapper(mesh);

            Assert.AreEqual(ElementType.Polygon, wrapper.ElementType);
            Assert.AreEqual(14, wrapper.ElementCount);

            Assert.AreEqual(4, wrapper.GetVertexCount(0));
            Assert.AreEqual(3, wrapper.GetVertexCount(1));

            Assert.AreEqual(0, wrapper.GetVertexXCoordinate(0, 0));
            Assert.AreEqual(5, wrapper.GetVertexYCoordinate(0, 0));
            Assert.AreEqual(1, wrapper.GetVertexXCoordinate(0, 1));
            Assert.AreEqual(3, wrapper.GetVertexYCoordinate(0, 1));
            Assert.AreEqual(3, wrapper.GetVertexXCoordinate(0, 2));
            Assert.AreEqual(4, wrapper.GetVertexYCoordinate(0, 2));
            Assert.AreEqual(2, wrapper.GetVertexXCoordinate(0, 3));
            Assert.AreEqual(6, wrapper.GetVertexYCoordinate(0, 3));

            Assert.AreEqual(1, wrapper.GetVertexXCoordinate(13, 0));
            Assert.AreEqual(3, wrapper.GetVertexYCoordinate(13, 0));
            Assert.AreEqual(2, wrapper.GetVertexXCoordinate(13, 1));
            Assert.AreEqual(1, wrapper.GetVertexYCoordinate(13, 1));
            Assert.AreEqual(3, wrapper.GetVertexXCoordinate(13, 2));
            Assert.AreEqual(4, wrapper.GetVertexYCoordinate(13, 2));
        }
예제 #2
0
        public void NodeBasedMesh()
        {
            SpatialMesh mesh = CreateMesh(true);

            SpatialMeshWrapper wrapper = new SpatialMeshWrapper(mesh);

            Assert.AreEqual(ElementType.Point, wrapper.ElementType);
            Assert.AreEqual(13, wrapper.ElementCount);

            Assert.AreEqual(1, wrapper.GetVertexCount(0));
            Assert.AreEqual(1, wrapper.GetVertexCount(1));
            Assert.AreEqual(1, wrapper.GetVertexCount(12));

            Assert.AreEqual(0, wrapper.GetVertexXCoordinate(0, 0));
            Assert.AreEqual(5, wrapper.GetVertexYCoordinate(0, 0));

            Assert.AreEqual(7, wrapper.GetVertexXCoordinate(12, 0));
            Assert.AreEqual(4, wrapper.GetVertexYCoordinate(12, 0));
        }
예제 #3
0
        public void ToMatlabScript()
        {
            SpatialMesh mesh = CreateMesh(true);

            Console.Out.WriteLine("Nodes = [");
            foreach (ICoordinate node in mesh.Nodes)
            {
                Console.Out.WriteLine("{0}, {1}, {2}", node.X, node.Y, node.Z);
            }
            Console.Out.WriteLine("];");

            Console.Out.WriteLine("Elmts = [");
            foreach (int[] elmtNodes in mesh.Connectivity)
            {
                int count = 0;
                foreach (int nodeIndex in elmtNodes)
                {
                    if (count > 0)
                    {
                        Console.Out.Write(", ");
                    }
                    Console.Out.Write("{0}", nodeIndex + 1);
                    count++;
                }
                while (count < 4)
                {
                    Console.Out.Write(", 0");
                    count++;
                }
                Console.Out.WriteLine("");
            }
            Console.Out.WriteLine("];");
            // The following prints out code that will plot the mesh
            // outline, including the quadrilateral.
            Console.Out.WriteLine("I4       = (Elmts(:,4) > 0);");
            Console.Out.WriteLine("NI       = Elmts(:,[1 2 3 1 1]);");
            Console.Out.WriteLine("NI(I4,:) = Elmts(I4,[1 2 3 4 1]);");
            Console.Out.WriteLine("NI       = NI';");
            Console.Out.WriteLine("X = Nodes(:,1);");
            Console.Out.WriteLine("Y = Nodes(:,2);");
            Console.Out.WriteLine("Z = Nodes(:,3);");
            Console.Out.WriteLine("patch(X(NI),Y(NI),Z(NI));");
        }
예제 #4
0
        /// <summary>
        /// convert triangular mesh to a square mesh
        /// </summary>
        /// <param name="smesh">spatial mesh</param>
        /// <param name="x">x coordinates</param>
        /// <param name="y">y coordinates</param>
        /// <param name="uxy">grid location</param>
        /// <param name="inten">average intensity of each traingle</param>
        /// <param name="nxy">total points</param>
        public static void SquareTriMeshToGrid(ref SpatialMesh smesh, ref double[] x, ref double[] y, ref double[][] uxy, double[] inten, int nxy)
        {
            int    i, j, k;
            int    np, nt;
            double dx, dy;

            int[][]    tn;
            double[][] a12;
            double[][] a13;
            double[]   a2 = new double[2];
            double[]   a3 = new double[2];
            double[]   b2 = new double[2];
            double[]   b3 = new double[2];
            double     d2, d3;

            double[] r1p = new double[2];

            double xmin, xmax, zmin, zmax;
            double temp;
            double tiny = 2.2204e-12;

            double[] xminArray;
            double[] xmaxArray;
            double[] zminArray;
            double[] zmaxArray;

            int[] idxxminArray;
            int[] idxxmaxArray;
            int[] idxzminArray;
            int[] idxzmaxArray;

            // Assign large number for min and small number for max
            xmin = 1e10; xmax = -1e10; zmin = 1e10; zmax = -1e10;

            np = smesh.Np;
            nt = smesh.Nt;

            for (i = 0; i < np; i++)
            {
                xmin = Math.Min(smesh.P[i][0], xmin);
                xmax = Math.Max(smesh.P[i][0], xmax);
                zmin = Math.Min(smesh.P[i][1], zmin);
                zmax = Math.Max(smesh.P[i][1], zmax);
            }

            dx = (xmax - xmin) / (nxy - 1);
            dy = (zmax - zmin) / (nxy - 1);

            for (i = 0; i < nxy; i++)
            {
                x[i] = xmin + i * dx;
                y[i] = zmin + i * dy;
            }

            xminArray = new double[nt];
            xmaxArray = new double[nt];
            zminArray = new double[nt];
            zmaxArray = new double[nt];

            idxxminArray = new int[nt];
            idxxmaxArray = new int[nt];
            idxzminArray = new int[nt];
            idxzmaxArray = new int[nt];

            for (i = 0; i < nt; i++)
            {
                xmin = 1e10; xmax = -1e10; zmin = 1e10; zmax = -1e10;

                xmin = Math.Min(smesh.P[smesh.T[i][0]][0], xmin);
                xmin = Math.Min(smesh.P[smesh.T[i][1]][0], xmin);
                xmin = Math.Min(smesh.P[smesh.T[i][2]][0], xmin);

                xmax = Math.Max(smesh.P[smesh.T[i][0]][0], xmax);
                xmax = Math.Max(smesh.P[smesh.T[i][1]][0], xmax);
                xmax = Math.Max(smesh.P[smesh.T[i][2]][0], xmax);

                zmin = Math.Min(smesh.P[smesh.T[i][0]][1], zmin);
                zmin = Math.Min(smesh.P[smesh.T[i][1]][1], zmin);
                zmin = Math.Min(smesh.P[smesh.T[i][2]][1], zmin);

                zmax = Math.Max(smesh.P[smesh.T[i][0]][1], zmax);
                zmax = Math.Max(smesh.P[smesh.T[i][1]][1], zmax);
                zmax = Math.Max(smesh.P[smesh.T[i][2]][1], zmax);

                xminArray[i] = xmin;
                xmaxArray[i] = xmax;
                zminArray[i] = zmin;
                zmaxArray[i] = zmax;

                idxxminArray[i] = i;
                idxxmaxArray[i] = i;
                idxzminArray[i] = i;
                idxzmaxArray[i] = i;
            }

            QuickSort(xminArray, idxxminArray, 0, nt - 1);
            QuickSort(xmaxArray, idxxmaxArray, 0, nt - 1);
            QuickSort(zminArray, idxzminArray, 0, nt - 1);
            QuickSort(zmaxArray, idxzmaxArray, 0, nt - 1);

            j = 0;
            for (i = 0; i < nt; i++)
            {
                if (j < nxy)
                {
                    while (x[j] < xminArray[i])
                    {
                        j++;
                        if (j >= nxy)
                        {
                            break;
                        }
                    }
                }
                xminArray[i] = j;
            }

            j = nxy - 1;
            for (i = nt - 1; i >= 0; i--)
            {
                if (j >= 0)
                {
                    while (x[j] > xmaxArray[i])
                    {
                        j--;
                        if (j < 0)
                        {
                            break;
                        }
                    }
                }
                xmaxArray[i] = j;
            }


            j = 0;
            for (i = 0; i < nt; i++)
            {
                if (j < nxy)
                {
                    while (y[j] < zminArray[i])
                    {
                        j++;
                        if (j >= nxy)
                        {
                            break;
                        }
                    }
                }
                zminArray[i] = j;
            }

            j = nxy - 1;
            for (i = nt - 1; i >= 0; i--)
            {
                if (j >= 0)
                {
                    while (y[j] > zmaxArray[i])
                    {
                        j--;
                        if (j < 0)
                        {
                            break;
                        }
                    }
                }
                zmaxArray[i] = j;
            }

            RearrangeArray(ref xminArray, idxxminArray, nt);
            RearrangeArray(ref xmaxArray, idxxmaxArray, nt);
            RearrangeArray(ref zminArray, idxzminArray, nt);
            RearrangeArray(ref zmaxArray, idxzmaxArray, nt);


            tn  = new int[nxy][];
            a12 = new double[nxy][];
            a13 = new double[nxy][];
            for (i = 0; i < nxy; i++)
            {
                tn[i]  = new int[nxy];
                a12[i] = new double[nxy];
                a13[i] = new double[nxy];
            }

            //Set tn to a non positive number
            for (i = 0; i < nxy; i++)
            {
                for (j = 0; j < nxy; j++)
                {
                    tn[i][j] = -1;
                }
            }


            for (i = 0; i < nt; i++)
            {
                if ((xminArray[i] <= xmaxArray[i]) && (zminArray[i] <= zmaxArray[i]))
                {
                    for (j = 0; j < 2; j++)
                    {
                        a2[j] = smesh.P[smesh.T[i][1]][j] - smesh.P[smesh.T[i][0]][j];
                        a3[j] = smesh.P[smesh.T[i][2]][j] - smesh.P[smesh.T[i][0]][j];
                    }

                    temp  = a2[0] * a3[1] - a2[1] * a3[0];
                    b2[0] = a3[1] / temp;
                    b2[1] = -a3[0] / temp;
                    b3[0] = -a2[1] / temp;
                    b3[1] = a2[0] / temp;

                    for (j = (int)xminArray[i]; j <= (int)xmaxArray[i]; j++)
                    {
                        for (k = (int)zminArray[i]; k <= (int)zmaxArray[i]; k++)
                        {
                            if (tn[k][j] == -1)
                            {
                                r1p[0] = x[j] - smesh.P[smesh.T[i][0]][0];
                                r1p[1] = y[k] - smesh.P[smesh.T[i][0]][1];
                                d2     = b2[0] * r1p[0] + b2[1] * r1p[1];
                                if ((d2 >= -tiny) && (d2 <= 1 + tiny))
                                {
                                    d3 = b3[0] * r1p[0] + b3[1] * r1p[1];
                                    if ((d3 >= -tiny) && (d2 + d3 <= 1 + tiny))
                                    {
                                        tn[k][j]  = i;
                                        a12[k][j] = d2;
                                        a13[k][j] = d3;
                                    }
                                }
                            }
                        }
                    }
                }
            }


            double tt1, tt2, tt3;

            for (i = 0; i < nxy; i++)
            {
                for (j = 0; j < nxy; j++)
                {
                    tt1       = (1 - a12[i][j] - a13[i][j]) * inten[(int)smesh.T[tn[i][j]][0]];
                    tt2       = a12[i][j] * inten[(int)smesh.T[tn[i][j]][1]];
                    tt3       = a13[i][j] * inten[(int)smesh.T[tn[i][j]][2]];
                    uxy[i][j] = tt1 + tt2 + tt3;
                }
            }
        }
예제 #5
0
        public Measurement RteOutput(double[][][] flux, double[][][] q, AngularMesh amesh, SpatialMesh smesh, BoundaryCoupling b, int vacuum)

        {
            int i, j, k;
            int nxy;

            int[][] t;
            int     nt = smesh.Nt, ns = amesh.Ns, np = smesh.Np;
            double  dtheta = 2 * Pi / ns;

            t = smesh.T;

            Measurement Det = new Measurement();


            nxy = (int)Math.Ceiling(Math.Sqrt(nt / 2.0)) + 1;

            Det.fluence = new double[np];

            Det.radiance = new double[np][];
            for (i = 0; i < np; i++)
            {
                Det.radiance[i] = new double[ns];
            }

            Det.uxy = new double[nxy][];
            for (i = 0; i < nxy; i++)
            {
                Det.uxy[i] = new double[nxy];
            }

            Det.xloc  = new double[nxy];
            Det.zloc  = new double[nxy];
            Det.dx    = new double[nxy];
            Det.dz    = new double[nxy];
            Det.inten = new double[nxy * nxy];


            // compute radiance at each node
            for (i = 0; i < nt; i++)
            {
                for (j = 0; j < ns; j++)
                {
                    for (k = 0; k < 3; k++)
                    {
                        Det.radiance[t[i][k]][j] = flux[j][i][k];
                    }
                }
            }

            // compute fluence at each node
            for (i = 0; i < np; i++)
            {
                Det.fluence[i] = 0;
                for (j = 0; j < ns; j++)
                {
                    Det.fluence[i] += Det.radiance[i][j];
                }
                Det.fluence[i] *= dtheta;
            }

            MathFunctions.SquareTriMeshToGrid(ref smesh, ref Det.xloc, ref Det.zloc, ref Det.uxy, Det.fluence, nxy);

            for (i = 0; i < nxy; i++)
            {
                for (j = 0; j < nxy; j++)
                {
                    Det.inten[i * nxy + j] = Det.uxy[i][j];
                }
            }

            for (i = 0; i < nxy; i++)
            {
                Det.dx[i] = Det.xloc[1] - Det.xloc[0];
                Det.dz[i] = Det.zloc[1] - Det.zloc[0];
            }



            return(Det);
        }
예제 #6
0
        /// <summary>
        /// Execute MG RTE solver
        /// </summary>
        /// <param name="input">Simulation inputs</param>
        /// <returns>measurements</returns>
        public static Measurement ExecuteMGRTE(SimulationInput input)
        {
            int    nMismatch;
            int    i, j, k, m, n;
            int    level;
            double res = 0, res0 = 1, rho = 1.0;
            int    ds = input.MeshDataInput.SMeshLevel - input.SimulationOptionsInput.StartingSmeshLevel;
            int    da = input.MeshDataInput.AMeshLevel - input.SimulationOptionsInput.StartingAmeshLevel;


            /* Read the initial time. */
            DateTime startTime1 = DateTime.Now;
            ILogger  logger     = LoggerFactoryLocator.GetDefaultNLogFactory().Create(typeof(SolverMGRTE));

            //  step 1: compute "level"
            //  level: the indicator of mesh levels in multigrid
            switch (input.SimulationOptionsInput.MethodMg)
            {
            case 1:
                level = da;
                break;

            case 2:     //SMG:
                level = ds;
                break;

            case 3:     //MG1:
                level = Math.Max(da, ds);
                break;

            case 4:     //MG2:
                level = ds + da;
                break;

            case 5:     //MG3:
                level = ds + da;
                break;

            case 6:     //MG4_a:
                level = ds + da;
                break;

            case 7:     //MG4_s:
                level = ds + da;
                break;

            default:
                level = -1;
                break;
            }


            //Create Dynamic arrays based on above values
            var amesh = new AngularMesh[input.MeshDataInput.AMeshLevel + 1];
            var smesh = new SpatialMesh[input.MeshDataInput.SMeshLevel + 1];
            var b     = new BoundaryCoupling[level + 1];

            var noflevel = new int[level + 1][];
            var ua       = new double[input.MeshDataInput.SMeshLevel + 1][][];
            var us       = new double[input.MeshDataInput.SMeshLevel + 1][][];
            var rhs      = new double[level + 1][][][];
            var d        = new double[level + 1][][][];
            var flux     = new double[level + 1][][][];
            var q        = new double[level + 1][][][];

            var mgrid  = new MultiGridCycle();
            var rteout = new OutputCalculation();

            var tissueInput = (MultiEllipsoidTissueInput)input.TissueInput;
            int incRegions  = tissueInput.EllipsoidRegions.Length;
            int tisRegions  = tissueInput.LayerRegions.Length;

            double depth = 0.0;

            for (i = 1; i < tissueInput.LayerRegions.Length - 1; i++)
            {
                depth += ((LayerTissueRegion)(tissueInput.LayerRegions[i])).ZRange.Stop - ((LayerTissueRegion)(tissueInput.LayerRegions[i])).ZRange.Start;
            }

            input.MeshDataInput.SideLength = depth;
            int totRegions = incRegions + tisRegions;

            //   MG-RTE does not converge when g = 1.0;
            for (i = 0; i < totRegions; i++)
            {
                if (input.TissueInput.Regions[i].RegionOP.G >= 1.0)
                {
                    input.TissueInput.Regions[i].RegionOP.G = 1.0 - 1e-5;
                }
            }

            // Check refractive index mismatch
            if (Math.Abs(input.TissueInput.Regions[0].RegionOP.N - input.TissueInput.Regions[1].RegionOP.N)
                / input.TissueInput.Regions[0].RegionOP.N < 0.01) // refraction index mismatch at the boundary
            {
                nMismatch = 1;
            }
            else
            {
                nMismatch = 0;
            }


            //Create spatial and angular mesh
            MathFunctions.CreateSquareMesh(ref smesh, input.MeshDataInput.SMeshLevel, depth);
            MathFunctions.AssignRegions(ref smesh, input.MeshDataInput.SMeshLevel, tissueInput);
            MathFunctions.CreateAnglularMesh(ref amesh, input.MeshDataInput.AMeshLevel, tissueInput);


            MathFunctions.SweepOrdering(ref smesh, amesh, input.MeshDataInput.SMeshLevel, input.MeshDataInput.AMeshLevel);
            MathFunctions.SetMus(ref us, smesh, input);
            MathFunctions.SetMua(ref ua, smesh, input);

            // load optical property, angular mesh, and spatial mesh files
            Initialization.Initial(
                ref amesh, ref smesh, ref flux, ref d,
                ref rhs, ref q, ref noflevel, ref b,
                level, input.SimulationOptionsInput.MethodMg, nMismatch, input.SimulationOptionsInput.NExternal,
                input.SimulationOptionsInput.NExternal, input.MeshDataInput.AMeshLevel, input.SimulationOptionsInput.StartingAmeshLevel,
                input.MeshDataInput.SMeshLevel, input.SimulationOptionsInput.StartingSmeshLevel, ua, us, mgrid);

            //Assign external source if available
            if (input.ExtSourceInput != null)
            {
                IExtSource extsource = FemSourceFactory.GetExtSource(input.ExtSourceInput);
                extsource.AssignMeshForExtSource(amesh, input.MeshDataInput.AMeshLevel, smesh, input.MeshDataInput.SMeshLevel, level, q);
            }

            //Assign internal source if available
            if (input.IntSourceInput != null)
            {
                //Assign an internal source
                IIntSource intsource = FemSourceFactory.GetIntSource(input.IntSourceInput);
                intsource.AssignMeshForIntSource(amesh, input.MeshDataInput.AMeshLevel, smesh, input.MeshDataInput.SMeshLevel, level, rhs);
            }

            /* Read the end time. */
            DateTime stopTime1 = DateTime.Now;
            /* Compute and print the duration of this first task. */
            TimeSpan duration1 = stopTime1 - startTime1;

            logger.Info(() => "Initlalization for RTE_2D takes " + duration1.TotalSeconds + " seconds\n");

            //step 2: RTE solver
            DateTime startTime2 = DateTime.Now;

            int ns = amesh[input.MeshDataInput.AMeshLevel].Ns;


            if (input.SimulationOptionsInput.FullMg == 1)
            {
                int nt1, ns1;
                int nt2 = smesh[noflevel[level][0]].Nt;
                int ns2 = amesh[noflevel[level][1]].Ns;

                for (n = level - 1; n >= 0; n--)
                {
                    nt1 = smesh[noflevel[n][0]].Nt;
                    ns1 = amesh[noflevel[n][1]].Ns;
                    if (nt1 == nt2)
                    {
                        mgrid.FtoC_a(nt1, ns1, rhs[n + 1], rhs[n]);
                    }
                    else
                    {
                        if (ns1 == ns2)
                        {
                            mgrid.FtoC_s(nt1, ns1, rhs[n + 1], rhs[n], smesh[noflevel[n][0] + 1].Smap, smesh[noflevel[n][0] + 1].Fc);
                        }
                        else
                        {
                            mgrid.FtoC(nt1, ns1, rhs[n + 1], rhs[n], smesh[noflevel[n][0] + 1].Smap, smesh[noflevel[n][0] + 1].Fc);
                        }
                    }
                    nt2 = nt1; ns2 = ns1;
                }

                nt1 = smesh[noflevel[0][0]].Nt;
                ns1 = amesh[noflevel[0][1]].Ns;

                for (n = 0; n < level; n++)
                {
                    if (input.SimulationOptionsInput.MethodMg == 6)
                    {
                        if (((level - n) % 2) == 0)
                        {
                            for (i = 0; i < input.SimulationOptionsInput.NCycle; i++)
                            {
                                res = mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations,
                                                    noflevel[n][1], input.SimulationOptionsInput.StartingAmeshLevel, noflevel[n][0], input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch, 6);
                            }
                        }
                        else
                        {
                            for (i = 0; i < input.SimulationOptionsInput.NCycle; i++)
                            {
                                mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations,
                                              noflevel[n][1], input.SimulationOptionsInput.StartingAmeshLevel, noflevel[n][0], input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch, 7);
                            }
                        }
                    }
                    else
                    {
                        if (input.SimulationOptionsInput.MethodMg == 7)
                        {
                            if (((level - n) % 2) == 0)
                            {
                                for (i = 0; i < input.SimulationOptionsInput.NCycle; i++)
                                {
                                    mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations,
                                                  noflevel[n][1], input.SimulationOptionsInput.StartingAmeshLevel, noflevel[n][0], input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch, 7);
                                }
                            }
                            else
                            {
                                for (i = 0; i < input.SimulationOptionsInput.NCycle; i++)
                                {
                                    mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations,
                                                  noflevel[n][1], input.SimulationOptionsInput.StartingAmeshLevel, noflevel[n][0], input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch, 6);
                                }
                            }
                        }
                        else
                        {
                            for (i = 0; i < input.SimulationOptionsInput.NCycle; i++)
                            {
                                mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations,
                                              noflevel[n][1], input.SimulationOptionsInput.StartingAmeshLevel, noflevel[n][0], input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch,
                                              input.SimulationOptionsInput.MethodMg);
                            }
                        }
                    }

                    nt2 = smesh[noflevel[n + 1][0]].Nt;
                    ns2 = amesh[noflevel[n + 1][1]].Ns;
                    if (nt1 == nt2)
                    {
                        mgrid.CtoF_a(nt1, ns1, flux[n + 1], flux[n]);
                    }
                    else
                    {
                        if (ns1 == ns2)
                        {
                            mgrid.CtoF_s(nt1, ns1, flux[n + 1], flux[n], smesh[noflevel[n][0] + 1].Smap, smesh[noflevel[n][0] + 1].Cf);
                        }
                        else
                        {
                            mgrid.CtoF(nt1, ns1, flux[n + 1], flux[n], smesh[noflevel[n][0] + 1].Smap, smesh[noflevel[n][0] + 1].Cf);
                        }
                    }
                    nt1 = nt2; ns1 = ns2;
                    for (m = 0; m <= n; m++)
                    {
                        for (i = 0; i < amesh[noflevel[m][1]].Ns; i++)
                        {
                            for (j = 0; j < smesh[noflevel[m][0]].Nt; j++)
                            {
                                for (k = 0; k < 3; k++)
                                {
                                    flux[m][i][j][k] = 0;
                                }
                            }
                        }
                    }
                }
            }

            // 2.2. multigrid solver on the finest mesh
            n = 0;

            while (n < input.SimulationOptionsInput.NIterations)
            {
                n++;
                res = mgrid.MgCycle(amesh, smesh, b, q, rhs, ua, us, flux, d, input.SimulationOptionsInput.NPreIterations, input.SimulationOptionsInput.NPostIterations, input.MeshDataInput.AMeshLevel,
                                    input.SimulationOptionsInput.StartingAmeshLevel, input.MeshDataInput.SMeshLevel, input.SimulationOptionsInput.StartingSmeshLevel, ns, nMismatch, input.SimulationOptionsInput.MethodMg);
                for (m = 0; m < level; m++)
                {
                    for (i = 0; i < amesh[noflevel[m][1]].Ns; i++)
                    {
                        for (j = 0; j < smesh[noflevel[m][0]].Nt; j++)
                        {
                            for (k = 0; k < 3; k++)
                            {
                                flux[m][i][j][k] = 0;
                            }
                        }
                    }
                }


                if (n > 1)
                {
                    rho *= res / res0;
                    logger.Info(() => "Iteration: " + n + ", Current tolerance: " + res + "\n");

                    if (res < input.SimulationOptionsInput.ConvTolerance)
                    {
                        rho = Math.Pow(rho, 1.0 / (n - 1));
                        n   = input.SimulationOptionsInput.NIterations;
                    }
                }
                else
                {
                    logger.Info(() => "Iteration: " + n + ", Current tolerance: " + res + "\n");
                    res0 = res;
                    if (res < input.SimulationOptionsInput.ConvTolerance)
                    {
                        n = input.SimulationOptionsInput.NIterations;
                    }
                }
            }

            // 2.3. compute the residual
            //Mgrid.Defect(amesh[para.AMeshLevel], smesh[para.SMeshLevel], ns, RHS[level], ua[para.SMeshLevel], us[para.SMeshLevel],
            //    flux[level], b[level], q[level], d[level], vacuum);
            //res = Mgrid.Residual(smesh[para.SMeshLevel].nt, amesh[para.AMeshLevel].ns, d[level], smesh[para.SMeshLevel].a);

            /* Read the start time. */
            DateTime stopTime2 = DateTime.Now;
            TimeSpan duration2 = stopTime2 - startTime2;
            TimeSpan duration3 = stopTime2 - startTime1;

            logger.Info(() => "Iteration time: " + duration2.TotalSeconds + "seconds\n");
            logger.Info(() => "Total time: " + duration3.TotalSeconds + "seconds, Final residual: " + res + "\n");

            // step 3: postprocessing
            // 3.1. output
            Measurement measurement = rteout.RteOutput(flux[level], q[level], amesh[input.MeshDataInput.AMeshLevel], smesh[input.MeshDataInput.SMeshLevel], b[level], nMismatch);

            return(measurement);
        }