Esempio n. 1
0
        private static float[,] SolvePoissonNeimanMultiLattice(float[,] rho, int steps_max, float stop_dpd, SolutionReporter callback)
        {
            // Making lower resolutions
            int W = rho.GetLength(0);
            int H = rho.GetLength(1);

            List<int> ww = new List<int>();
            List<int> hh = new List<int>();

            int divides = 0, wt = W, ht = H;
            ww.Add(wt); hh.Add(ht);
            while (wt > 1 && ht > 1 && divides < 5)
            {
                wt /= 2; ht /= 2;
                ww.Add(wt); hh.Add(ht);
                divides ++;
            }

            List<float[,]> Rho = new List<float[,]>();
            Rho.Add(rho);

            for (int p = 1; p <= divides; p++)
            {
                int w = ww[p - 1];
                int h = hh[p - 1];

                float[,] rho_new = new float[ww[p], hh[p]];
                for (int i = 0; i < w; i++)
                for (int j = 0; j < h; j++)
                {
                    if (i / 2 < ww[p] && j / 2 < hh[p])
                        rho_new[i / 2, j / 2] += 0.25f * Rho[p - 1][i, j];
                }

                Rho.Add(rho_new);
            }

            float[,] I = new float[Rho[divides].GetLength(0), Rho[divides].GetLength(1)];
            float old_progress = 0;
            for (int p = divides; p >= 0; p--)
            {
                SolvePoissonNeiman(I, Rho[p], steps_max, stop_dpd, delegate (float progress, float[,] solution)
                {
                    if (callback != null)
                    {
                        float complete_effort = 0;
                        for (int q = divides; q > p; q--)
                            complete_effort += (float)ww[q] * hh[q];

                        float full_effort = complete_effort;
                        for (int q = p; q >= 0; q--)
                            full_effort += (float)ww[q] * hh[q];

                        float new_progress = (complete_effort + ww[p] * hh[p] * progress) / full_effort;
                        if (new_progress > old_progress) old_progress = new_progress;

                        callback(old_progress, solution);
                    }

                });

                if (p > 0)
                {
                    I = Upsample2(I, ww[p - 1], hh[p - 1]);
                }
            }

            return I;
        }
