예제 #1
0
        // Based on the wikipedia koppen entry, and Table 1 from this paper:
        // https://opus.bibliothek.uni-augsburg.de/opus4/frontdoor/deliver/index/docId/40083/file/metz_Vol_15_No_3_p259-263_World_Map_of_the_Koppen_Geiger_climate_classification_updated_55034.pdf
        public static string Classify(WeatherSample sample)
        {
            if (sample.TemperatureMax < 0)
            {
                return("EF");
            }

            if (sample.TemperatureMax >= 0 && sample.TemperatureMax < 10)
            {
                return("ET");
            }

            var group         = string.Empty;
            var precipitation = string.Empty;
            var temperature   = string.Empty;

            // have to check before Group A because Aw is defined basically as
            // "Hot, but not rainy, but also not B"
            //Group B
            if (sample.TotalAnnualRainfall <= sample.DesertThreshold)
            {
                group = "B";

                precipitation =
                    (sample.TotalAnnualRainfall <= sample.DesertThreshold * .5f)
                    ? "W"  //desert
                    : "S"; //steppe

                temperature = sample.TemperatureMin > 0 ? "h" : "k";

                return($"{group}{precipitation}{temperature}");
            } // else rainfall is above the desert threshold, this is not a Group B climate

            //Group A
            if (sample.TemperatureMin >= 18)
            {
                group = "A";

                var monsoonRainfallCutoff = 25 * (100 - sample.RainfallMin);

                if (sample.RainfallMin >= 60)
                {
                    precipitation = "f";
                }
                else if (sample.TotalAnnualRainfall >= monsoonRainfallCutoff)
                {
                    precipitation = "m";
                }
                else if (sample.RainfallWinter < 60 &&
                         sample.RainfallWinter < sample.RainfallSummer)
                {
                    precipitation = "w";
                }
                else
                {
                    precipitation = "s";
                }

                return($"{group}{precipitation}");
            }

            //Group C
            if (sample.TemperatureMin > 0)
            {
                group = "C";

                if (sample.RainfallSummer < sample.RainfallWinter &&
                    sample.RainfallWinter > 3 * sample.RainfallSummer &&
                    sample.RainfallSummer < 40)
                {
                    precipitation = "s";
                }
                else if (sample.RainfallSummer > 10 * sample.RainfallWinter)
                {
                    precipitation = "w";
                }
                else
                {
                    precipitation = "f";
                }
            }

            //Group D
            if (sample.TemperatureMin <= 0)
            {
                group = "D";

                if (sample.RainfallSummer < sample.RainfallWinter &&
                    sample.RainfallWinter > 3 * sample.RainfallSummer &&
                    sample.RainfallSummer < 40)
                {
                    precipitation = "s";
                }
                else if (sample.RainfallSummer > 10 * sample.RainfallWinter)
                {
                    precipitation = "w";
                }
                else
                {
                    precipitation = "f";
                }
            }

            if (sample.TemperatureMax >= 22)
            {
                temperature = "a";
            }
            else if (sample.Temperatures.Count(t => t > 10) >= 2)
            {
                temperature = "b";
            }
            else if (sample.TemperatureMin > -38)
            {
                temperature = "c";
            }
            else
            {
                temperature = "d";
            }

            if (group == string.Empty)
            {
                throw new Exception("Could not determine Koppen Climate Group for Sample: " + sample.ToString());
            }

            return($"{group}{precipitation}{temperature}");
        }
예제 #2
0
        static void Main(string[] args)
        {
            //TODO: Make args
            // var summerTemperatureOffset = 0;
            // var winterTemperatureOffset = 0;
            const short hottestTemperatureOffset = 2;
            const short coldestTemperatureOffset = -2;

            //

            Directory.SetCurrentDirectory(args[0]);

            _inDir  = Path.Join(Directory.GetCurrentDirectory(), "input");
            _outDir = Path.Join(Directory.GetCurrentDirectory(), "output");

            Console.WriteLine($"Koppen Classifier reading from: {_inDir}");

            var imageInfo   = new MagickImageInfo(Path.Join(_inDir, "alpha.png"));
            var imageWidth  = imageInfo.Width;
            var imageHeight = imageInfo.Height;
            var halfHeight  = imageHeight / 2;
            var sampleCount = imageWidth * imageHeight;

            Console.WriteLine($"Map Resolution: {imageWidth}x{imageHeight} ({sampleCount} Samples)");

            var climateMaps = InitializeClimateMaps(
                imageWidth, imageHeight);

            Console.Write("Loading Maps... ");

            var landMask = ReadImage("alpha.png");

            var summerRain         = ReadImage("summerRain.png");
            var winterRain         = ReadImage("winterRain.png");
            var summerTemperature  = ReadImage("summerTemperature.png");
            var winterTemperature  = ReadImage("winterTemperature.png");
            var hottestTemperature = ReadImage("hottestTemperature.png");
            var coldestTemperature = ReadImage("coldestTemperature.png");

            //TODO: Check that all image dimensions match

            Console.WriteLine("Done!");
            Console.WriteLine("Classification Progress...");

            void ClassifySample(int x, int y)
            {
                if (landMask[x, y][COLOR_CHANNEL] == 0)
                {
                    return;
                }

                var sampleHemisphere = y <= halfHeight
                    ? Hemisphere.North
                    : Hemisphere.South;

                //TODO: Check bounds given offsets
                //TODO: use summer and winter offsets
                var sample = new WeatherSample(
                    sampleHemisphere,
                    ToRainfall(ReadPixel(summerRain, x, y)),
                    ToRainfall(ReadPixel(winterRain, x, y)),
                    ToTemperature(ReadPixel(summerTemperature, x, y)),
                    ToTemperature(ReadPixel(winterTemperature, x, y)),
                    (short)(ToTemperature(ReadPixel(hottestTemperature, x, y)) +
                            hottestTemperatureOffset),
                    (short)(ToTemperature(ReadPixel(coldestTemperature, x, y)) +
                            coldestTemperatureOffset)
                    );

                var zone = KoppenClassifier.Classify(sample);

                climateMaps[zone][x, y] = true;
            }

            Console.WriteLine("0%");
            var completed = 0;
            var cursorPos = Console.CursorTop - 1;

            void UpdateProgress(object _)
            {
                Console.SetCursorPosition(0, cursorPos);
                Console.WriteLine($"{Math.Round((completed / (float) sampleCount) * 100, 1)}%      ");
            }

            var updateProgressPeriod = TimeSpan.FromSeconds(3);

            var watch = Stopwatch.StartNew();

            using (new Timer(UpdateProgress, null, updateProgressPeriod, updateProgressPeriod)) {
                // for (var x = 0; x < imageWidth; x++) {
                //     for (var y = 0; y < imageHeight; y++) {
                Parallel.For(0, imageWidth, x => {
                    Parallel.For(0, imageHeight, y => {
                        ClassifySample(x, y);
                        Interlocked.Increment(ref completed); //threadsafe completed++
                    });
                });
            }

            watch.Stop();

            Console.SetCursorPosition(0, cursorPos);
            Console.WriteLine("100.0%    ");
            Console.WriteLine($"Classification Completed in {watch.ElapsedMilliseconds/1000f}s");

            Console.WriteLine("Writing Climate Maps...");

            SaveClimateZoneMaps(climateMaps);

            Console.WriteLine("Climate Maps Complete!");
        }