public void ejecutarEvapotranspiracion(ref DataSet dataSetSimulador)
        {
            dataSetSimulador.evaporacionEP = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            for (int x = 0; x < dataSetSimulador.anchoEjeX; x++)
            {
                for (int y = 0; y < dataSetSimulador.altoEjeY; y++)
                {
                    //Si hay agua superficial
                    if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] > 0.0)
                    {
                        //La evaporacion en ese punto se correspondera con el coeficiente de evaporacion.
                        //evaporacionEP.setValue(EP,x,y);
                        dataSetSimulador.evaporacionEP.matrizDEM_[y, x] = dataSetSimulador.coefEvaporacion;
                    }
                    //Si no hay agua superficial y la profundidad del suelo en ese punto no es nula
                    else if (dataSetSimulador.profundidadSuelos.matrizDEM_[y, x] > 0.0)
                    {
                        //La evaporacion en ese punto se traduce en:
                        dataSetSimulador.evaporacionEP.matrizDEM_[y, x] = dataSetSimulador.coefEvaporacion *
                               (dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] / dataSetSimulador.profundidadSuelos.matrizDEM_[y, x]);
                        //Que se corresponde con la formula extraida del doc referente a Wolski y Overton.
                        //Si no hay agua en la capa 1 la evaporacion queda en 0.
                    }
                }
            }
        }
 public ControlEjecucionProc(ConfParameters parametrosSimulacion, GUIModelEjecForm formEjec)
 {
     formPadre = formEjec;
     parametrosSimulador = parametrosSimulacion;
     dataSetSimulador = new DataSet(parametrosSimulacion);
     arrayOfMatrizFlowsEnX = new int[parametrosSimulador.escSupPasosNts + 1][,];
     arrayOfMatrizFlowsEnY = new int[parametrosSimulador.escSupPasosNts + 1][,];
     infiltradorVertical = new InfiltracionVertical();
     escurridorSuperficial = new EscurrimientoSuperficial();
     clusterizadorPlanchador = new ClusteringPlanchado();
     evaporador = new Evapotranspiracion();
     infiltradorHorizontal = new InfiltracionHorizontal();
 }
        public void ejecutarEscurrimientoSuperficial(ref DataSet dataSetSimulador, float dts)
        {
            float tempValue;

            //Se hace una copia de los datos que seran leidos para procesar. Ya que no acepta valores por referencia.
            DataSet copyDataSetSimulador = dataSetSimulador;

            //Se generan datos
            RasterDatos tempFlujoEnX = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);
            RasterDatos tempFlujoEnY = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            int anchoEjeX = dataSetSimulador.anchoEjeX;
            int altoEjeY = dataSetSimulador.altoEjeY;

            Parallel.Invoke(
                () =>
                {
                    tempFlujoEnX = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, 0, anchoEjeX, 0, altoEjeY);
                },  // close first Action

                () =>
                {
                    tempFlujoEnY = escurrimientoSuperficialEnY(copyDataSetSimulador, dts, 0, anchoEjeX, 0, altoEjeY);
                } //close second Action

            ); //close parallel.invoke

            dataSetSimulador.flujoEnXSuperficie = tempFlujoEnX;
            dataSetSimulador.flujoEnYSuperficie = tempFlujoEnY;

            /*
            dataSetSimulador.flujoEnXSuperficie = escurrimientoSuperficialEnX(dataSetSimulador, dts);
            dataSetSimulador.flujoEnYSuperficie = escurrimientoSuperficialEnY(dataSetSimulador, dts);*/

            dataSetSimulador.flujoResultanteSuperficie = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            for (int x = 1; x < dataSetSimulador.anchoEjeX - 1; x++)
            {
                for (int y = 1; y < dataSetSimulador.altoEjeY - 1; y++)
                {

                    tempValue = (float)((dataSetSimulador.flujoEnXSuperficie.matrizDEM_[y, x - 1] - dataSetSimulador.flujoEnXSuperficie.matrizDEM_[y, x]
                                        + dataSetSimulador.flujoEnYSuperficie.matrizDEM_[y - 1, x] - dataSetSimulador.flujoEnYSuperficie.matrizDEM_[y, x]) / Math.Pow(dataSetSimulador.dimensionCelda, 2.0));

                    dataSetSimulador.flujoResultanteSuperficie.matrizDEM_[y, x] = tempValue;
                }
            }
        }
        public void ejecutarInfiltracionHorizontal(ref DataSet dataSetSimulador)
        {
            float tempValue;

            dataSetSimulador.flujoResultanteCapaPerm = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            infiltracionHorizontalEnX(ref dataSetSimulador);

            infiltracionHorizontalEnY(ref dataSetSimulador);

            for (int x = 1; x < dataSetSimulador.anchoEjeX - 1; x++)
            {
                for (int y = 1; y < dataSetSimulador.altoEjeY - 1; y++)
                {
                    tempValue = (float)(dataSetSimulador.flujoResultanteCapaPerm.matrizDEM_[y, x] +
                                                    (dataSetSimulador.flujoEnXCapaPermeable.matrizDEM_[y, x - 1] - dataSetSimulador.flujoEnXCapaPermeable.matrizDEM_[y, x] +
                                                     dataSetSimulador.flujoEnYCapaPermeable.matrizDEM_[y - 1, x] - dataSetSimulador.flujoEnYCapaPermeable.matrizDEM_[y, x]) / Math.Pow(dataSetSimulador.dimensionCelda, 2.0));
                    dataSetSimulador.flujoResultanteCapaPerm.matrizDEM_[y, x] = tempValue;
                }
            }
        }
        private void infiltracionHorizontalEnY(ref DataSet dataSetSimulador)
        {
            float tempValue;
            dataSetSimulador.flujoEnYCapaPermeable = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            for (int x = 0; x < dataSetSimulador.anchoEjeX; x++)
            {
                for (int y = 0; y < dataSetSimulador.altoEjeY - 1; y++)
                {
                    //Si hay agua en el punto (x,y) o en el punto (x+1,y) y la capacidad de almacenamiento del suelo
                    //es mayor que cero en ambos puntos
                    if ((dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] > 0.0 || dataSetSimulador.aguaCapaPermeable.matrizDEM_[y + 1, x] > 0.0) &&
                        dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x] > 0.0 && dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y + 1, x] > 0.0)
                    {
                        //No coincide con la formula??? O como se explica esto??? Grafica en papel.
                        tempValue = (dataSetSimulador.kConductividadHSuelo.matrizDEM_[y, x] + dataSetSimulador.kConductividadHSuelo.matrizDEM_[y + 1, x]) / 2.0f *
                                                        ((dataSetSimulador.aguaCapaPermeable.matrizDEM_[y + 1, x] - dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x]) +
                                                         (dataSetSimulador.alturaSueloPermeable.matrizDEM_[y + 1, x] - dataSetSimulador.alturaSueloPermeable.matrizDEM_[y, x])) *
                                                        (dataSetSimulador.aguaCapaPermeable.matrizDEM_[y + 1, x] + dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x]) / 2.0f;
                        dataSetSimulador.flujoEnYCapaPermeable.matrizDEM_[y, x] = tempValue;
                    }
                }
            }
        }
        private void infiltracionHorizontalEnX(ref DataSet dataSetSimulador)
        {
            float tempValue;

            dataSetSimulador.flujoEnXCapaPermeable = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            for (int x = 0; x < dataSetSimulador.anchoEjeX - 1; x++)
            {
                for (int y = 0; y < dataSetSimulador.altoEjeY; y++)
                {
                    //Si hay agua en el punto (x,y) o en el punto (x+1,y) y la capacidad de almacenamiento del suelo
                    //es mayor que cero en ambos puntos
                    if ((dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] > 0.0 || dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x + 1] > 0.0) &&
                        dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x] > 0.0 && dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x + 1] > 0.0)
                    {
                        tempValue = (float)((dataSetSimulador.kConductividadHSuelo.matrizDEM_[y, x] + dataSetSimulador.kConductividadHSuelo.matrizDEM_[y, x + 1]) / 2.0 *
                                                        ((dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x + 1] - dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x]) +
                                                         (dataSetSimulador.alturaSueloPermeable.matrizDEM_[y, x + 1] - dataSetSimulador.alturaSueloPermeable.matrizDEM_[y, x])) *
                                                        (dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x + 1] + dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x]) / 2.0);
                        dataSetSimulador.flujoEnXCapaPermeable.matrizDEM_[y, x] = tempValue;
                    }
                }
            }
        }
        void clustering(ref DataSet dataSetSimulador)
        {
            int numberClusterCreated = 0;
            dataSetSimulador.matrizClusters = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            List<Tuple<int, int>> tempCluster = new List<Tuple<int, int>>();
            listOfClusters.Add(tempCluster);

            float numberClusterAssignedNew = 0;

            Tuple<int, int> tempParPixel;

            //recorrer toda la matriz de cantidad de variaciones
            for (int j = 0; j < dataSetSimulador.altoEjeY; j++)
            {
                for (int i = 0; i < dataSetSimulador.anchoEjeX; i++)
                {
                    numberClusterAssignedNew = 0;

                    //si el pixel tiene valor de cantidad de variaciones mayor que el definido
                    //debo determinar un valor de cluster al cual pertenece

                    if (dataSetSimulador.matrizCantVariaciones.matrizDEM_[j, i] > variacionesMax)
                    {
                        //si ES un pixel del borde izquierdo superior, o sea que no tiene vecinos a los que se le haya podido asignar
                        //un cluster previamente
                        if (i == 0 && j == 0)
                        {
                            numberClusterCreated++;

                            //Cuando se crea un nuevo indice de nuevo cluster se crea la nueva lista que almacenara
                            //los pares
                            tempCluster = new List<Tuple<int, int>>();
                            listOfClusters.Add(tempCluster);

                            numberClusterAssignedNew = numberClusterCreated;
                        }
                        else
                        {
                            if (i != 0)
                            {
                                //si la matriz de asignacion de clusters tiene un cluster asignado para el vecino i-1, j
                                if (dataSetSimulador.matrizClusters.matrizDEM_[j, i - 1] != 0.0)
                                {
                                    //asignar ese cluster al nuevo pixel
                                    numberClusterAssignedNew = dataSetSimulador.matrizClusters.matrizDEM_[j, i - 1];
                                }
                                //si no tiene un cluster asignado para el vecino i-1, j
                                else
                                {
                                    if (j != 0)
                                    {
                                        if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i - 1] != 0.0)
                                        {
                                            //asignar ese cluster al nuevo pixel
                                            numberClusterAssignedNew = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i - 1];
                                        }
                                    }
                                }
                            }
                            if (j != 0 && numberClusterAssignedNew == 0.0)
                            {
                                if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i] != 0.0)
                                {
                                    //asignar ese cluster al nuevo pixel
                                    numberClusterAssignedNew = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i];
                                }
                                //si no tiene un cluster asignado para el vecino i + 1, j - 1
                                else
                                {
                                    if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i + 1] != 0.0)
                                    {
                                        //asignar ese cluster al nuevo pixel
                                        numberClusterAssignedNew = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i + 1];
                                    }
                                }
                            }
                        }
                        //Si es el pixel superior izquierdo o no salio del ciclo por haber encontrado un vecino con cluster asignado
                        if (numberClusterAssignedNew == 0.0)
                        {
                            numberClusterCreated++;

                            tempCluster = new List<Tuple<int, int>>();
                            listOfClusters.Add(tempCluster);

                            numberClusterAssignedNew = numberClusterCreated;
                        }

                        //Cuando esta por asignar el nuevo cluster al cual pertenece el pixel tengo que ver si alguno de los
                        //otros vecinos tiene asignado un cluster diferente

                        bool different = false;
                        float differentValue = 0;

                        if (i != 0)
                        {
                            if (dataSetSimulador.matrizClusters.matrizDEM_[j, i - 1] != 0.0 &&
                                numberClusterAssignedNew != dataSetSimulador.matrizClusters.matrizDEM_[j, i - 1])
                            {
                                different = true;
                                differentValue = dataSetSimulador.matrizClusters.matrizDEM_[j, i - 1];
                            }

                            if (j != 0)
                            {
                                if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i - 1] != 0.0 &&
                                    numberClusterAssignedNew != dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i - 1])
                                {
                                    different = true;
                                    differentValue = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i - 1];
                                }
                            }
                        }

                        if (j != 0)
                        {
                            if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i] != 0.0 &&
                                numberClusterAssignedNew != dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i])
                            {
                                different = true;
                                differentValue = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i];
                            }
                            else if (i != dataSetSimulador.anchoEjeX - 1)
                            {
                                if (dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i + 1] != 0.0 &&
                                numberClusterAssignedNew != dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i + 1])
                                {
                                    different = true;
                                    differentValue = dataSetSimulador.matrizClusters.matrizDEM_[j - 1, i + 1];
                                }
                            }
                        }
                        if (different)
                        {
                            //Seteo en la matriz de clusters los valores correspondiente
                            for (int n = 0; n < listOfClusters[(int)differentValue].Count; n++)
                            {
                                dataSetSimulador.matrizClusters.matrizDEM_[listOfClusters[(int)differentValue][n].Item1,
                                                          listOfClusters[(int)differentValue][n].Item2] = numberClusterAssignedNew;
                            }

                            //Cambio los elementos de Cluster
                            int elementos = listOfClusters[(int)differentValue].Count;
                            for (int m = 0; m < elementos; m++)
                            {
                                listOfClusters[(int)numberClusterAssignedNew].Add(listOfClusters[(int)differentValue][m]);
                            }

                            listOfClusters[(int)differentValue].Clear();
                        }

                        different = false;

                        //Primero deberias crear el arreglo de clusters
                        tempParPixel = new Tuple<int, int>(j, i);

                        listOfClusters[(int)numberClusterAssignedNew].Add(tempParPixel);
                        //Estos es para poder visualizar el cluster, para desarrollo, puede ser omitido tal vez
                        dataSetSimulador.matrizClusters.matrizDEM_[j, i] = numberClusterAssignedNew;
                    }
                }
            }
        }
        void planchado(ref DataSet dataSetSimulador)
        {
            Tuple<int, int> tempParPixel;
            List<Tuple<int, int>> tempCluster;

            List<Tuple<double, Tuple<int, int>>> listAlturasDem = new List<Tuple<double, Tuple<int, int>>>();
            Tuple<double, Tuple<int, int>> tempAltura;
            double alturaDemTemp = 0.0f;

            //Altura media calculada en la que tiene que quedar el agua
            double media = 0.0;
            //agua total
            double aguaTotal = 0.0;
            //DEM total
            double DEMTotal = 0.0;
            //temporario de agua pixel
            double tempAguaPixel = 0.0;
            double tempDemPixel = 0.0;
            //Cantidad de pixeles en los que se divide el agua
            int pixelesN;

            List<float> verificacion = new List<float>();

            for (int g = 1; g < listOfClusters.Count; g++)
            {
                if (listOfClusters[g].Count != 0)
                {
                    tempCluster = listOfClusters[g];
                    pixelesN = tempCluster.Count;
                    //Se obtienen el agua
                    for (int h = 0; h < pixelesN; h++)
                    {
                        tempParPixel = tempCluster[h];
                        //Agua del pixel en cuestion
                        tempAguaPixel = dataSetSimulador.aguaSuperficie.matrizDEM_[tempParPixel.Item1, tempParPixel.Item2];
                        //Altura del pixel en cuestion
                        tempDemPixel = dataSetSimulador.DEM.matrizDEM_[tempParPixel.Item1, tempParPixel.Item2];
                        //AGUA TOTAL: Sumo el agua que corresponde al pixel total al total de agua
                        aguaTotal += tempAguaPixel;
                        //DEM TOTAL
                        DEMTotal += tempDemPixel;
                        //Se crea el nuevo elemento que contiene (altura de dem, pixeles)
                        tempAltura = new Tuple<double, Tuple<int, int>>(tempDemPixel, tempParPixel);
                        //Agrego
                        listAlturasDem.Add(tempAltura);
                    }

                    listAlturasDem.Sort((a, b) => a.Item1.CompareTo(b.Item1));
                    listAlturasDem.Reverse();

                    //obtener la media
                    media = (aguaTotal + DEMTotal) / pixelesN;

                    //Sacar el elemento mas grande
                    alturaDemTemp = listAlturasDem[0].Item1;

                    //Elimino de la lista los elementos del dem que dieron por encima de la media
                    while (media < alturaDemTemp)
                    {
                        DEMTotal = DEMTotal - alturaDemTemp;
                        pixelesN = pixelesN - 1;
                        media = (aguaTotal + DEMTotal) / pixelesN;
                        //Sacarle el agua a los pixeles cuya altura del DEM supere
                        tempParPixel = listAlturasDem[0].Item2;
                        dataSetSimulador.aguaSuperficie.matrizDEM_[tempParPixel.Item1, tempParPixel.Item2] = 0.0f;
                        //Se lo saca de la lista y se toma el siguiente elemento
                        listAlturasDem.RemoveAt(0);
                        alturaDemTemp = listAlturasDem[0].Item1;

                    }
                    //Acá distribuir el agua en los pixeles los cuales el DEM dio por debajo de la media.
                    for (int i = 0; i < listAlturasDem.Count; i++)
                    {
                        tempAltura = listAlturasDem[i];
                        tempParPixel = tempAltura.Item2;
                        dataSetSimulador.aguaSuperficie.matrizDEM_[tempParPixel.Item1, tempParPixel.Item2] = (float)(media - tempAltura.Item1);
                        aguaTotal = aguaTotal - (media - tempAltura.Item1);
                    }
                    listAlturasDem.Clear();

                    aguaTotal = 0.0f;
                    DEMTotal = 0.0f;
                }
            }
            listOfClusters.Clear();
        }
 public void ejecutarClusteringPlanchado(ref DataSet dataSetSimulador)
 {
     variacionesMax = dataSetSimulador.maxCantidadVariaciones;
     clustering(ref dataSetSimulador);
     planchado(ref dataSetSimulador);
 }
        public void ejecutarInfiltracionVertical(ref DataSet dataSetSimulador)
        {
            //Para cada punto de la cuadricula
            for (int x = 0; x < dataSetSimulador.anchoEjeX; x++)
            {
                for (int y = 0; y < dataSetSimulador.altoEjeY; y++)
                {
                    float alturaEquivCapa1 = 0.0f;
                    float alturaLibreCapa1 = 0.0f;
                    float aguaCabeCapa1 = 0.0f;

                    float maxFluxSupCapa1 = 0.0f;

                    float auxiliar2 = 0.0f;

                    //Si hay agua en la superficie y hay lugar para agua en la capa 1
                    if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] > 0 &&
                        dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] < dataSetSimulador.profundidadSuelos.matrizDEM_[y, x])
                    {
                        //Calculo la maxima agua que puede pasar de la superficia a la capa 1
                        maxFluxSupCapa1 = 2 * dataSetSimulador.kConductividadHSuelo.matrizDEM_[y, x];

                        //Guardo la altura libre de agua que hay en la capa 1
                        alturaLibreCapa1 = dataSetSimulador.profundidadSuelos.matrizDEM_[y, x] - dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x];

                        auxiliar2 = alturaLibreCapa1;
                        aguaCabeCapa1 = alturaLibreCapa1 * dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x] / dataSetSimulador.profundidadSuelos.matrizDEM_[y, x];

                        if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] <= maxFluxSupCapa1)
                        {
                            //Si el agua en superficie es menor que el maximo que se le puede sacar y ese maximo es menor que la que cantidad que cabe en la capa 1
                            if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] < aguaCabeCapa1)
                            {
                                //Altura equivalente en capa 1
                                alturaEquivCapa1 = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] *
                                    dataSetSimulador.profundidadSuelos.matrizDEM_[y, x] / dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x];

                                auxiliar2 = alturaEquivCapa1;

                                //Agua en superficie
                                aguaCabeCapa1 = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x];
                            }

                            //El agua en superficie se actualiza con lo que sale
                            dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] - aguaCabeCapa1; ;
                            //El agua en la capa 1 se actualiza con lo que le entra
                            dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] = dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] + auxiliar2;
                        }
                        else
                        {
                            if (maxFluxSupCapa1 < aguaCabeCapa1)
                            {
                                //Altura equivalente en capa 1
                                alturaEquivCapa1 = maxFluxSupCapa1 * dataSetSimulador.profundidadSuelos.matrizDEM_[y, x] / dataSetSimulador.capacidadAlmacenSuelo.matrizDEM_[y, x];

                                auxiliar2 = alturaEquivCapa1;

                                //Agua en superficie
                                aguaCabeCapa1 = maxFluxSupCapa1;
                            }

                            //El agua en superficie se actualiza con lo que sale
                            dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] - aguaCabeCapa1; ;
                            //El agua en la capa 1 se actualiza con lo que le entra
                            dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] = dataSetSimulador.aguaCapaPermeable.matrizDEM_[y, x] + auxiliar2;
                        }
                    }
                }
            }
        }
        public void ejecutarEscurrimientoSuperficial(ref DataSet dataSetSimulador, float dts)
        {
            float tempValue;

            //Se hace una copia de los datos que seran leidos para procesar. Ya que no acepta valores por referencia.
            DataSet copyDataSetSimulador = dataSetSimulador;
            int anchoEjeX = dataSetSimulador.anchoEjeX;
            int altoEjeY = dataSetSimulador.altoEjeY;

            //Se deben generar los raster tanto para X como para Y
            /*RasterDatos[] rastersFlujoX = new RasterDatos[divXFlujoEnX * divYFlujoEnX];
            RasterDatos[] rastersFlujoY = new RasterDatos[divXFlujoEnY * divYFlujoEnY];*/

            RasterDatos[] rastersFlujoX = desarmarRaster(anchoEjeX, altoEjeY, 2, 2);
            RasterDatos[] rastersFlujoY = desarmarRaster(anchoEjeX, altoEjeY, 2, 2);

            //Se generan datos
            RasterDatos tempFlujoEnX = new RasterDatos(anchoEjeX, altoEjeY);
            RasterDatos tempFlujoEnY = new RasterDatos(anchoEjeX, altoEjeY);

            Parallel.Invoke(
                () =>
                {
                    rastersFlujoX[0] = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, 0, anchoEjeX/2, 0, altoEjeY/2);
                },
                () =>
                {
                    rastersFlujoX[1] = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, anchoEjeX/2, anchoEjeX, 0, altoEjeY/2);
                },
                () =>
                {
                    rastersFlujoX[2] = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, 0, anchoEjeX/2, altoEjeY/2, altoEjeY);
                },
                () =>
                {
                    rastersFlujoX[3] = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, anchoEjeX/2, anchoEjeX, altoEjeY/2, altoEjeY);
                },

                () =>
                {
                    rastersFlujoY[0] = escurrimientoSuperficialEnY(copyDataSetSimulador, dts, 0, anchoEjeX/2, 0, altoEjeY/2);
                },
                () =>
                {
                    rastersFlujoY[1] = escurrimientoSuperficialEnY(copyDataSetSimulador, dts, anchoEjeX/2, anchoEjeX, 0, altoEjeY/2);
                },
                () =>
                {
                    rastersFlujoY[2] = escurrimientoSuperficialEnY(copyDataSetSimulador, dts, 0, anchoEjeX/2, altoEjeY/2, altoEjeY);
                },
                () =>
                {
                    rastersFlujoY[3] = escurrimientoSuperficialEnY(copyDataSetSimulador, dts, anchoEjeX/2, anchoEjeX, altoEjeY/2, altoEjeY);
                }

            ); //close parallel.invoke

            /*
            Parallel.Invoke(
                () =>
                    {
                        tempFlujoEnX = escurrimientoSuperficialEnX(copyDataSetSimulador, dts, 0, anchoEjeX, 0, altoEjeY);
                    },  // close first Action

                () =>
                    {
                        tempFlujoEnY = escurrimientoSuperficialEnY(copyDataSetSimulador, dts,0, anchoEjeX, 0, altoEjeY);
                    } //close second Action

            ); //close parallel.invoke
            */

            dataSetSimulador.flujoEnXSuperficie = armarRaster(rastersFlujoX, anchoEjeX, altoEjeY, 2, 2);
            dataSetSimulador.flujoEnYSuperficie = armarRaster(rastersFlujoY, anchoEjeX, altoEjeY, 2, 2);

            //dataSetSimulador.flujoEnXSuperficie = tempFlujoEnX;
            //dataSetSimulador.flujoEnYSuperficie = tempFlujoEnY;

            /*
            dataSetSimulador.flujoEnXSuperficie = escurrimientoSuperficialEnX(dataSetSimulador, dts);

            dataSetSimulador.flujoEnYSuperficie = escurrimientoSuperficialEnY(dataSetSimulador, dts);*/

            dataSetSimulador.flujoResultanteSuperficie = new RasterDatos(dataSetSimulador.anchoEjeX, dataSetSimulador.altoEjeY);

            for (int x = 1; x < dataSetSimulador.anchoEjeX - 1; x++)
            {
                for (int y = 1; y < dataSetSimulador.altoEjeY - 1; y++)
                {

                    tempValue = (float)((dataSetSimulador.flujoEnXSuperficie.matrizDEM_[y, x - 1] - dataSetSimulador.flujoEnXSuperficie.matrizDEM_[y, x]
                                        + dataSetSimulador.flujoEnYSuperficie.matrizDEM_[y - 1, x] - dataSetSimulador.flujoEnYSuperficie.matrizDEM_[y, x]) / Math.Pow(dataSetSimulador.dimensionCelda, 2.0));

                    dataSetSimulador.flujoResultanteSuperficie.matrizDEM_[y, x] = tempValue;
                }
            }
        }
        private RasterDatos escurrimientoSuperficialEnY(DataSet dataSetSimulador, float dts, int startEjeX, int endEjeX, int startEjeY, int endEjeY)
        {
            float Slope = 0.0f;
            float auxiliar1 = 0.0f;
            float CSArea = 0.0f;
            float RadiusHydraulic = 0.0f;
            float tempValue;

            //Se calculan los anchos y altos de las matrices.
            int anchoEjeX = endEjeX - startEjeX;
            int altoEjeY = endEjeY - startEjeY;

            dataSetSimulador.flujoEnYSuperficie = new RasterDatos(anchoEjeX, altoEjeY);

            //Llevar la cuenta de las posiciones para los rasters chiquitos.
            int f = 0;
            int g = 0;

            //Condicion para el borde.
            if (endEjeY == dataSetSimulador.altoEjeY)
            {
                endEjeY = endEjeY - 1;
            }

            for (int x = startEjeX; x < endEjeX; x++)
            {
                for (int y = startEjeY; y < endEjeY; y++)
                {
                    //Se va a armar una matriz de flujo de agua en X
                    dataSetSimulador.flujoEnYSuperficie.matrizDEM_[g, f] = 0.0f;

                    //Si hay agua superficial en alguna de las dos celdas, y o y+1
                    if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] > 0.0 || dataSetSimulador.aguaSuperficie.matrizDEM_[y + 1, x] > 0.0)
                    {
                        //Diferencias de las altura del DEM del x + agua superficial - lo mismo de x + 1
                        Slope = ((dataSetSimulador.DEM.matrizDEM_[y, x] + dataSetSimulador.aguaSuperficie.matrizDEM_[y, x]) -
                            (dataSetSimulador.DEM.matrizDEM_[y + 1, x] + dataSetSimulador.aguaSuperficie.matrizDEM_[y + 1, x])) / dataSetSimulador.dimensionCelda;

                        //Esto es, si la diferenca de agua entre las capaz es significativa
                        if (Math.Abs(Slope) >= cotaInferior)
                        {
                            //MUCHAS DUDAS DE CORRESPONDENCIA CON LA FORMULA TEORICA

                            auxiliar1 = (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] + dataSetSimulador.aguaSuperficie.matrizDEM_[y + 1, x]) / 2;
                            CSArea = auxiliar1 * dataSetSimulador.dimensionCelda;
                            RadiusHydraulic = dataSetSimulador.dimensionCelda + 2 * auxiliar1;
                            //Algo se entiende de la formula, porque hacerla de esta forma complicada lo del Slope?
                            tempValue = (float)(Math.Pow(CSArea, 5.0f / 3.0f) * Math.Pow(Math.Abs(Slope), 1.5f) / Slope / Math.Pow(RadiusHydraulic, 2.0f / 3.0f) / dataSetSimulador.coefManning);
                            //flujoEnY.setValue(tempValue,x,y);

                            if (tempValue > 0.0)
                            {
                                //NO ENTIENDO QUE HACE ACA - DE QUE FORMULA SALE? Segun lo que haga aca se crea una matriz inicial con todo esto
                                //Para no recalcular para los dos flujos

                                //Supongo que <= seria casi igual que < varia mas abajo
                                //Esta condicion no se va a cumplir nunca pues si el flujo de agua es positivo significa que el agua inicial
                                //en X es mayor que el agua inicial en X+1 por lo que no puede haber entrado al ciclo pasando las dos condiciones
                                //sobre la cota inferior, el cambio se ve en Modificacion 2.
                                if (dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] > cotaInferior)
                                {

                                    auxiliar1 = (float)(dataSetSimulador.aguaSuperficie.matrizDEM_[y, x] / dts
                                        * Math.Pow(dataSetSimulador.dimensionCelda, 2.0f) / 4.0f);
                                    if (tempValue > auxiliar1)
                                    {
                                        dataSetSimulador.flujoEnYSuperficie.matrizDEM_[g, f] = auxiliar1;
                                    }
                                    else
                                    {
                                        dataSetSimulador.flujoEnYSuperficie.matrizDEM_[g, f] = tempValue;
                                    }
                                }
                            }

                            if (tempValue < 0.0)
                            {
                                if (dataSetSimulador.aguaSuperficie.matrizDEM_[y + 1, x] > cotaInferior)
                                {
                                    auxiliar1 = (float)(dataSetSimulador.aguaSuperficie.matrizDEM_[y + 1, x] / dts * Math.Pow(dataSetSimulador.dimensionCelda, 2.0f) / 4.0f);
                                    if (-tempValue > auxiliar1)
                                    {
                                        dataSetSimulador.flujoEnYSuperficie.matrizDEM_[g, f] = -auxiliar1;
                                    }
                                    else
                                    {
                                        dataSetSimulador.flujoEnYSuperficie.matrizDEM_[g, f] = tempValue;
                                    }
                                }
                            }
                        }
                    }
                    g++;
                }
                g=0;
                f++;
            }

            return dataSetSimulador.flujoEnYSuperficie;
        }
        private RasterDatos escurrimientoSuperficialEnX(DataSet dataSetSimulador, float dts, int startEjeX, int endEjeX, int startEjeY, int endEjeY)
        {
            float Slope = 0.0f;
            float auxiliar1 = 0.0f;
            float CSArea = 0.0f;
            float WettedPerimeter = 0.0f;

            float aguaSupxy = 0.0f;
            float aguaSupx1y = 0.0f;

            float tempValue;

            //Se calculan los anchos y altos de las matrices.
            int anchoEjeX = endEjeX - startEjeX;
            int altoEjeY = endEjeY - startEjeY;

            //Se crea el Raster del tamaño adecuado.
            dataSetSimulador.flujoEnXSuperficie = new RasterDatos(anchoEjeX, altoEjeY);

            //Llevar la cuenta de las posiciones para los rasters chiquitos.
            int f = 0;
            int g = 0;

            //Condicion para el borde.
            if (endEjeX == dataSetSimulador.anchoEjeX)
            {
                endEjeX = endEjeX - 1;
            }

            for (int x = startEjeX; x < endEjeX; x++)
            {
                for (int y = startEjeY; y < endEjeY; y++)
                {
                    //Seteo el valor 0 a la casilla [x,y]
                    dataSetSimulador.flujoEnXSuperficie.matrizDEM_[g, f] = 0.0f;
                    aguaSupxy = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x];
                    aguaSupx1y = dataSetSimulador.aguaSuperficie.matrizDEM_[y, x + 1];

                    //Si hay agua superficial en alguna de las dos celdas, x o x+1
                    if (aguaSupxy > 0.0 || aguaSupx1y > 0.0)
                    {
                        //(Altura suelo + agua en x    - (menos)  Altura suelo + agua en x+1) dividido el otro cateto y obtengo la hipotenusa
                        // o pendiente o slope.
                        Slope = ((dataSetSimulador.DEM.matrizDEM_[y, x] + aguaSupxy) - (dataSetSimulador.DEM.matrizDEM_[y, x + 1] + aguaSupx1y)) / dataSetSimulador.dimensionCelda;

                        //Esto es, si la diferenca de agua entre las capaz es significativa.
                        //Se le pone el valor absoluto ya que no me importa que sentido sea la diferencia.
                        if (Math.Abs(Slope) >= cotaInferior)
                        {
                            //Se toma el promedio de las dos alturas.
                            auxiliar1 = (aguaSupxy + aguaSupx1y) / 2;
                            CSArea = auxiliar1 * dataSetSimulador.dimensionCelda;

                            WettedPerimeter = dataSetSimulador.dimensionCelda + 2 * auxiliar1;

                            //Calculo del flujo
                            tempValue = (float)(Math.Pow(CSArea, 5.0f / 3.0f) * Math.Pow(Math.Abs(Slope), 1.5f) / Slope / Math.Pow(WettedPerimeter, 2.0f / 3.0f) / dataSetSimulador.coefManning);

                            //Si el flujo es mayor que 0.
                            if (tempValue > 0.0)
                            {
                                if (aguaSupxy > cotaInferior)
                                {
                                    auxiliar1 = (float)(aguaSupxy / dts * Math.Pow(dataSetSimulador.dimensionCelda, 2.0f) / 4.0f);
                                    if (tempValue > auxiliar1)
                                    {
                                        dataSetSimulador.flujoEnXSuperficie.matrizDEM_[g, f] = auxiliar1;
                                    }
                                    else
                                    {
                                        dataSetSimulador.flujoEnXSuperficie.matrizDEM_[g, f] = tempValue;
                                    }
                                }
                            }

                            if (tempValue < 0.0)
                            {
                                //En esta parte implementar las mismas modificaciones que para el caso anterior
                                if (aguaSupx1y > cotaInferior)
                                {
                                    auxiliar1 = (float)(aguaSupx1y / dts * Math.Pow(dataSetSimulador.dimensionCelda, 2.0f) / 4.0f);
                                    if (-tempValue > auxiliar1)
                                    {
                                        dataSetSimulador.flujoEnXSuperficie.matrizDEM_[g, f] = -auxiliar1;
                                    }
                                    else
                                    {
                                        dataSetSimulador.flujoEnXSuperficie.matrizDEM_[g, f] = tempValue;
                                    }
                                }

                            }
                        }
                    }
                    g++;
                }
                g = 0;
                f++;
            }

            return dataSetSimulador.flujoEnXSuperficie;
        }