public FokkerPlanck(ModelConfig modelConfig,
                            Func <double, double> p_upper, Func <double, double> p_lower)
        {
            m_stepsX = modelConfig.Grid.StepsX;
            m_stepsT = modelConfig.Grid.StepsT;
            m_xMin   = modelConfig.Grid.XMin;
            m_xMax   = modelConfig.Grid.XMax;
            m_tMax   = modelConfig.Grid.TMax;
            m_dx     = modelConfig.Grid.Dx;
            m_dt     = modelConfig.Grid.Dt;

            m_drift     = modelConfig.Model.Drift;
            m_diffusion = modelConfig.Model.Diffusion;

            m_density = new double[m_stepsT][];

            m_t = new double[m_stepsT];

            for (int iTime = 0; iTime < m_stepsT; iTime++)
            {
                m_t[iTime] = iTime * m_dt;
            }

            m_x = new double[m_stepsX];

            for (int iStepX = 0; iStepX < m_stepsX; iStepX++)
            {
                m_x[iStepX] = m_xMin + iStepX * m_dx;
            }

            m_A      = new double[m_stepsT][];
            m_dAdX   = new double[m_stepsT][];
            m_d2AdX2 = new double[m_stepsT][];

            m_B    = new double[m_stepsT][];
            m_dBdx = new double[m_stepsT][];

            m_alpha = new double[m_stepsT][];
            m_beta  = new double[m_stepsT][];
            m_gamma = new double[m_stepsT][];

            m_a = new double[m_stepsT][];
            m_b = new double[m_stepsT][];
            m_c = new double[m_stepsT][];

            for (int iTime = 0; iTime < m_stepsT; iTime++)
            {
                m_density[iTime] = new double[m_stepsX];

                m_A[iTime]      = new double[m_stepsX + 2];
                m_dAdX[iTime]   = new double[m_stepsX];
                m_d2AdX2[iTime] = new double[m_stepsX];

                m_B[iTime]    = new double[m_stepsX + 2];
                m_dBdx[iTime] = new double[m_stepsX];

                m_alpha[iTime] = new double[m_stepsX];
                m_beta[iTime]  = new double[m_stepsX];
                m_gamma[iTime] = new double[m_stepsX];

                m_a[iTime] = new double[m_stepsX];
                m_b[iTime] = new double[m_stepsX];
                m_c[iTime] = new double[m_stepsX];
            }

            for (int iStepX = 0; iStepX < m_stepsX; iStepX++)
            {
                m_density[0][iStepX] = modelConfig.P_0(m_xMin + iStepX * m_dx);
            }

            for (int iTime = 0; iTime < m_stepsT; iTime++)
            {
                m_density[iTime][m_stepsX - 1] = p_upper(iTime * m_dt);
            }

            for (int iTime = 0; iTime < m_stepsT; iTime++)
            {
                m_density[iTime][0] = p_lower(iTime * m_dt);
            }

            for (int iTime = 0; iTime < m_stepsT; iTime++)
            {
                for (int iStepX = 0; iStepX < m_stepsX + 2; iStepX++)
                {
                    m_A[iTime][iStepX] = m_diffusion(new double[] { iTime *m_dt, m_xMin + (iStepX - 1) * m_dx });
                    m_B[iTime][iStepX] = m_drift(new double[] { iTime *m_dt, m_xMin + iStepX *m_dx });
                }
            }
        }