Ejemplo n.º 1
0
        /// <summary>
        /// Calculate the roughness lenght based on objects like buildings and vegetation areas
        /// </summary>
        /// <param name="ReaderClass">Program Reader Class</param>
        private static void CreateAdaptiveRoughnessLenght(ProgramReaders ReaderClass)
        {
            //read buildings into a local array
            float[][] TempArray = CreateArray <float[]>(NII + 2, () => new float[NJJ + 2]);

            if (Topo == 1)
            {
                ReaderClass.ReadBuildingsTerrain(TempArray);
            }
            else
            {
                ReaderClass.ReadBuildingsFlat(TempArray);
            }

            ArrayFilter fil = new ArrayFilter();

            //Find building outlines
            //TempArray = fil.FindOutline(TempArray);

            // Take building height into Z0
            float max = 0;

            for (int i = 0; i <= NII; i++)
            {
                for (int j = 0; j <= NJJ; j++)
                {
                    if (TempArray[i][j] > 1)
                    {
                        float val = MathF.Log10(TempArray[i][j]); //roughness from building height
                        max = MathF.Max(max, val);
                        Program.Z0Gral[i][j] = MathF.Min(AdaptiveRoughnessMax, val);
                    }
                }
            }

            max = Math.Min(max, Program.AdaptiveRoughnessMax);
            //Filter Roughness
            Program.Z0Gral = fil.LowPassGaussian(Program.Z0Gral, Program.DXK, 40, max); // scale with max

            //roughness length for building walls
            float buildingZ0 = 0.01F;

            if (File.Exists("building_roughness.txt") == true)
            {
                try
                {
                    using (StreamReader sr = new StreamReader("building_roughness.txt"))
                    {
                        buildingZ0 = Convert.ToSingle(sr.ReadLine().Replace(".", Program.Decsep));
                    }
                }
                catch
                { }
            }

            //Set Roughness within buildings to building wall value and clear TempArray
            for (int i = 0; i <= NII; i++)
            {
                for (int j = 0; j <= NJJ; j++)
                {
                    if (TempArray[i][j] > Program.Z0Gral[i][j] * 2)
                    {
                        Program.Z0Gral[i][j] = buildingZ0;
                    }
                    TempArray[i][j] = 0;
                }
            }

            // Read vegetation heigth, limit vegetation roughness to 1.3 m and combine with building roughness
            ReaderClass.ReadVegetationDomain(TempArray);
            //Limit vegetation to 1.5
            for (int i = 0; i <= NII; i++)
            {
                for (int j = 0; j <= NJJ; j++)
                {
                    TempArray[i][j] = MathF.Min(1.3F, TempArray[i][j]);
                }
            }

            // Filter vegetation array
            TempArray = fil.LowPassGaussian(TempArray, Program.DXK, 15, 0); // no scale
            fil       = null;

            for (int i = 0; i <= NII; i++)
            {
                for (int j = 0; j <= NJJ; j++)
                {
                    Program.Z0Gral[i][j] = MathF.Max(MathF.Min(1.5F, TempArray[i][j]), Program.Z0Gral[i][j]);
                }
            }

            if ((Program.Topo == 1) && (Program.LandUseAvailable == true))
            {
                float DDX1       = Program.DDX[1];
                float DDY1       = Program.DDY[1];
                int   Delta_IKOO = (int)XsiMinGral - Program.GrammWest;
                int   Delta_JKOO = (int)EtaMinGral - Program.GrammSouth;
                //With topography and LandUse File for Roughness lenght -> Compare with Z0Gramm and take larger value
                for (int i = 0; i <= NII; i++)
                {
                    for (int j = 0; j <= NJJ; j++)
                    {
                        int GrammCellX = Math.Clamp((int)((Delta_IKOO + DXK * i - DXK * 0.5) / DDX1) + 1, 1, Program.NX);
                        int GrammCellY = Math.Clamp((int)((Delta_JKOO + DYK * j - DYK * 0.5) / DDY1) + 1, 1, Program.NY);
                        Program.Z0Gral[i][j] = MathF.Max(Program.Z0Gramm[GrammCellX][GrammCellY],
                                                         MathF.Min(AdaptiveRoughnessMax, Program.Z0Gral[i][j]));
                    }
                }
            }
            else
            {
                // limit roughness between min and max
                for (int i = 0; i <= NII; i++)
                {
                    for (int j = 0; j <= NJJ; j++)
                    {
                        Program.Z0Gral[i][j] = MathF.Max(Z0, MathF.Min(AdaptiveRoughnessMax, Program.Z0Gral[i][j]));
                    }
                }
            }

            max = 0;
            float min = 20000;

            for (int i = 0; i <= NII; i++)
            {
                for (int j = 0; j <= NJJ; j++)
                {
                    max = MathF.Max(max, Program.Z0Gral[i][j]);
                    min = MathF.Min(min, Program.Z0Gral[i][j]);
                }
            }

            string Info = "Using adaptive roughness length. User minimum: " + Z0.ToString("0.00") + " m  User maximum: " + AdaptiveRoughnessMax.ToString("0.00") + " m";

            Console.WriteLine(Info);
            ProgramWriters.LogfileGralCoreWrite(Info);
            Info = "                                 Used minimum: " + min.ToString("0.00") + " m  Used maximum: " + max.ToString("0.00") + " m";
            Console.WriteLine(Info);
            ProgramWriters.LogfileGralCoreWrite(Info);

            // ProgramWriters WriteClass = new ProgramWriters();
            ProgramWriters WriteClass = new ProgramWriters();

            WriteClass.WriteBuildingHeights("RoughnessLengthsGral.txt", Program.Z0Gral, "0.00", 2, Program.GralWest, Program.GralSouth);

            WriteClass = null;
            TempArray  = null;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Pre calculations for flat microscale terrain
        /// </summary>
        public static void Calculate()
        {
            Console.WriteLine();
            Console.WriteLine("FLOW FIELD COMPUTATION WITHOUT TOPOGRAPHY");

            Program.KADVMAX = 1;
            int inumm = Program.MetProfileNumb;

            //set wind-speed components equal to zero
            Parallel.For(1, Program.NII + 2, Program.pOptions, i =>
            {
                for (int j = 1; j <= Program.NJJ + 1; j++)
                {
                    float[] UK_L = Program.UK[i][j];
                    float[] VK_L = Program.VK[i][j];
                    float[] WK_L = Program.WK[i][j];
                    for (int k = 1; k <= Program.NKK; k++)
                    {
                        UK_L[k] = 0;
                        VK_L[k] = 0;
                        WK_L[k] = 0;
                    }
                }
            });

            object obj = new object();

            //Parallel.For(1, Program.NII + 1, Program.pOptions, i =>
            Parallel.ForEach(Partitioner.Create(1, Program.NII + 1, Math.Max(4, (int)(Program.NII / Program.pOptions.MaxDegreeOfParallelism))), range =>
            {
                int KADVMAX1 = 1;

                for (int i = range.Item1; i < range.Item2; i++)
                {
                    for (int j = 1; j <= Program.NJJ; j++)
                    {
                        Program.AHK[i][j]   = 0;
                        Program.KKART[i][j] = 0;

                        //Pointers (to speed up the computations)
                        float[] UK_L  = Program.UK[i][j];
                        float[] VK_L  = Program.VK[i][j];
                        float[] UKi_L = Program.UK[i + 1][j];
                        float[] VKj_L = Program.VK[i][j + 1];
                        double UXint;
                        double UYint;
                        double vertk;
                        double exponent;
                        double dumfac;

                        for (int k = Program.NKK; k >= 1; k--)
                        {
                            vertk = Program.HOKART[k - 1] + Program.DZK[k] * 0.5;
                            if (vertk > Program.CUTK[i][j])
                            {
                                //interpolation between observations
                                if (vertk <= Program.MeasurementHeight[1])
                                {
                                    if (Program.Ob[1][1] <= 0)
                                    {
                                        exponent = Math.Max(0.35 - 0.4 * Math.Pow(Math.Abs(Program.Ob[1][1]), -0.15), 0.05);
                                    }
                                    else
                                    {
                                        exponent = 0.56 * Math.Pow(Program.Ob[1][1], -0.15);
                                    }

                                    dumfac = Math.Pow(vertk / Program.MeasurementHeight[1], exponent);
                                    UXint  = Program.UX[1] * dumfac;
                                    UYint  = Program.UY[1] * dumfac;
                                }
                                else if (vertk > Program.MeasurementHeight[inumm])
                                {
                                    if (inumm == 1)
                                    {
                                        if (Program.Ob[1][1] <= 0)
                                        {
                                            exponent = Math.Max(0.35 - 0.4 * Math.Pow(Math.Abs(Program.Ob[1][1]), -0.15), 0.05);
                                        }
                                        else
                                        {
                                            exponent = 0.56 * Math.Pow(Program.Ob[1][1], -0.15);
                                        }

                                        dumfac = Math.Pow(vertk / Program.MeasurementHeight[inumm], exponent);
                                        UXint  = Program.UX[inumm] * dumfac;
                                        UYint  = Program.UY[inumm] * dumfac;
                                    }
                                    else
                                    {
                                        UXint = Program.UX[inumm];
                                        UYint = Program.UY[inumm];
                                    }
                                }
                                else
                                {
                                    int ipo = 1;
                                    for (int iprof = 1; iprof <= inumm; iprof++)
                                    {
                                        if (vertk > Program.MeasurementHeight[iprof])
                                        {
                                            ipo = iprof + 1;
                                        }
                                    }
                                    UXint = Program.UX[ipo - 1] + (Program.UX[ipo] - Program.UX[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) *
                                            (vertk - Program.MeasurementHeight[ipo - 1]);
                                    UYint = Program.UY[ipo - 1] + (Program.UY[ipo] - Program.UY[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) *
                                            (vertk - Program.MeasurementHeight[ipo - 1]);
                                }

                                //finally get wind speeds outside obstacles
                                UK_L[k] = (float)UXint;
                                VK_L[k] = (float)UYint;
                                if (i > 1)
                                {
                                    if (vertk <= Program.CUTK[i - 1][j])
                                    {
                                        UK_L[k] = 0;
                                    }
                                }
                                if (j > 1)
                                {
                                    if (vertk <= Program.CUTK[i][j - 1])
                                    {
                                        VK_L[k] = 0;
                                    }
                                }
                                Program.UK[Program.NII + 1][j][k] = Program.UK[Program.NII][j][k];
                                Program.VK[i][Program.NJJ + 1][k] = Program.VK[i][Program.NJJ][k];
                            }
                            else
                            {
                                //set wind speed zero inside obstacles
                                UK_L[k] = 0;
                                if (i < Program.NII)
                                {
                                    UKi_L[k] = 0;
                                }
                                VK_L[k] = 0;
                                if (j < Program.NJJ)
                                {
                                    VKj_L[k] = 0;
                                }
                                Program.AHK[i][j]        = Math.Max(Program.HOKART[k], Program.AHK[i][j]);
                                Program.BUI_HEIGHT[i][j] = Program.AHK[i][j];
                                Program.KKART[i][j]      = Convert.ToInt16(Math.Max(k, Program.KKART[i][j]));
                                if (Program.CUTK[i][j] > 0)
                                {
                                    KADVMAX1 = Math.Max(Program.KKART[i][j], KADVMAX1);
                                }
                            }
                        }
                    }
                }
                if (KADVMAX1 > Program.KADVMAX)
                {
                    lock (obj) { Program.KADVMAX = Math.Max(Program.KADVMAX, KADVMAX1); }
                }
            });
            obj = null;
            //maximum z-index up to which the microscale flow field is being computed
            Program.KADVMAX = Math.Min(Program.NKK, Program.KADVMAX + Program.VertCellsFF);

            Program.AHMIN = 0;

            //in case of the diagnostic approach, a boundary layer is established near the obstacle's walls
            if (Program.FlowFieldLevel <= 1)
            {
                Parallel.For((1 + Program.IGEB), (Program.NII - Program.IGEB + 1), Program.pOptions, i =>
                {
                    for (int j = 1 + Program.IGEB; j <= Program.NJJ - Program.IGEB; j++)
                    {
                        double entf = 0;
                        double vertk;
                        double abmind;
                        for (int k = 1; k < Program.NKK; k++)
                        {
                            abmind = 1;
                            vertk  = Program.HOKART[k - 1] + Program.DZK[k] * 0.5;

                            //search towards west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((i - ig) * Program.DXK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((i - ig) * Program.DXK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south for obstacles
                            for (int jg = j - Program.IGEB; jg < j; jg++)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((j - jg) * Program.DYK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north for obstacles
                            for (int jg = j + Program.IGEB; jg >= j + 1; jg--)
                            {
                                entf = 21;
                                if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Abs((j - jg) * Program.DYK);
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north/east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                int jg = j + ig - i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south/west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                int jg = j + ig - i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards south/east for obstacles
                            for (int ig = i + Program.IGEB; ig >= i + 1; ig--)
                            {
                                int jg = j - ig + i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            //search towards north/west for obstacles
                            for (int ig = i - Program.IGEB; ig < i; ig++)
                            {
                                int jg = j - ig + i;
                                entf   = 21;
                                if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j]))
                                {
                                    entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK));
                                }
                            }
                            if (entf <= 20)
                            {
                                abmind *= 0.19 * Math.Log((entf + 0.5) * 10);
                            }

                            Program.UK[i][j][k] *= (float)abmind;
                            Program.VK[i][j][k] *= (float)abmind;
                        }
                    }
                });
            }

            //computing flow field either with diagnostic or prognostic approach
            if (Program.FlowFieldLevel > 0)
            {
                if (Program.FlowFieldLevel == 1)
                {
                    Console.WriteLine("DIAGNOSTIC WIND FIELD AROUND OBSTACLES");
                    DiagnosticFlowfield.Calculate();
                }
                if (Program.FlowFieldLevel == 2)
                {
                    //read vegetation only once
                    if (Program.VEG[0][0][0] < 0)
                    {
                        ProgramReaders Readclass = new ProgramReaders();
                        Readclass.ReadVegetationDomain();
                        Readclass.ReadVegetation();
                    }

                    Console.WriteLine("PROGNOSTIC WIND FIELD AROUND OBSTACLES");
                    PrognosticFlowfield.Calculate();
                }

                //Final mass conservation using poisson equation for pressure after advection has been computed with level 2
                if (Program.FlowFieldLevel == 2)
                {
                    DiagnosticFlowfield.Calculate();
                }
            }

            //in diagnostic mode mass-conservation is finally achieved by adjusting the vertical velocity in each cell
            if (Program.FlowFieldLevel < 2)
            {
                Parallel.For(2, Program.NII, Program.pOptions, i =>
                {
                    for (int j = 2; j < Program.NJJ; j++)
                    {
                        //Pointers (to speed up the computations)
                        float[] UK_L  = Program.UK[i][j];
                        float[] UKi_L = Program.UK[i + 1][j];
                        float[] VK_L  = Program.VK[i][j];
                        float[] VKj_L = Program.VK[i][j + 1];
                        float[] WK_L  = Program.WK[i][j];
                        double fwo1   = 0;
                        double fwo2   = 0;
                        double fsn1   = 0;
                        double fsn2   = 0;
                        double fbt1   = 0;
                        int KKART     = Program.KKART[i][j];

                        for (int k = 1; k < Program.NKK; k++)
                        {
                            if (k > KKART)
                            {
                                if (k <= Program.KKART[i - 1][j])
                                {
                                    fwo1 = 0;
                                }
                                else
                                {
                                    fwo1 = Program.DZK[k] * Program.DYK * UK_L[k];
                                }

                                if (k <= Program.KKART[i + 1][j])
                                {
                                    fwo2 = 0;
                                }
                                else
                                {
                                    fwo2 = Program.DZK[k] * Program.DYK * UKi_L[k];
                                }

                                if (k <= Program.KKART[i][j - 1])
                                {
                                    fsn1 = 0;
                                }
                                else
                                {
                                    fsn1 = Program.DZK[k] * Program.DXK * VK_L[k];
                                }

                                if (k <= Program.KKART[i][j + 1])
                                {
                                    fsn2 = 0;
                                }
                                else
                                {
                                    fsn2 = Program.DZK[k] * Program.DXK * VKj_L[k];
                                }

                                if ((k <= KKART + 1) || (k == 1))
                                {
                                    fbt1 = 0;
                                }
                                else
                                {
                                    fbt1 = Program.DXK * Program.DYK * WK_L[k];
                                }

                                WK_L[k + 1] = (float)((fwo1 - fwo2 + fsn1 - fsn2 + fbt1) / (Program.DXK * Program.DYK));
                            }
                        }
                    }
                });
            }
        }