Esempio n. 2
0
        private static bool SolvePoissonNeiman(float[,] I0, float[,] rho, int steps_max, float stop_dpd, SolutionReporter callback)
        {
            int w = rho.GetLength(0), h = rho.GetLength(1);
            float[,] I = new float[w + 2, h + 2];
            float[,] Inew = new float[w + 2, h + 2];

            // Setting initial values
            for (int i = 0; i < w + 2; i++)
            for (int j = 0; j < h + 2; j++)
            {
                int i1 = i;
                if (i == 0) i1 = 1;
                if (i == w + 1) i1 = w;
                int j1 = j;
                if (j == 0) j1 = 1;
                if (j == h + 1) j1 = h;

                I[i, j] = I0[i1 - 1, j1 - 1];
                Inew[i, j] = I0[i1 - 1, j1 - 1];
            }

            float delta = 0; float delta_prev = 10000;
            object delta_lock = new object();
            for (int step = 0; step < steps_max; step ++)
            {
                // *** Horizontal iterations ***
                int threads_num = 6;
                Thread[] threads = new Thread[threads_num];

                for (int q = 0; q < threads_num; q++)
                {
                    threads[q] = new Thread(delegate (object obj)
                    {
                        int i1 = ((thread_data)obj).i1;
                        int i2 = ((thread_data)obj).i2;

                        float my_delta = 0;

                        for (int i = i1; i < i2; i++)
                        {
                            // Run, Thomas, run!
                            float[] alpha = new float[h + 3];
                            float[] beta = new float[h + 3];

                            alpha[1] = 0.25f; beta[1] = 0.25f * (I[i + 1, 0] + Inew[i - 1, 0]);
                            for (int j = 1; j < h + 2; j++)
                            {
                                alpha[j + 1] = 1.0f / (4 - alpha[j]);
                                float Fj;
                                if (j < h + 1)
                                    Fj = I[i + 1, j] + Inew[i - 1, j] - 2 * rho[i - 1, j - 1];
                                else
                                    Fj = I[i + 1, j] + Inew[i - 1, j];

                                beta[j + 1] = (Fj + beta[j]) / (4f - alpha[j]);
                            }

                            Inew[i, h + 1] = beta[h + 2];

                            for (int j = h; j >= 0; j--)
                            {
                                double iold = I[i, j];
                                Inew[i, j] = alpha[j + 1] * Inew[i, j + 1] + beta[j + 1];
                                my_delta += (float)Math.Abs(Inew[i, j] - iold);
                            }
                        }

                        lock (delta_lock)
                        {
                            delta += my_delta;
                        }

                    });
                }

                // Starting horizontal threads
                for (int q = 0; q < threads_num; q++)
                {
                    thread_data td = new thread_data();
                    td.i1 = (w / threads_num) * q + 1;
                    if (q < threads_num - 1)
                    {
                        td.i2 = (w / threads_num) * (q + 1) + 1;
                    }
                    else
                    {
                        td.i2 = w + 1;
                    }

                    threads[q].Start(td);
                }

                // Waiting for horizontal threads
                for (int q = 0; q < threads_num; q++)
                {
                    threads[q].Join();
                }

                // Restoring Neiman boundary conditions after horizontal iterations
                for (int i = 0; i < w + 2; i++)
                {
                    Inew[i, 0] = Inew[i, 1];
                    Inew[i, h + 1] = Inew[i, h];
                }
                for (int j = 0; j < h + 2; j++)
                {
                    Inew[0, j] = Inew[1, j];
                    Inew[w + 1, j] = Inew[w, j];
                }

                // Controlling the constant after horizontal iterations
                float m = 0;
                for (int i = 0; i < w + 2; i++)
                for (int j = 0; j < h + 2; j++)
                {
                    m += Inew[i, j];
                }
                m /= (w+2) * (h+2);

                for (int i = 0; i < w + 2; i++)
                for (int j = 0; j < h + 2; j++)
                {
                    I[i, j] = Inew[i, j] - m;
                }

                // *** Vertical iterations ***
                threads = new Thread[threads_num];

                for (int q = 0; q < threads_num; q++)
                {
                    threads[q] = new Thread(delegate (object obj)
                    {
                        int j1 = ((thread_data)obj).i1;
                        int j2 = ((thread_data)obj).i2;

                        float my_delta = 0;

                        for (int j = j1; j < j2; j++)
                        {
                            // Run, Thomas, run!
                            float[] alpha = new float[w + 3];
                            float[] beta = new float[w + 3];

                            alpha[1] = 0.25f; beta[1] = 0.25f * (I[0, j + 1] + Inew[0, j - 1]);
                            for (int i = 1; i < w + 2; i++)
                            {
                                alpha[i + 1] = 1.0f / (4 - alpha[i]);
                                float Fi;
                                if (i < w + 1)
                                    Fi = I[i, j + 1] + Inew[i, j - 1] - 2 * rho[i - 1, j - 1];
                                else
                                    Fi = I[i, j + 1] + Inew[i, j - 1];

                                beta[i + 1] = (Fi + beta[i]) / (4f - alpha[i]);
                            }

                            Inew[w + 1, j] = beta[w + 2];

                            for (int i = w; i >= 0; i--)
                            {
                                double iold = I[i, j];
                                Inew[i, j] = alpha[i + 1] * Inew[i + 1, j] + beta[i + 1];
                                my_delta += (float)Math.Abs(Inew[i, j] - iold);
                            }
                        }

                        lock (delta_lock)
                        {
                            delta += my_delta;
                        }

                    });
                }

                // Starting vertical threads
                for (int q = 0; q < threads_num; q++)
                {
                    thread_data td = new thread_data();
                    td.i1 = (h / threads_num) * q + 1;
                    if (q < threads_num - 1)
                    {
                        td.i2 = (h / threads_num) * (q + 1) + 1;
                    }
                    else
                    {
                        td.i2 = h + 1;
                    }

                    threads[q].Start(td);
                }

                // Waiting for vertical threads
                for (int q = 0; q < threads_num; q++)
                {
                    threads[q].Join();
                }

                // Restoring Neiman boundary conditions after vertical iterations
                for (int i = 0; i < w + 2; i++)
                {
                    Inew[i, 0] = Inew[i, 1];
                    Inew[i, h + 1] = Inew[i, h];
                }
                for (int j = 0; j < h + 2; j++)
                {
                    Inew[0, j] = Inew[1, j];
                    Inew[w + 1, j] = Inew[w, j];
                }

                // Controlling the constant after vertical iterations
                m = 0;
                for (int i = 0; i < w + 2; i++)
                for (int j = 0; j < h + 2; j++)
                {
                    m += Inew[i, j];
                }
                m /= (w+2) * (h+2);

                for (int i = 0; i < w + 2; i++)
                for (int j = 0; j < h + 2; j++)
                {
                    I[i, j] = Inew[i, j] - m;
                }

                for (int i = 1; i < w + 1; i++)
                for (int j = 1; j < h + 1; j++)
                {
                    I0[i - 1, j - 1] = I[i, j];
                }

                delta /= (float)Math.Sqrt(w * h);
                float dpd = Math.Abs((delta - delta_prev) / delta);

                // This formula is found experimentally
                float progress = (float)Math.Min(Math.Pow(stop_dpd / (dpd + 0.000001), 0.78), 0.999);

                if (callback != null)
                {
                    callback(progress, I0);
                }

                if (dpd < stop_dpd)
                {
                    return true;
                }
                delta_prev = delta;
                delta = 0;
            }

            return false;
        }